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 | 5 ++++- diskdump.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ kaslr_helper.c | 9 ++++++++- symbols.c | 4 ++++ x86_64.c | 3 ++- 5 files changed, 79 insertions(+), 3 deletions(-) diff --git a/defs.h b/defs.h index ec2d61c..fe87a05 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) @@ -6274,6 +6274,7 @@ int diskdump_memory_dump(FILE *); FILE *set_diskdump_fp(FILE *); void get_diskdump_regs(struct bt_info *, ulong *, ulong *); int diskdump_phys_base(unsigned long *); +int diskdump_set_phys_base(unsigned long); ulong *diskdump_flags; int is_partial_diskdump(void); int dumpfile_is_split(void); @@ -6285,6 +6286,8 @@ 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); +QEMUCPUState *diskdump_get_qemucpustate(int); /* * makedumpfile.c diff --git a/diskdump.c b/diskdump.c index b08a46c..40ad59d 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 */ @@ -153,8 +154,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 +289,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 +342,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 +773,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 +872,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; @@ -967,6 +987,17 @@ diskdump_phys_base(unsigned long *phys_base) return FALSE; } +int +diskdump_set_phys_base(unsigned long phys_base) +{ + if (diskdump_kaslr_check()) { + dd->sub_header_kdump->phys_base = phys_base; + return TRUE; + } + + return FALSE; +} + /* * Check whether paddr is already cached. */ @@ -2435,4 +2466,34 @@ 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; +} + +#ifdef X86_64 +QEMUCPUState * diskdump_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]; +} +#endif diff --git a/kaslr_helper.c b/kaslr_helper.c index d02ef72..8646b8f 100644 --- a/kaslr_helper.c +++ b/kaslr_helper.c @@ -241,7 +241,14 @@ qemu_get_cr3_idtr(ulong *cr3, ulong *idtr) { QEMUCPUState *cpustat; - cpustat = kdump_get_qemucpustate(0); + if (DISKDUMP_DUMPFILE()) { + cpustat = diskdump_get_qemucpustate(0); + } else if (KDUMP_DUMPFILE()) { + cpustat = kdump_get_qemucpustate(0); + } else { + return FALSE; + } + if (!cpustat) { return FALSE; } diff --git a/symbols.c b/symbols.c index 348d9ae..ddbce7d 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_phys_base(phys_base); } return; diff --git a/x86_64.c b/x86_64.c index f6f6c0e..c36bf66 100644 --- a/x86_64.c +++ b/x86_64.c @@ -6633,7 +6633,8 @@ x86_64_calc_phys_base(void) */ if (QEMU_MEM_DUMP_NO_VMCOREINFO()) { - if (KDUMP_DUMPFILE() && kdump_phys_base(&phys_base)) + if ((KDUMP_DUMPFILE() && kdump_phys_base(&phys_base)) || + (DISKDUMP_DUMPFILE() && diskdump_phys_base(&phys_base))) machdep->machspec->phys_base = phys_base; if (!x86_64_virt_phys_base()) -- 2.14.3 -- Crash-utility mailing list Crash-utility@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/crash-utility