[Crash-utility] [PATCH] sadump: Fix a problem of PTI enabled kernel

Takao Indoh indou.takao at jp.fujitsu.com
Fri Jan 26 00:25:41 UTC 2018


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 at 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





More information about the Crash-utility mailing list