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

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