Blame SOURCES/kexec-tools-2.0.20-makedumpfile-PATCH-sadump-kaslr-fix-failure-of-calculating-kaslr.patch

255b7a
From 3c0cf7a93cff83f1e711e241eb47fcb096a451c5 Mon Sep 17 00:00:00 2001
255b7a
From: HATAYAMA Daisuke <d.hatayama@fujitsu.com>
255b7a
Date: Thu, 9 Jul 2020 18:27:49 +0900
255b7a
Subject: [PATCH] [PATCH] sadump, kaslr: fix failure of calculating
255b7a
 kaslr_offset due to an sadump format restriction
255b7a
255b7a
We faced recently a memory dump collected by sadump where unused part
255b7a
of register values are non-zero. For the crash dump, calculating
255b7a
kaslr_offset fails because it is based on the assumption that unused
255b7a
part of register values in the sadump format are always zero cleared.
255b7a
255b7a
The problem is that used and unused part of register values are
255b7a
rigorously indistinguishable in the sadump format. Although there is
255b7a
kernel data structure that represents a map between logical cpu
255b7a
numbers and lapic ids, they cannot be used in order to calculate
255b7a
kaslr_offset.
255b7a
255b7a
To fix this, we have no choice but use a trial-and-error approach: try
255b7a
to use each entry of register values in order until we find a good
255b7a
pair of cr3 and idtr by which we can refer to linux_banner symbol as
255b7a
expected.
255b7a
255b7a
Signed-off-by: HATAYAMA Daisuke <d.hatayama@fujitsu.com>
255b7a
---
255b7a
 sadump_info.c | 129 +++++++++++++++++++++++++++++++++++++++++-----------------
255b7a
 1 file changed, 91 insertions(+), 38 deletions(-)
255b7a
255b7a
diff --git a/makedumpfile-1.6.7/sadump_info.c b/makedumpfile-1.6.7/sadump_info.c
255b7a
index 72a077b4f408..410c6bc2a909 100644
255b7a
--- a/makedumpfile-1.6.7/sadump_info.c
255b7a
+++ b/makedumpfile-1.6.7/sadump_info.c
255b7a
@@ -101,6 +101,7 @@ static int lookup_diskset(unsigned long long whole_offset, int *diskid,
255b7a
 			  unsigned long long *disk_offset);
255b7a
 static int max_mask_cpu(void);
255b7a
 static int cpu_online_mask_init(void);
255b7a
+static int linux_banner_sanity_check(ulong cr3);
255b7a
 static int per_cpu_init(void);
255b7a
 static int get_data_from_elf_note_desc(const char *note_buf, uint32_t n_descsz,
255b7a
 				       char *name, uint32_t n_type, char **data);
255b7a
@@ -1293,6 +1294,30 @@ finish:
255b7a
 	return ret;
255b7a
 }
255b7a
 
255b7a
+static int linux_banner_sanity_check(ulong cr3)
255b7a
+{
255b7a
+	unsigned long linux_banner_paddr;
255b7a
+	char buf[sizeof("Linux version")];
255b7a
+
255b7a
+	linux_banner_paddr = vtop4_x86_64_pagetable(SYMBOL(linux_banner), cr3);
255b7a
+	if (linux_banner_paddr == NOT_PADDR) {
255b7a
+		DEBUG_MSG("sadump: linux_banner address translation failed\n");
255b7a
+		return FALSE;
255b7a
+	}
255b7a
+
255b7a
+	if (!readmem(PADDR, linux_banner_paddr, &buf, sizeof(buf))) {
255b7a
+		DEBUG_MSG("sadump: reading linux_banner failed\n");
255b7a
+		return FALSE;
255b7a
+	}
255b7a
+
255b7a
+	if (!STRNEQ(buf, "Linux version")) {
255b7a
+		DEBUG_MSG("sadump: linux_banner sanity check failed\n");
255b7a
+		return FALSE;
255b7a
+	}
255b7a
+
255b7a
+	return TRUE;
255b7a
+}
255b7a
+
255b7a
 /*
255b7a
  * Calculate kaslr_offset and phys_base
255b7a
  *
255b7a
@@ -1370,59 +1395,85 @@ calc_kaslr_offset(void)
255b7a
 {
255b7a
 	struct sadump_header *sh = si->sh_memory;
255b7a
 	uint64_t idtr = 0, cr3 = 0, idtr_paddr;
255b7a
-	struct sadump_smram_cpu_state smram, zero;
255b7a
+	struct sadump_smram_cpu_state smram;
255b7a
 	int apicid;
255b7a
 	unsigned long divide_error_vmcore, divide_error_vmlinux;
255b7a
 	unsigned long kaslr_offset, phys_base;
255b7a
 	unsigned long kaslr_offset_kdump, phys_base_kdump;
255b7a
+	int sanity_check_passed = FALSE;
255b7a
 
255b7a
-	memset(&zero, 0, sizeof(zero));
255b7a
 	for (apicid = 0; apicid < sh->nr_cpus; ++apicid) {
255b7a
+
255b7a
+		DEBUG_MSG("sadump: apicid: %d\n", apicid);
255b7a
+
255b7a
 		if (!get_smram_cpu_state(apicid, &smram)) {
255b7a
 			ERRMSG("get_smram_cpu_state error\n");
255b7a
 			return FALSE;
255b7a
 		}
255b7a
 
255b7a
-		if (memcmp(&smram, &zero, sizeof(smram)) != 0)
255b7a
-			break;
255b7a
-	}
255b7a
-	if (apicid >= sh->nr_cpus) {
255b7a
-		ERRMSG("Can't get smram state\n");
255b7a
-		return FALSE;
255b7a
-	}
255b7a
+		idtr = ((uint64_t)smram.IdtUpper)<<32|(uint64_t)smram.IdtLower;
255b7a
 
255b7a
-	idtr = ((uint64_t)smram.IdtUpper)<<32 | (uint64_t)smram.IdtLower;
255b7a
-	if ((SYMBOL(pti_init) != NOT_FOUND_SYMBOL) ||
255b7a
-	    (SYMBOL(kaiser_init) != NOT_FOUND_SYMBOL))
255b7a
-		cr3 = smram.Cr3 & ~(CR3_PCID_MASK|PTI_USER_PGTABLE_MASK);
255b7a
-	else
255b7a
-		cr3 = smram.Cr3 & ~CR3_PCID_MASK;
255b7a
+		if (!smram.Cr3 || !idtr) {
255b7a
+			DEBUG_MSG("sadump: cr3: %lx idt: %lx, skipped\n",
255b7a
+				  smram.Cr3, idtr);
255b7a
+			continue;
255b7a
+		}
255b7a
 
255b7a
-	/* Convert virtual address of IDT table to physical address */
255b7a
-	if ((idtr_paddr = vtop4_x86_64_pagetable(idtr, cr3)) == NOT_PADDR)
255b7a
-		return FALSE;
255b7a
+		if ((SYMBOL(pti_init) != NOT_FOUND_SYMBOL) ||
255b7a
+		    (SYMBOL(kaiser_init) != NOT_FOUND_SYMBOL))
255b7a
+			cr3 = smram.Cr3 & ~(CR3_PCID_MASK|PTI_USER_PGTABLE_MASK);
255b7a
+		else
255b7a
+			cr3 = smram.Cr3 & ~CR3_PCID_MASK;
255b7a
 
255b7a
-	/* Now we can calculate kaslr_offset and phys_base */
255b7a
-	divide_error_vmlinux = SYMBOL(divide_error);
255b7a
-	divide_error_vmcore = get_vec0_addr(idtr_paddr);
255b7a
-	kaslr_offset = divide_error_vmcore - divide_error_vmlinux;
255b7a
-	phys_base = idtr_paddr -
255b7a
-		(SYMBOL(idt_table) + kaslr_offset - __START_KERNEL_map);
255b7a
+		/* Convert virtual address of IDT table to physical address */
255b7a
+		idtr_paddr = vtop4_x86_64_pagetable(idtr, cr3);
255b7a
+		if (idtr_paddr == NOT_PADDR) {
255b7a
+			DEBUG_MSG("sadump: converting IDT physical address "
255b7a
+				  "failed.\n");
255b7a
+			continue;
255b7a
+		}
255b7a
 
255b7a
-	info->kaslr_offset = kaslr_offset;
255b7a
-	info->phys_base = phys_base;
255b7a
+		/* Now we can calculate kaslr_offset and phys_base */
255b7a
+		divide_error_vmlinux = SYMBOL(divide_error);
255b7a
+		divide_error_vmcore = get_vec0_addr(idtr_paddr);
255b7a
+		kaslr_offset = divide_error_vmcore - divide_error_vmlinux;
255b7a
+		phys_base = idtr_paddr -
255b7a
+			(SYMBOL(idt_table)+kaslr_offset-__START_KERNEL_map);
255b7a
 
255b7a
-	DEBUG_MSG("sadump: idtr=%" PRIx64 "\n", idtr);
255b7a
-	DEBUG_MSG("sadump: cr3=%" PRIx64 "\n", cr3);
255b7a
-	DEBUG_MSG("sadump: idtr(phys)=%" PRIx64 "\n", idtr_paddr);
255b7a
-	DEBUG_MSG("sadump: devide_error(vmlinux)=%lx\n",
255b7a
-		divide_error_vmlinux);
255b7a
-	DEBUG_MSG("sadump: devide_error(vmcore)=%lx\n",
255b7a
-		divide_error_vmcore);
255b7a
+		info->kaslr_offset = kaslr_offset;
255b7a
+		info->phys_base = phys_base;
255b7a
 
255b7a
-	/* Reload symbol */
255b7a
-	if (!get_symbol_info())
255b7a
-		return FALSE;
255b7a
+		DEBUG_MSG("sadump: idtr=%" PRIx64 "\n", idtr);
255b7a
+		DEBUG_MSG("sadump: cr3=%" PRIx64 "\n", cr3);
255b7a
+		DEBUG_MSG("sadump: idtr(phys)=%" PRIx64 "\n", idtr_paddr);
255b7a
+		DEBUG_MSG("sadump: devide_error(vmlinux)=%lx\n",
255b7a
+			  divide_error_vmlinux);
255b7a
+		DEBUG_MSG("sadump: devide_error(vmcore)=%lx\n",
255b7a
+			  divide_error_vmcore);
255b7a
+
255b7a
+		/* Reload symbol */
255b7a
+		if (!get_symbol_info()) {
255b7a
+			ERRMSG("Reading symbol table failed\n");
255b7a
+			return FALSE;
255b7a
+		}
255b7a
+
255b7a
+		/* Sanity check */
255b7a
+		if (linux_banner_sanity_check(cr3)) {
255b7a
+			sanity_check_passed = TRUE;
255b7a
+			break;
255b7a
+		}
255b7a
+
255b7a
+		info->kaslr_offset = 0;
255b7a
+		info->phys_base = 0;
255b7a
+	}
255b7a
+
255b7a
+	if (!sanity_check_passed) {
255b7a
+		ERRMSG("failed to calculate kaslr_offset and phys_base; "
255b7a
+		       "default to 0\n");
255b7a
+		info->kaslr_offset = 0;
255b7a
+		info->phys_base = 0;
255b7a
+		return TRUE;
255b7a
+	}
255b7a
 
255b7a
 	/*
255b7a
 	 * Check if current kaslr_offset/phys_base is for 1st kernel or 2nd
255b7a
@@ -1430,13 +1481,15 @@ calc_kaslr_offset(void)
255b7a
 	 * from vmcoreinfo
255b7a
 	 */
255b7a
 	if (get_kaslr_offset_from_vmcoreinfo(cr3, &kaslr_offset_kdump,
255b7a
-					    &phys_base_kdump)) {
255b7a
+					     &phys_base_kdump)) {
255b7a
 		info->kaslr_offset = kaslr_offset_kdump;
255b7a
 		info->phys_base = phys_base_kdump;
255b7a
 
255b7a
 		/* Reload symbol */
255b7a
-		if (!get_symbol_info())
255b7a
+		if (!get_symbol_info()) {
255b7a
+			ERRMSG("Reading symbol table failed\n");
255b7a
 			return FALSE;
255b7a
+		}
255b7a
 	}
255b7a
 
255b7a
 	DEBUG_MSG("sadump: kaslr_offset=%lx\n", info->kaslr_offset);
255b7a
-- 
255b7a
2.7.4
255b7a