-----Original Message-----
From: Takao Indoh [mailto:indou.takao@jp.fujitsu.com]
Sent: Friday, January 26, 2018 9:26 AM
To: crash-utility(a)redhat.com; Hatayama, Daisuke
<d.hatayama(a)jp.fujitsu.com>
Subject: [PATCH] sadump: Fix a problem of PTI enabled kernel
This patch fixes a problem that a dumpfile of sadump cannot be opened
by crash when Page Table Isolation(PTI) is enabled.
When PTI is enabled, bit 12 of CR3 register is used to split user
space and kernel space. Also bit 11:0 is used for Process Context
IDentifiers(PCID). To open a dump file of sadump, a value of CR3 is
used to calculate KASLR offset and phys_base, therefore this patch
fixes to mask CR3 register value collectly for PTI enabled kernel.
This patch also includes code cleanup.
Signed-off-by: Takao Indoh <indou.takao(a)jp.fujitsu.com>
---
defs.h | 2 ++
sadump.c | 33 +++++++++++++++++++++------------
symbols.c | 9 +++++++++
3 files changed, 32 insertions(+), 12 deletions(-)
diff --git a/defs.h b/defs.h
index dcd6c26..a19f280 100644
--- a/defs.h
+++ b/defs.h
@@ -2605,6 +2605,8 @@ struct symbol_table_data {
ulong divide_error_vmlinux;
ulong idt_table_vmlinux;
ulong saved_command_line_vmlinux;
+ ulong pti_init_vmlinux;
+ ulong kaiser_init_vmlinux;
};
/* flags for st */
diff --git a/sadump.c b/sadump.c
index 6b912d4..25cefe9 100644
--- a/sadump.c
+++ b/sadump.c
@@ -1749,7 +1749,7 @@ static ulong memparse(char *ptr, char **retptr)
* of elfcorehdr.
*/
static ulong
-get_elfcorehdr(ulong cr3, ulong kaslr_offset)
+get_elfcorehdr(ulong kaslr_offset)
{
char cmdline[BUFSIZE], *ptr;
ulong cmdline_vaddr;
@@ -1906,7 +1906,7 @@ get_vmcoreinfo(ulong elfcorehdr, ulong *addr, int *len)
* using "elfcorehdr=" and retrieve kaslr_offset/phys_base from
vmcoreinfo.
*/
static int
-get_kaslr_offset_from_vmcoreinfo(ulong cr3, ulong orig_kaslr_offset,
+get_kaslr_offset_from_vmcoreinfo(ulong orig_kaslr_offset,
ulong *kaslr_offset, ulong *phys_base)
{
ulong elfcorehdr_addr = 0;
@@ -1916,7 +1916,7 @@ get_kaslr_offset_from_vmcoreinfo(ulong cr3, ulong
orig_kaslr_offset,
int ret = FALSE;
/* Find "elfcorehdr=" in the kernel boot parameter */
- elfcorehdr_addr = get_elfcorehdr(cr3, orig_kaslr_offset);
+ elfcorehdr_addr = get_elfcorehdr(orig_kaslr_offset);
if (!elfcorehdr_addr)
return FALSE;
@@ -1973,8 +1973,8 @@ quit:
* 1) Get IDTR and CR3 value from the dump header.
* 2) Get a virtual address of IDT from IDTR value
* --- (A)
- * 3) Translate (A) to physical address using CR3, which points a top of
- * page table.
+ * 3) Translate (A) to physical address using CR3, the upper 52 bits
+ * of which points a top of page table.
* --- (B)
* 4) Get an address of vector0 (Devide Error) interrupt handler from
* IDT, which are pointed by (B).
@@ -2023,12 +2023,15 @@ quit:
* kernel. Retrieve vmcoreinfo from address of "elfcorehdr=" and
* get kaslr_offset and phys_base from vmcoreinfo.
*/
+#define PTI_USER_PGTABLE_BIT PAGE_SHIFT
+#define PTI_USER_PGTABLE_MASK (1 << PTI_USER_PGTABLE_BIT)
+#define CR3_PCID_MASK 0xFFFull
int
sadump_calc_kaslr_offset(ulong *kaslr_offset)
{
ulong phys_base = 0;
struct sadump_smram_cpu_state scs;
- uint64_t idtr = 0, cr3 = 0, idtr_paddr;
+ uint64_t idtr = 0, pgd = 0, idtr_paddr;
ulong divide_error_vmcore;
ulong kaslr_offset_kdump, phys_base_kdump;
int ret = FALSE;
@@ -2039,7 +2042,10 @@ sadump_calc_kaslr_offset(ulong *kaslr_offset)
memset(&scs, 0, sizeof(scs));
get_sadump_smram_cpu_state_any(&scs);
- cr3 = scs.Cr3;
+ if (st->pti_init_vmlinux || st->kaiser_init_vmlinux)
+ pgd = scs.Cr3 & ~(CR3_PCID_MASK|PTI_USER_PGTABLE_MASK);
+ else
+ pgd = scs.Cr3 & ~CR3_PCID_MASK;
idtr = ((uint64_t)scs.IdtUpper)<<32 | (uint64_t)scs.IdtLower;
/*
@@ -2050,12 +2056,12 @@ sadump_calc_kaslr_offset(ulong *kaslr_offset)
*
* TODO: XEN and 5-level is not supported
*/
- vt->kernel_pgd[0] = cr3;
+ vt->kernel_pgd[0] = pgd;
machdep->machspec->last_pml4_read = vt->kernel_pgd[0];
machdep->machspec->physical_mask_shift =
__PHYSICAL_MASK_SHIFT_2_6;
machdep->machspec->pgdir_shift = PGDIR_SHIFT;
- if (!readmem(cr3, PHYSADDR, machdep->machspec->pml4, PAGESIZE(),
- "cr3", RETURN_ON_ERROR))
+ if (!readmem(pgd, PHYSADDR, machdep->machspec->pml4, PAGESIZE(),
+ "pgd", RETURN_ON_ERROR))
goto quit;
/* Convert virtual address of IDT table to physical address */
@@ -2070,7 +2076,7 @@ sadump_calc_kaslr_offset(ulong *kaslr_offset)
if (CRASHDEBUG(1)) {
fprintf(fp, "calc_kaslr_offset: idtr=%lx\n", idtr);
- fprintf(fp, "calc_kaslr_offset: cr3=%lx\n", cr3);
+ fprintf(fp, "calc_kaslr_offset: pgd=%lx\n", pgd);
fprintf(fp, "calc_kaslr_offset: idtr(phys)=%lx\n",
idtr_paddr);
fprintf(fp, "calc_kaslr_offset:
divide_error(vmlinux): %lx\n",
st->divide_error_vmlinux);
@@ -2084,9 +2090,12 @@ sadump_calc_kaslr_offset(ulong *kaslr_offset)
* from vmcoreinfo
*/
if (get_kaslr_offset_from_vmcoreinfo(
- cr3, *kaslr_offset, &kaslr_offset_kdump,
&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, "sadump: failed to determine which kernel was
running at crash,\n");
+ fprintf(fp, "sadump: asssuming the kdump 1st kernel.\n");
}
if (CRASHDEBUG(1)) {
diff --git a/symbols.c b/symbols.c
index 2372887..26b319a 100644
--- a/symbols.c
+++ b/symbols.c
@@ -3072,10 +3072,14 @@ dump_symbol_table(void)
fprintf(fp, "divide_error_vmlinux: %lx\n",
st->divide_error_vmlinux);
fprintf(fp, " idt_table_vmlinux: %lx\n",
st->idt_table_vmlinux);
fprintf(fp, "saved_command_line_vmlinux: %lx\n",
st->saved_command_line_vmlinux);
+ fprintf(fp, " pti_init_vmlinux: %lx\n",
st->pti_init_vmlinux);
+ fprintf(fp, " kaiser_init_vmlinux: %lx\n",
st->kaiser_init_vmlinux);
} else {
fprintf(fp, "divide_error_vmlinux: (unused)\n");
fprintf(fp, " idt_table_vmlinux: (unused)\n");
fprintf(fp, "saved_command_line_vmlinux: (unused)\n");
+ fprintf(fp, " pti_init_vmlinux: (unused)\n");
+ fprintf(fp, " kaiser_init_vmlinux: (unused)\n");
}
fprintf(fp, " symval_hash[%d]: %lx\n", SYMVAL_HASH,
@@ -12306,6 +12310,11 @@ numeric_forward(const void *P_x, const void *P_y)
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);
--
1.8.3.1
It looks good to me. Thanks.
Dave, could you merge this patch?
Thanks.
HATAYAMA, Daisuke