[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@xxxxxxxxxx> --- 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 -- Crash-utility mailing list Crash-utility@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/crash-utility