[Crash-utility] [PATCH] Add --kaslr=auto option to automatically detect kaslr offset

Andy Honig ahonig at google.com
Mon Feb 24 17:08:56 UTC 2014


[PATCH] Add --kaslr=auto option to automatically detect kaslr offset.

This patch adds the --kaslr=auto option.  When set crash will
attempt to find the aslr offset by comparing the _stext symbol
in the vmlinux file to the _stext symbol in the vmcoreinfo.
When the kernel is updated to include the kernel aslr offset
in the vmcoreinfo, that should be used instead of this indirect
method.

Signed-off-by: Andrew Honig <ahonig at google.com>
---
 crash.8    |  7 ++++---
 defs.h     |  1 +
 diskdump.c |  8 ++++++++
 main.c     | 21 +++++++++++++++------
 netdump.c  | 11 +++++++++++
 symbols.c  | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++++-----
 6 files changed, 91 insertions(+), 14 deletions(-)

diff --git a/crash.8 b/crash.8
index 6f2c192..271bc59 100644
--- a/crash.8
+++ b/crash.8
@@ -448,11 +448,12 @@ command, search for their object files in
 .I directory
 instead of in the standard location.
 .TP
-.BI --kaslr \ offset
-If an x86 or x86_64 kernel was configured with 
+.BI --kaslr \ [offset|auto]
+If an x86_64 kernel was configured with 
 .B CONFIG_RANDOMIZE_BASE,
 the offset value is equal to the difference between the symbol values 
-compiled into the vmlinux file and their relocated value.
+compiled into the vmlinux file and their relocated value.  If set to
+auto, crash will attempt to automatically calculate the kaslr offset.
 .TP
 .BI --reloc \ size
 When analyzing live x86 kernels that were configured with a
diff --git a/defs.h b/defs.h
index c9a4b73..5f1ec9d 100644
--- a/defs.h
+++ b/defs.h
@@ -600,6 +600,7 @@ struct new_utsname {
 #define PRE_KERNEL_INIT     (0x20000000)
 #define ARCH_PVOPS_XEN      (0x40000000)
 #define IRQ_DESC_TREE       (0x80000000)
+#define RELOC_AUTO         (0x100000000ULL)
 
 #define GCC_VERSION_DEPRECATED (GCC_3_2|GCC_3_2_3|GCC_2_96|GCC_3_3_2|GCC_3_3_3)
 
diff --git a/diskdump.c b/diskdump.c
index 79fbba7..eb41744 100644
--- a/diskdump.c
+++ b/diskdump.c
@@ -845,6 +845,14 @@ is_diskdump(char *file)
 		get_log_from_vmcoreinfo(file, vmcoreinfo_read_string);
 	}
 
+	/*
+	 * We may need the _stext_SYMBOL from the vmcore_info to adjust for
+	 * kaslr and we may not have gotten it elsewhere.
+	 */
+	char *tmpstring = vmcoreinfo_read_string("SYMBOL(_stext)");
+	kt->vmcoreinfo._stext_SYMBOL = htol(tmpstring, RETURN_ON_ERROR, NULL);
+	free(tmpstring);
+
 	return TRUE;
 }
 
diff --git a/main.c b/main.c
index 44594f0..9fa79d7 100644
--- a/main.c
+++ b/main.c
@@ -218,13 +218,22 @@ main(int argc, char **argv)
 				kt->module_tree = optarg;
 
 			else if (STREQ(long_options[option_index].name, "kaslr")) {
-				if (!calculate(optarg, &kt->relocate, NULL, 0)) {
-					error(INFO, "invalid --kaslr argument: %s\n",
-						optarg);
-					program_usage(SHORT_FORM);
+				if (!machine_type("X86_64")) {
+					error(INFO, "option kaslr only valid "
+						"with X86_64 machine type.");
+				} else if (STREQ(optarg, "auto")) {
+					kt->flags |= RELOC_AUTO;
+				} else {
+					if (!calculate(optarg, &kt->relocate,
+							NULL, 0)) {
+						error(INFO,
+						    "invalid --kaslr argument: %s\n",
+						    optarg);
+						program_usage(SHORT_FORM);
+					}
+					kt->relocate *= -1;
+					kt->flags |= RELOC_SET;
 				}
-				kt->relocate *= -1;
-				kt->flags |= RELOC_SET;
 
 			} else if (STREQ(long_options[option_index].name, "reloc")) {
 				if (!calculate(optarg, &kt->relocate, NULL, 0)) {
diff --git a/netdump.c b/netdump.c
index 7dc2fca..884dd73 100644
--- a/netdump.c
+++ b/netdump.c
@@ -411,6 +411,17 @@ is_netdump(char *file, ulong source_query)
 		get_log_from_vmcoreinfo(file, vmcoreinfo_read_string);
 	}
 
+	/*
+	 * We may need the _stext_SYMBOL from the vmcore_info to adjust for
+	 * kaslr and we may not have gotten it elsewhere.
+	 */
+	if (source_query == KDUMP_LOCAL) {
+		char *tmpstring = vmcoreinfo_read_string("SYMBOL(_stext)");
+		kt->vmcoreinfo._stext_SYMBOL =
+			htol(tmpstring, RETURN_ON_ERROR, NULL);
+		free(tmpstring);
+	}
+
 	return nd->header_size;
 
 bailout:
diff --git a/symbols.c b/symbols.c
index 83bc0ff..7d4a4ef 100644
--- a/symbols.c
+++ b/symbols.c
@@ -557,6 +557,46 @@ strip_symbol_end(const char *name, char *buf)
 }
 
 /*
+ * Derives the kernel aslr offset by comparing the _stext symbol from the
+ * the vmcore_info in the dump file to the _stext symbol in the vmlinux file.
+ */
+static void
+derive_kaslr_offset(bfd *abfd, int dynamic, bfd_byte *start, bfd_byte *end,
+		    unsigned int size, asymbol *store)
+{
+	symbol_info syminfo;
+	asymbol *sym;
+	char *name;
+	unsigned long relocate;
+	char buf[BUFSIZE];
+
+	if (kt->vmcoreinfo._stext_SYMBOL == 0)
+		return;
+
+	for (; start < end; start += size) {
+		sym = bfd_minisymbol_to_symbol(abfd, dynamic, start, store);
+		if (sym == NULL)
+			error(FATAL, "bfd_minisymbol_to_symbol() failed\n");
+
+		bfd_get_symbol_info(abfd, sym, &syminfo);
+		name = strip_symbol_end(syminfo.name, buf);
+		if (strcmp("_stext", name) == 0) {
+			relocate = syminfo.value - kt->vmcoreinfo._stext_SYMBOL;
+			/*
+			 *To avoid mistaking an mismatched kernel version with
+			 * a kaslr offset, we make sure that the offset is
+			 * aligned by 0x1000, as it always will be for
+			 * kaslr.
+			 */
+			if ((relocate & 0xFFF) == 0) {
+				kt->relocate = relocate;
+				kt->flags |= RELOC_SET;
+			}
+		}
+	}
+}
+
+/*
  *  Store the symbols gathered by symtab_init().  The symbols are stored
  *  in increasing numerical order.
  */
@@ -591,15 +631,22 @@ store_symbols(bfd *abfd, int dynamic, void *minisyms, long symcount,
 	st->symcnt = 0;
 	sp = st->symtable;
 
-	if (machine_type("X86") || machine_type("X86_64")) {
-		if (!(kt->flags & RELOC_SET))
+	first = 0;
+	from = (bfd_byte *) minisyms;
+	fromend = from + symcount * size;
+
+	if (machine_type("X86")) {
+		if (!(kt->flags & RELOC_SET)) {
 			kt->flags |= RELOC_FORCE;
+		}
+	} else if (machine_type("X86_64")) {
+		if (kt->flags & RELOC_AUTO && !(kt->flags & RELOC_SET)) {
+			derive_kaslr_offset(abfd, dynamic, from,
+					fromend, size, store);
+		}
 	} else
 		kt->flags &= ~RELOC_SET;
 
-	first = 0;
-  	from = (bfd_byte *) minisyms;
-  	fromend = from + symcount * size;
   	for (; from < fromend; from += size)
     	{
       		if ((sym = bfd_minisymbol_to_symbol(abfd, dynamic, from, store))
-- 
1.9.0.rc1.175.g0b1dcb5




More information about the Crash-utility mailing list