[Skiboot] [PATCH 4/4] fast-reboot: verify firmware "romem" checksum

Nicholas Piggin npiggin at gmail.com
Tue Sep 18 15:49:53 AEST 2018


This takes a checksum of skiboot memory after boot that should be
unchanged during OS operation, and verifies it before allowing a
fast reboot.

This is not read-only memory from skiboot's point of view, beause
it includes things like the opal branch table that gets populated
during boot.

This helps to improve the integrity of firmware against host and
runtime firmware memory scribble bugs.

Signed-off-by: Nicholas Piggin <npiggin at gmail.com>
---
 core/fast-reboot.c   |  5 +++++
 core/init.c          | 47 ++++++++++++++++++++++++++++++++++++++++++++
 include/mem_region.h |  3 +++
 3 files changed, 55 insertions(+)

diff --git a/core/fast-reboot.c b/core/fast-reboot.c
index c3eb50ba..f4fb2daa 100644
--- a/core/fast-reboot.c
+++ b/core/fast-reboot.c
@@ -89,6 +89,11 @@ static bool fast_reboot_sanity_check(void)
 		return false;
 	}
 
+	if (!verify_romem()) {
+		disable_fast_reboot("Inconsistent firmware romem checksum");
+		return false;
+	}
+
 	return true;
 }
 
diff --git a/core/init.c b/core/init.c
index ca6c468c..eb769a0d 100644
--- a/core/init.c
+++ b/core/init.c
@@ -814,6 +814,51 @@ static void pci_nvram_init(void)
 	}
 }
 
+static uint32_t mem_csum(void *_p, void *_e)
+{
+	size_t len = _e - _p;
+	uint32_t *p = _p;
+	uint32_t v1 = 0, v2 = 0;
+	uint32_t csum;
+	unsigned int i;
+
+	for (i = 0; i < len; i += 4) {
+		uint32_t v = *p++;
+		v1 += v;
+		v2 += v1;
+	}
+
+	csum = v1 ^ v2;
+
+	return csum;
+}
+
+static uint32_t romem_csum;
+
+static void checksum_romem(void)
+{
+	uint32_t csum;
+
+	romem_csum = 0;
+
+	csum = mem_csum(_start, _romem_end);
+	romem_csum ^= csum;
+	csum = mem_csum(__builtin_kernel_start, __builtin_kernel_end);
+	romem_csum ^= csum;
+}
+
+bool verify_romem(void)
+{
+	uint32_t old = romem_csum;
+	checksum_romem();
+	if (old != romem_csum) {
+		romem_csum = old;
+		prlog(PR_NOTICE, "OPAL checksums did not match\n");
+		return false;
+	}
+	return true;
+}
+
 /* Called from head.S, thus no prototype. */
 void main_cpu_entry(const void *fdt);
 
@@ -1177,6 +1222,8 @@ void __noreturn __nomcount main_cpu_entry(const void *fdt)
 	/* On P9, switch to radix mode by default */
 	cpu_set_radix_mode();
 
+	checksum_romem();
+
 	load_and_boot_kernel(false);
 }
 
diff --git a/include/mem_region.h b/include/mem_region.h
index 018dfa0e..d9e490af 100644
--- a/include/mem_region.h
+++ b/include/mem_region.h
@@ -84,4 +84,7 @@ struct mem_region *find_mem_region(const char *name);
 
 bool mem_range_is_reserved(uint64_t start, uint64_t size);
 
+/* Read-only memory checksum */
+bool verify_romem(void);
+
 #endif /* __MEMORY_REGION */
-- 
2.18.0



More information about the Skiboot mailing list