369 lines
12 KiB
Diff
369 lines
12 KiB
Diff
From b97e7fd4e8268d5c46f1b30b41ce1f6ca9ceb216 Mon Sep 17 00:00:00 2001
|
|
From: HATAYAMA Daisuke <d.hatayama@fujitsu.com>
|
|
Date: Mon, 27 Jul 2020 19:00:19 +0900
|
|
Subject: [PATCH 1/4] symbols: Add linux_banner_vmlinux in symbol table
|
|
|
|
Add linux_banner_vmlinux in symbol table, which we'll later use in
|
|
calc_kaslr_offset() to do a sanity check in calculation of
|
|
kaslr_offset and phys_base.
|
|
|
|
Signed-off-by: HATAYAMA Daisuke <d.hatayama@fujitsu.com>
|
|
---
|
|
defs.h | 1 +
|
|
symbols.c | 10 ++++++++++
|
|
2 files changed, 11 insertions(+)
|
|
|
|
diff --git a/defs.h b/defs.h
|
|
index d7adb23b86d5..17e98763362b 100644
|
|
--- a/defs.h
|
|
+++ b/defs.h
|
|
@@ -2714,6 +2714,7 @@ struct symbol_table_data {
|
|
ulong pti_init_vmlinux;
|
|
ulong kaiser_init_vmlinux;
|
|
int kernel_symbol_type;
|
|
+ ulong linux_banner_vmlinux;
|
|
};
|
|
|
|
/* flags for st */
|
|
diff --git a/symbols.c b/symbols.c
|
|
index 3b1f08af43ff..b9de4a179d93 100644
|
|
--- a/symbols.c
|
|
+++ b/symbols.c
|
|
@@ -3226,6 +3226,11 @@ dump_symbol_table(void)
|
|
fprintf(fp, " kaiser_init_vmlinux: (unused)\n");
|
|
}
|
|
|
|
+ if (SADUMP_DUMPFILE())
|
|
+ fprintf(fp, "linux_banner_vmlinux: %lx\n", st->linux_banner_vmlinux);
|
|
+ else
|
|
+ fprintf(fp, "linux_banner_vmlinux: (unused)\n");
|
|
+
|
|
fprintf(fp, " symval_hash[%d]: %lx\n", SYMVAL_HASH,
|
|
(ulong)&st->symval_hash[0]);
|
|
|
|
@@ -12687,6 +12692,11 @@ numeric_forward(const void *P_x, const void *P_y)
|
|
else if (STREQ(y->name, "idt_table"))
|
|
st->idt_table_vmlinux = valueof(y);
|
|
|
|
+ if (STREQ(x->name, "linux_banner"))
|
|
+ st->linux_banner_vmlinux = valueof(x);
|
|
+ else if (STREQ(y->name, "linux_banner"))
|
|
+ st->linux_banner_vmlinux = valueof(y);
|
|
+
|
|
if (STREQ(x->name, "saved_command_line"))
|
|
st->saved_command_line_vmlinux = valueof(x);
|
|
else if (STREQ(y->name, "saved_command_line"))
|
|
--
|
|
2.7.4
|
|
|
|
|
|
From d494fabe99b90cea8d717a90951e44e6dbda84bb Mon Sep 17 00:00:00 2001
|
|
From: HATAYAMA Daisuke <d.hatayama@fujitsu.com>
|
|
Date: Mon, 27 Jul 2020 19:00:20 +0900
|
|
Subject: [PATCH 2/4] symbols: fix initialization of st->{pti_init,
|
|
kaiser}_vmlinux
|
|
|
|
In numeric_forward(), care must be taken both for x- and y- positions,
|
|
but either of kaiser_init and pti_init is only for x- or y- position
|
|
only. Fix this. Also, move the code in an appropriate position
|
|
according to each symbol name in the alphabetical order.
|
|
|
|
Signed-off-by: HATAYAMA Daisuke <d.hatayama@fujitsu.com>
|
|
---
|
|
symbols.c | 15 ++++++++++-----
|
|
1 file changed, 10 insertions(+), 5 deletions(-)
|
|
|
|
diff --git a/symbols.c b/symbols.c
|
|
index b9de4a179d93..2fecaee093a2 100644
|
|
--- a/symbols.c
|
|
+++ b/symbols.c
|
|
@@ -12692,20 +12692,25 @@ numeric_forward(const void *P_x, const void *P_y)
|
|
else if (STREQ(y->name, "idt_table"))
|
|
st->idt_table_vmlinux = valueof(y);
|
|
|
|
+ if (STREQ(x->name, "kaiser_init"))
|
|
+ st->kaiser_init_vmlinux = valueof(x);
|
|
+ else if (STREQ(y->name, "kaiser_init"))
|
|
+ st->kaiser_init_vmlinux = valueof(y);
|
|
+
|
|
if (STREQ(x->name, "linux_banner"))
|
|
st->linux_banner_vmlinux = valueof(x);
|
|
else if (STREQ(y->name, "linux_banner"))
|
|
st->linux_banner_vmlinux = valueof(y);
|
|
|
|
+ if (STREQ(x->name, "pti_init"))
|
|
+ st->pti_init_vmlinux = valueof(x);
|
|
+ else if (STREQ(y->name, "pti_init"))
|
|
+ st->pti_init_vmlinux = valueof(y);
|
|
+
|
|
if (STREQ(x->name, "saved_command_line"))
|
|
st->saved_command_line_vmlinux = valueof(x);
|
|
else if (STREQ(y->name, "saved_command_line"))
|
|
st->saved_command_line_vmlinux = valueof(y);
|
|
-
|
|
- if (STREQ(x->name, "pti_init"))
|
|
- st->pti_init_vmlinux = valueof(x);
|
|
- else if (STREQ(y->name, "kaiser_init"))
|
|
- st->kaiser_init_vmlinux = valueof(y);
|
|
}
|
|
|
|
xs = bfd_get_section(x);
|
|
--
|
|
2.7.4
|
|
|
|
|
|
From ff45c8da8cafed350940b1a56dce65f58051db5e Mon Sep 17 00:00:00 2001
|
|
From: HATAYAMA Daisuke <d.hatayama@fujitsu.com>
|
|
Date: Mon, 27 Jul 2020 19:00:22 +0900
|
|
Subject: [PATCH 3/4] kaslr: cleanup how to set values to the arguments of
|
|
calc_kaslr_offset()
|
|
|
|
Setting values of the arguments of calc_kaslr_offset() should be done
|
|
at the end of the function. Currently, they are set in the middle
|
|
where their values could still be changed according to
|
|
get_kaslr_offset_from_vmcoreinfo(). This behavior will be problematic
|
|
in the later commits when we implement a trial-and-error approach
|
|
because the value of kaslr_offset could be passed to the outside of
|
|
calc_kaslr_offset() unexpectedly. Thus, fix this first.
|
|
|
|
Signed-off-by: HATAYAMA Daisuke <d.hatayama@fujitsu.com>
|
|
---
|
|
kaslr_helper.c | 22 +++++++++++++---------
|
|
1 file changed, 13 insertions(+), 9 deletions(-)
|
|
|
|
diff --git a/kaslr_helper.c b/kaslr_helper.c
|
|
index fe5909caa937..acbb5c2692e2 100644
|
|
--- a/kaslr_helper.c
|
|
+++ b/kaslr_helper.c
|
|
@@ -394,10 +394,11 @@ quit:
|
|
#define PTI_USER_PGTABLE_MASK (1 << PTI_USER_PGTABLE_BIT)
|
|
#define CR3_PCID_MASK 0xFFFull
|
|
int
|
|
-calc_kaslr_offset(ulong *kaslr_offset, ulong *phys_base)
|
|
+calc_kaslr_offset(ulong *ko, ulong *pb)
|
|
{
|
|
uint64_t cr3 = 0, idtr = 0, pgd = 0, idtr_paddr;
|
|
ulong divide_error_vmcore;
|
|
+ ulong kaslr_offset, phys_base;
|
|
ulong kaslr_offset_kdump, phys_base_kdump;
|
|
int ret = FALSE;
|
|
int verbose = CRASHDEBUG(1)? 1: 0;
|
|
@@ -445,9 +446,9 @@ calc_kaslr_offset(ulong *kaslr_offset, ulong *phys_base)
|
|
|
|
/* Now we can calculate kaslr_offset and phys_base */
|
|
divide_error_vmcore = get_vec0_addr(idtr_paddr);
|
|
- *kaslr_offset = divide_error_vmcore - st->divide_error_vmlinux;
|
|
- *phys_base = idtr_paddr -
|
|
- (st->idt_table_vmlinux + *kaslr_offset - __START_KERNEL_map);
|
|
+ kaslr_offset = divide_error_vmcore - st->divide_error_vmlinux;
|
|
+ phys_base = idtr_paddr -
|
|
+ (st->idt_table_vmlinux + kaslr_offset - __START_KERNEL_map);
|
|
|
|
if (CRASHDEBUG(1)) {
|
|
fprintf(fp, "calc_kaslr_offset: idtr=%lx\n", idtr);
|
|
@@ -465,9 +466,9 @@ calc_kaslr_offset(ulong *kaslr_offset, ulong *phys_base)
|
|
* from vmcoreinfo
|
|
*/
|
|
if (get_kaslr_offset_from_vmcoreinfo(
|
|
- *kaslr_offset, &kaslr_offset_kdump, &phys_base_kdump)) {
|
|
- *kaslr_offset = kaslr_offset_kdump;
|
|
- *phys_base = phys_base_kdump;
|
|
+ kaslr_offset, &kaslr_offset_kdump, &phys_base_kdump)) {
|
|
+ kaslr_offset = kaslr_offset_kdump;
|
|
+ phys_base = phys_base_kdump;
|
|
} else if (CRASHDEBUG(1)) {
|
|
fprintf(fp, "kaslr_helper: failed to determine which kernel was running at crash,\n");
|
|
fprintf(fp, "kaslr_helper: asssuming the kdump 1st kernel.\n");
|
|
@@ -475,10 +476,13 @@ calc_kaslr_offset(ulong *kaslr_offset, ulong *phys_base)
|
|
|
|
if (CRASHDEBUG(1)) {
|
|
fprintf(fp, "calc_kaslr_offset: kaslr_offset=%lx\n",
|
|
- *kaslr_offset);
|
|
- fprintf(fp, "calc_kaslr_offset: phys_base=%lx\n", *phys_base);
|
|
+ kaslr_offset);
|
|
+ fprintf(fp, "calc_kaslr_offset: phys_base=%lx\n", phys_base);
|
|
}
|
|
|
|
+ *ko = kaslr_offset;
|
|
+ *pb = phys_base;
|
|
+
|
|
ret = TRUE;
|
|
quit:
|
|
vt->kernel_pgd[0] = 0;
|
|
--
|
|
2.7.4
|
|
|
|
|
|
From 8b50d94ada21f403665a5e562f40191f111e0313 Mon Sep 17 00:00:00 2001
|
|
From: HATAYAMA Daisuke <d.hatayama@fujitsu.com>
|
|
Date: Mon, 27 Jul 2020 19:00:23 +0900
|
|
Subject: [PATCH 4/4] kaslr: fix failure of calculating kaslr_offset due to an
|
|
sadump format restriction
|
|
|
|
We faced recently a memory dump collected by sadump where unused part
|
|
of register values are non-zero. For the crash dump, calculating
|
|
kaslr_offset fails because it is based on the assumption that unused
|
|
part of register values in the sadump format are always zero cleared.
|
|
|
|
The problem is that used and unused part of register values are
|
|
rigorously indistinguishable in the sadump format. Although there is
|
|
kernel data structure that represents a map between logical cpu
|
|
numbers and lapic ids, they cannot be used in order to calculate
|
|
kaslr_offset.
|
|
|
|
To fix this, we have no choice but use a trial-and-error approach: try
|
|
to use each entry of register values in order until we find a good
|
|
pair of cr3 and idtr by which we can refer to linux_banner symbol as
|
|
expected.
|
|
|
|
This fix is for the sadump specific issue, so there is no functional
|
|
change for the other crash dump formats.
|
|
|
|
[ lijiang: adjust the code indent. ]
|
|
|
|
Signed-off-by: HATAYAMA Daisuke <d.hatayama@fujitsu.com>
|
|
---
|
|
kaslr_helper.c | 39 +++++++++++++++++++++++++++++++++++----
|
|
sadump.c | 52 ++++++++++++++++++++++++++++------------------------
|
|
2 files changed, 63 insertions(+), 28 deletions(-)
|
|
|
|
diff --git a/kaslr_helper.c b/kaslr_helper.c
|
|
index acbb5c2692e2..bb19e548d04e 100644
|
|
--- a/kaslr_helper.c
|
|
+++ b/kaslr_helper.c
|
|
@@ -406,6 +406,7 @@ calc_kaslr_offset(ulong *ko, ulong *pb)
|
|
if (!machine_type("X86_64"))
|
|
return FALSE;
|
|
|
|
+retry:
|
|
if (SADUMP_DUMPFILE()) {
|
|
if (!sadump_get_cr3_idtr(&cr3, &idtr))
|
|
return FALSE;
|
|
@@ -437,12 +438,20 @@ calc_kaslr_offset(ulong *ko, ulong *pb)
|
|
machdep->machspec->pgdir_shift = PGDIR_SHIFT;
|
|
machdep->machspec->ptrs_per_pgd = PTRS_PER_PGD;
|
|
if (!readmem(pgd, PHYSADDR, machdep->pgd, PAGESIZE(),
|
|
- "pgd", RETURN_ON_ERROR))
|
|
- goto quit;
|
|
+ "pgd", RETURN_ON_ERROR)) {
|
|
+ if (SADUMP_DUMPFILE())
|
|
+ goto retry;
|
|
+ else
|
|
+ goto quit;
|
|
+ }
|
|
|
|
/* Convert virtual address of IDT table to physical address */
|
|
- if (!kvtop(NULL, idtr, &idtr_paddr, verbose))
|
|
- goto quit;
|
|
+ if (!kvtop(NULL, idtr, &idtr_paddr, verbose)) {
|
|
+ if (SADUMP_DUMPFILE())
|
|
+ goto retry;
|
|
+ else
|
|
+ goto quit;
|
|
+ }
|
|
|
|
/* Now we can calculate kaslr_offset and phys_base */
|
|
divide_error_vmcore = get_vec0_addr(idtr_paddr);
|
|
@@ -450,6 +459,28 @@ calc_kaslr_offset(ulong *ko, ulong *pb)
|
|
phys_base = idtr_paddr -
|
|
(st->idt_table_vmlinux + kaslr_offset - __START_KERNEL_map);
|
|
|
|
+ if (SADUMP_DUMPFILE()) {
|
|
+ char buf[sizeof("Linux version")];
|
|
+ ulong linux_banner_paddr;
|
|
+
|
|
+ if (!kvtop(NULL,
|
|
+ st->linux_banner_vmlinux + kaslr_offset,
|
|
+ &linux_banner_paddr,
|
|
+ verbose))
|
|
+ goto retry;
|
|
+
|
|
+ if (!readmem(linux_banner_paddr,
|
|
+ PHYSADDR,
|
|
+ buf,
|
|
+ sizeof(buf),
|
|
+ "linux_banner",
|
|
+ RETURN_ON_ERROR))
|
|
+ goto retry;
|
|
+
|
|
+ if (!STRNEQ(buf, "Linux version"))
|
|
+ goto retry;
|
|
+ }
|
|
+
|
|
if (CRASHDEBUG(1)) {
|
|
fprintf(fp, "calc_kaslr_offset: idtr=%lx\n", idtr);
|
|
fprintf(fp, "calc_kaslr_offset: pgd=%lx\n", pgd);
|
|
diff --git a/sadump.c b/sadump.c
|
|
index 35f7cf0fcf8f..009e17a4a44a 100644
|
|
--- a/sadump.c
|
|
+++ b/sadump.c
|
|
@@ -1664,29 +1664,32 @@ get_sadump_data(void)
|
|
static int
|
|
get_sadump_smram_cpu_state_any(struct sadump_smram_cpu_state *smram)
|
|
{
|
|
- ulong offset;
|
|
- struct sadump_header *sh = sd->dump_header;
|
|
- int apicid;
|
|
- struct sadump_smram_cpu_state scs, zero;
|
|
-
|
|
- offset = sd->sub_hdr_offset + sizeof(uint32_t) +
|
|
- sd->dump_header->nr_cpus * sizeof(struct sadump_apic_state);
|
|
-
|
|
- memset(&zero, 0, sizeof(zero));
|
|
-
|
|
- for (apicid = 0; apicid < sh->nr_cpus; ++apicid) {
|
|
- if (!read_device(&scs, sizeof(scs), &offset)) {
|
|
- error(INFO, "sadump: cannot read sub header "
|
|
- "cpu_state\n");
|
|
- return FALSE;
|
|
- }
|
|
- if (memcmp(&scs, &zero, sizeof(scs)) != 0) {
|
|
- *smram = scs;
|
|
- return TRUE;
|
|
- }
|
|
- }
|
|
-
|
|
- return FALSE;
|
|
+ ulong offset;
|
|
+ struct sadump_header *sh = sd->dump_header;
|
|
+ static int apicid;
|
|
+ struct sadump_smram_cpu_state scs;
|
|
+
|
|
+ if (apicid >= sh->nr_cpus)
|
|
+ return FALSE;
|
|
+
|
|
+ offset = sd->sub_hdr_offset + sizeof(uint32_t) +
|
|
+ sd->dump_header->nr_cpus * sizeof(struct sadump_apic_state) +
|
|
+ apicid * sizeof(scs);
|
|
+
|
|
+ while (apicid < sh->nr_cpus) {
|
|
+ apicid++;
|
|
+ if (!read_device(&scs, sizeof(scs), &offset)) {
|
|
+ error(INFO, "sadump: cannot read sub header "
|
|
+ "cpu_state\n");
|
|
+ return FALSE;
|
|
+ }
|
|
+ if (scs.Cr3 && (scs.IdtUpper || scs.IdtLower)) {
|
|
+ *smram = scs;
|
|
+ return TRUE;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return FALSE;
|
|
}
|
|
|
|
int
|
|
@@ -1695,7 +1698,8 @@ sadump_get_cr3_idtr(ulong *cr3, ulong *idtr)
|
|
struct sadump_smram_cpu_state scs;
|
|
|
|
memset(&scs, 0, sizeof(scs));
|
|
- get_sadump_smram_cpu_state_any(&scs);
|
|
+ if (!get_sadump_smram_cpu_state_any(&scs))
|
|
+ return FALSE;
|
|
|
|
*cr3 = scs.Cr3;
|
|
*idtr = ((uint64_t)scs.IdtUpper)<<32 | (uint64_t)scs.IdtLower;
|
|
--
|
|
2.7.4
|
|
|