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