If a QEMU COMPRESSED dump from a KASLR-enabled kernel is missing the vmcoreinfo data, try to calculate phys_base and kaslr_offset by using the technique developed by Takao Indoh. --- defs.h | 7 ++++- diskdump.c | 96 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ kaslr_helper.c | 3 ++ symbols.c | 4 +++ x86_64.c | 11 +++++-- 5 files changed, 118 insertions(+), 3 deletions(-) diff --git a/defs.h b/defs.h index 84fc85c..8c60b75 100644 --- a/defs.h +++ b/defs.h @@ -284,7 +284,7 @@ struct number_option { #define KVMDUMP_DUMPFILE() (pc->flags & KVMDUMP) #define SADUMP_DUMPFILE() (pc->flags & SADUMP) #define QEMU_MEM_DUMP_NO_VMCOREINFO() \ - ((pc->flags2 & (QEMU_MEM_DUMP_ELF)) && !(pc->flags2 & VMCOREINFO)) + ((pc->flags2 & (QEMU_MEM_DUMP_ELF|QEMU_MEM_DUMP_COMPRESSED)) && !(pc->flags2 & VMCOREINFO)) #define NETDUMP_LOCAL (0x1) /* netdump_data flags */ #define NETDUMP_REMOTE (0x2) @@ -6286,6 +6286,11 @@ void diskdump_display_regs(int, FILE *); void process_elf32_notes(void *, ulong); void process_elf64_notes(void *, ulong); void dump_registers_for_compressed_kdump(void); +int diskdump_kaslr_check(void); +int diskdump_kaslr_phys_base(ulong *); +int diskdump_set_kaslr_phys_base(ulong); +ulong diskdump_get_idtr(void); +ulong diskdump_get_cr3(void); /* * makedumpfile.c diff --git a/diskdump.c b/diskdump.c index b08a46c..1ec4bcf 100644 --- a/diskdump.c +++ b/diskdump.c @@ -56,6 +56,7 @@ struct diskdump_data { void **nt_prstatus_percpu; uint num_prstatus_notes; void **nt_qemu_percpu; + void **nt_qemucs_percpu; uint num_qemu_notes; /* page cache */ @@ -72,6 +73,7 @@ struct diskdump_data { ulong *valid_pages; ulong accesses; ulong snapshot_task; + ulong kaslr_phys_base; }; static struct diskdump_data diskdump_data = { 0 }; @@ -153,8 +155,13 @@ resize_note_pointers: dd->num_qemu_notes * sizeof(void *))) == NULL) error(FATAL, "compressed kdump: cannot realloc QEMU note pointers\n"); + if ((dd->nt_qemucs_percpu = realloc(dd->nt_qemucs_percpu, + dd->num_qemu_notes * sizeof(void *))) == NULL) + error(FATAL, + "compressed kdump: cannot realloc QEMU note pointers\n"); } else free(dd->nt_qemu_percpu); + free(dd->nt_qemucs_percpu); } } @@ -283,6 +290,10 @@ process_elf32_notes(void *note_buf, unsigned long size_note) } len = sizeof(Elf32_Nhdr); if (STRNEQ((char *)nt + len, "QEMU")) { + ulong *ptr = + (ulong *)((char *)nt + sizeof(Elf32_Nhdr) + nt->n_namesz); + dd->nt_qemucs_percpu[qemu_num] = + (ulong *)roundup((ulong) ptr, 4); dd->nt_qemu_percpu[qemu_num] = nt; qemu_num++; } @@ -332,6 +343,10 @@ process_elf64_notes(void *note_buf, unsigned long size_note) } len = sizeof(Elf64_Nhdr); if (STRNEQ((char *)nt + len, "QEMU")) { + ulong *ptr = + (ulong *)((char *)nt + sizeof(Elf64_Nhdr) + nt->n_namesz); + dd->nt_qemucs_percpu[qemu_num] = + (ulong *)roundup((ulong) ptr, 4); dd->nt_qemu_percpu[qemu_num] = nt; qemu_num++; } @@ -759,6 +774,10 @@ restart: error(FATAL, "qemu mem dump compressed: cannot malloc pointer" " to QEMU notes\n"); + if ((dd->nt_qemucs_percpu = malloc(NR_CPUS * sizeof(void *))) == NULL) + error(FATAL, "qemu mem dump compressed: cannot malloc pointer" + " to QEMUCS notes\n"); + if (FLAT_FORMAT()) { if (!read_flattened_format(dd->dfd, offset, dd->notes_buf, size)) { error(INFO, "compressed kdump: cannot read notes data" @@ -854,6 +873,8 @@ err: free(dd->nt_prstatus_percpu); if (dd->nt_qemu_percpu) free(dd->nt_qemu_percpu); + if (dd->nt_qemucs_percpu) + free(dd->nt_qemucs_percpu); dd->flags &= ~(DISKDUMP_LOCAL|KDUMP_CMPRS_LOCAL); pc->flags2 &= ~ELF_NOTES; @@ -2435,4 +2456,79 @@ dump_registers_for_compressed_kdump(void) } } +int diskdump_kaslr_check() +{ + if (!QEMU_MEM_DUMP_NO_VMCOREINFO()) + return FALSE; + + if (dd->num_qemu_notes) + return TRUE; + + return FALSE; +} + +int diskdump_kaslr_phys_base(ulong *kaslr_phys_base) +{ + if (!diskdump_kaslr_check()) + return FALSE; + + if (dd->kaslr_phys_base) { + *kaslr_phys_base = dd->kaslr_phys_base; + return TRUE; + } + + return FALSE; +} + +int diskdump_set_kaslr_phys_base(ulong kaslr_phys_base) +{ + if (!diskdump_kaslr_check()) + return FALSE; + + dd->kaslr_phys_base = kaslr_phys_base; + return TRUE; +} + +#ifdef X86_64 +static QEMUCPUState * get_qemucpustate(int cpu) +{ + if (cpu >= dd->num_qemu_notes) { + if (CRASHDEBUG(1)) + error(INFO, + "Invalid index for QEMU Note: %d (>= %d)\n", + cpu, dd->num_qemu_notes); + return NULL; + } + + if (dd->machine_type != EM_X86_64) { + if (CRASHDEBUG(1)) + error(INFO, "Only x86_64 64bit is supported.\n"); + return NULL; + } + + return (QEMUCPUState *)dd->nt_qemucs_percpu[cpu]; +} + +ulong diskdump_get_idtr() +{ + QEMUCPUState *cpustat; + + cpustat = get_qemucpustate(0); + if (!cpustat) { + return 0; + } + return cpustat->idt.base; +} + +ulong diskdump_get_cr3() +{ + QEMUCPUState *cpustat; + + cpustat = get_qemucpustate(0); + if (!cpustat) { + return 0; + } + return cpustat->cr[3]; +} +#endif diff --git a/kaslr_helper.c b/kaslr_helper.c index 1079863..5b71e3e 100644 --- a/kaslr_helper.c +++ b/kaslr_helper.c @@ -386,6 +386,9 @@ calc_kaslr_offset(ulong *kaslr_offset, ulong *phys_base) if (KDUMP_DUMPFILE()) { idtr = kdump_get_idtr(); cr3 = kdump_get_cr3(); + } else if (DISKDUMP_DUMPFILE()) { + idtr = diskdump_get_idtr(); + cr3 = diskdump_get_cr3(); } else { return FALSE; } diff --git a/symbols.c b/symbols.c index 348d9ae..614a36d 100644 --- a/symbols.c +++ b/symbols.c @@ -613,6 +613,8 @@ kaslr_init(void) if (QEMU_MEM_DUMP_NO_VMCOREINFO()) { if (KDUMP_DUMPFILE() && kdump_kaslr_check()) { kt->flags2 |= KASLR_CHECK; + } else if (DISKDUMP_DUMPFILE() && diskdump_kaslr_check()) { + kt->flags2 |= KASLR_CHECK; } } else if (KDUMP_DUMPFILE() || DISKDUMP_DUMPFILE()) { if ((string = pc->read_vmcoreinfo("SYMBOL(_stext)"))) { @@ -660,6 +662,8 @@ derive_kaslr_offset(bfd *abfd, int dynamic, bfd_byte *start, bfd_byte *end, sadump_set_phys_base(phys_base); else if (KDUMP_DUMPFILE()) kdump_set_phys_base(phys_base); + else if (DISKDUMP_DUMPFILE()) + diskdump_set_kaslr_phys_base(phys_base); } return; diff --git a/x86_64.c b/x86_64.c index ed5985a..3c492e4 100644 --- a/x86_64.c +++ b/x86_64.c @@ -6632,8 +6632,15 @@ x86_64_calc_phys_base(void) * Get relocation value from whatever dumpfile format is being used. */ - if (QEMU_MEM_DUMP_NO_VMCOREINFO() && KDUMP_DUMPFILE()) { - if (kdump_phys_base(&phys_base)) { + if (QEMU_MEM_DUMP_NO_VMCOREINFO()) { + int ret; + + if (KDUMP_DUMPFILE()) + ret = kdump_phys_base(&phys_base); + else if (DISKDUMP_DUMPFILE()) + ret = diskdump_kaslr_phys_base(&phys_base); + + if (ret) { machdep->machspec->phys_base = phys_base; if (CRASHDEBUG(1)) fprintf(fp, "kdump-novmci: phys base: %lx\n", -- 2.14.3 -- Crash-utility mailing list Crash-utility@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/crash-utility