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

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