Hello Furquan Shaikh, Aaron Durbin,
I'd like you to do a code review. Please visit
https://review.coreboot.org/c/coreboot/+/48839
to review the following change.
Change subject: prog: Enable CBFS file hashing for programs ......................................................................
prog: Enable CBFS file hashing for programs
This patch enables CBFS file hashing for all programs (stages, payloads, etc.), except for some special cases with the Intel FSP that will need to be addressed in a later patch.
Signed-off-by: Julius Werner jwerner@chromium.org Change-Id: I3c6e8942e502035d365a193abf2cbe2f312e6561 --- M src/include/program_loading.h M src/lib/cbfs.c M src/lib/fit_payload.c M src/lib/prog_loaders.c M src/lib/rmodule.c M src/lib/selfboot.c 6 files changed, 54 insertions(+), 21 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/39/48839/1
diff --git a/src/include/program_loading.h b/src/include/program_loading.h index 57efd7b..01b0159 100644 --- a/src/include/program_loading.h +++ b/src/include/program_loading.h @@ -7,6 +7,7 @@ #include <commonlib/bsd/cbfs_serialized.h> #include <commonlib/region.h> #include <types.h> +#include <vb2_sha.h>
enum { /* Last segment of program. Can be used to take different actions for @@ -50,6 +51,7 @@ size_t size; /* Program size in memory (including BSS). */ void (*entry)(void *); /* Function pointer to entry point. */ void *arg; /* Optional argument (only valid for some archs). */ + struct vb2_hash hash; /* Content hash for CBFS_VERIFICATION. */ };
#define PROG_INIT(type_, name_) \ @@ -105,6 +107,11 @@ return prog->arg; }
+static inline const struct vb2_hash *prog_hash(const struct prog *prog) +{ + return &prog->hash; +} + /* region_device representing the 32-bit flat address space. */ extern const struct mem_region_device addrspace_32bit;
@@ -145,6 +152,13 @@ * value prohibits further progress */ int prog_locate_hook(struct prog *prog);
+/* rdev_mmap() the program source (with automatic verification). */ +void *prog_mmap(struct prog *prog); +static inline void prog_munmap(struct prog *prog, void *mapping) +{ + rdev_munmap(prog_rdev(prog), mapping); +} + /* Run the program described by prog. */ void prog_run(struct prog *prog); /* Per architecture implementation running a program. */ diff --git a/src/lib/cbfs.c b/src/lib/cbfs.c index bfbb7bc..b145177 100644 --- a/src/lib/cbfs.c +++ b/src/lib/cbfs.c @@ -398,13 +398,15 @@ !CONFIG(NO_XIP_EARLY_STAGES) && CONFIG(BOOT_DEVICE_MEMORY_MAPPED)) { void *mapping = rdev_mmap_full(rdev); rdev_munmap(rdev, mapping); + if (cbfs_file_hash_mismatch(mapping, region_device_sz(rdev), + prog_hash(pstage))) + return -1; if (mapping == prog_start(pstage)) return 0; }
- fsize = cbfs_stage_load_and_decompress(rdev, - prog_start(pstage), prog_size(pstage), - prog_compression(pstage), NULL); + fsize = cbfs_stage_load_and_decompress(rdev, prog_start(pstage), + prog_size(pstage), prog_compression(pstage), prog_hash(pstage)); if (!fsize) return -1;
diff --git a/src/lib/fit_payload.c b/src/lib/fit_payload.c index b3a03a1..2321826 100644 --- a/src/lib/fit_payload.c +++ b/src/lib/fit_payload.c @@ -174,7 +174,7 @@ struct region kernel = {0}, fdt = {0}, initrd = {0}; void *data;
- data = rdev_mmap_full(prog_rdev(payload)); + data = prog_mmap(payload);
if (data == NULL) return; @@ -185,14 +185,14 @@
if (!config) { printk(BIOS_ERR, "ERROR: Could not load FIT\n"); - rdev_munmap(prog_rdev(payload), data); + prog_munmap(payload, data); return; }
dt = unpack_fdt(config->fdt); if (!dt) { printk(BIOS_ERR, "ERROR: Failed to unflatten the FDT.\n"); - rdev_munmap(prog_rdev(payload), data); + prog_munmap(payload, data); return; }
@@ -225,7 +225,7 @@ if (!fit_payload_arch(payload, config, &kernel, &fdt, &initrd)) { printk(BIOS_ERR, "ERROR: Failed to find free memory region\n"); bootmem_dump_ranges(); - rdev_munmap(prog_rdev(payload), data); + prog_munmap(payload, data); return; }
@@ -240,7 +240,7 @@ extract(&initrd, config->ramdisk)) { printk(BIOS_ERR, "ERROR: Failed to extract initrd\n"); prog_set_entry(payload, NULL, NULL); - rdev_munmap(prog_rdev(payload), data); + prog_munmap(payload, data); return; }
@@ -249,11 +249,11 @@ if (extract(&kernel, config->kernel)) { printk(BIOS_ERR, "ERROR: Failed to extract kernel\n"); prog_set_entry(payload, NULL, NULL); - rdev_munmap(prog_rdev(payload), data); + prog_munmap(payload, data); return; }
timestamp_add_now(TS_START_KERNEL);
- rdev_munmap(prog_rdev(payload), data); + prog_munmap(payload, data); } diff --git a/src/lib/prog_loaders.c b/src/lib/prog_loaders.c index f75f2ee..e29d335 100644 --- a/src/lib/prog_loaders.c +++ b/src/lib/prog_loaders.c @@ -18,6 +18,7 @@ #include <timestamp.h> #include <fit_payload.h> #include <security/vboot/vboot_common.h> +#include <vb2_sha.h>
/* Only can represent up to 1 byte less than size_t. */ const struct mem_region_device addrspace_32bit = @@ -56,9 +57,32 @@ be32toh(stgh->entry_offset), NULL); }
+ prog->hash.algo = VB2_HASH_INVALID; + if (CONFIG(CBFS_VERIFICATION)) { + const struct vb2_hash *hash = cbfs_file_hash(&mdata); + if (hash) + memcpy(&prog->hash, hash, offsetof(struct vb2_hash, raw) + + vb2_digest_size(hash->algo)); + } + return CB_SUCCESS; }
+void *prog_mmap(struct prog *prog) +{ + struct region_device *rdev = prog_rdev(prog); + void *data = rdev_mmap_full(rdev); + + if (data && CONFIG(CBFS_VERIFICATION) && + vb2_hash_verify(data, region_device_sz(rdev), prog_hash(prog))) { + prog_munmap(prog, data); + printk(BIOS_CRIT, "CBFS file hash mismatch!\n"); + return NULL; + } + + return data; +} + void run_romstage(void) { struct prog romstage = diff --git a/src/lib/rmodule.c b/src/lib/rmodule.c index bcd7b18..0e2fcb3 100644 --- a/src/lib/rmodule.c +++ b/src/lib/rmodule.c @@ -263,7 +263,7 @@ prog_name(rsl->prog), rmod_loc, prog_size(prog));
if (!cbfs_load_and_decompress(prog_rdev(prog), rmod_loc, - prog_size(prog), prog_compression(prog), NULL)) + prog_size(prog), prog_compression(prog), prog_hash(prog))) return -1;
if (rmodule_parse(rmod_loc, &rmod_stage)) diff --git a/src/lib/selfboot.c b/src/lib/selfboot.c index c5ad525..66782b3 100644 --- a/src/lib/selfboot.c +++ b/src/lib/selfboot.c @@ -225,20 +225,13 @@ return 0; }
-static void *selfprepare(struct prog *payload) -{ - void *data; - data = rdev_mmap_full(prog_rdev(payload)); - return data; -} - static bool _selfload(struct prog *payload, checker_t f, void *args) { uintptr_t entry = 0; struct cbfs_payload_segment *cbfssegs; void *data;
- data = selfprepare(payload); + data = prog_mmap(payload); if (data == NULL) return false;
@@ -252,14 +245,14 @@
printk(BIOS_SPEW, "Loaded segments\n");
- rdev_munmap(prog_rdev(payload), data); + prog_munmap(payload, data);
/* Pass cbtables to payload if architecture desires it. */ prog_set_entry(payload, (void *)entry, cbmem_find(CBMEM_ID_CBTABLE));
return true; out: - rdev_munmap(prog_rdev(payload), data); + prog_munmap(payload, data); return false; }