Julius Werner would like Furquan Shaikh and Aaron Durbin to review this change.

View Change

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;
}


To view, visit change 48839. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: coreboot
Gerrit-Branch: master
Gerrit-Change-Id: I3c6e8942e502035d365a193abf2cbe2f312e6561
Gerrit-Change-Number: 48839
Gerrit-PatchSet: 1
Gerrit-Owner: Julius Werner <jwerner@chromium.org>
Gerrit-Reviewer: Aaron Durbin <adurbin@chromium.org>
Gerrit-Reviewer: Furquan Shaikh <furquan@google.com>
Gerrit-MessageType: newchange