Aaron Durbin (adurbin@chromium.org) just uploaded a new patch set to gerrit, which you can find at https://review.coreboot.org/12786
-gerrit
commit e81f45a2449c5ab2092468aabb6598ad112620b5 Author: Aaron Durbin adurbin@chromium.org Date: Tue Dec 15 15:57:11 2015 -0600
commonlib: Add function to hash contents of a CBFS region.
Provide a common routine to hash the contents of a cbfs region. The cbfs region is hashed in the following order: 1. potential cbfs header at offset 0 2. potential cbfs header retlative offset at cbfs size - 4 3. For each file the metadata of the file. 4. For each non-empty file the data of the file.
BUG=chrome-os-partner:48412 BUG=chromium:445938 BRANCH=None TEST=Utilized in chromeos cros_bundle_firmware as well as at runtime during vboot verification on glados.
Change-Id: Ie1e5db5b8a80d9465e88d3f69f5367d887bdf73f Signed-off-by: Aaron Durbin adurbin@chromium.org --- Makefile.inc | 2 + src/commonlib/cbfs.c | 158 +++++++++++++++++++++++++++- src/commonlib/include/commonlib/cbfs.h | 12 +++ src/vendorcode/amd/pi/Makefile.inc | 1 + src/vendorcode/google/chromeos/Makefile.inc | 2 - 5 files changed, 168 insertions(+), 7 deletions(-)
diff --git a/Makefile.inc b/Makefile.inc index 06dea87..887fa1d 100644 --- a/Makefile.inc +++ b/Makefile.inc @@ -301,6 +301,8 @@ endif
CPPFLAGS_common := -Isrc -Isrc/include -Isrc/commonlib/include -I$(obj) CPPFLAGS_common += -Isrc/device/oprom/include +VB_SOURCE ?= 3rdparty/vboot +CPPFLAGS_common += -I$(VB_SOURCE)/firmware/include CPPFLAGS_common += -include $(src)/include/kconfig.h
CFLAGS_common += -pipe -g -nostdinc diff --git a/src/commonlib/cbfs.c b/src/commonlib/cbfs.c index 06d31ed..56faf28 100644 --- a/src/commonlib/cbfs.c +++ b/src/commonlib/cbfs.c @@ -108,6 +108,19 @@ int cbfs_for_each_file(const struct region_device *cbfs, return -1; }
+static int cbfsf_file_type(struct cbfsf *fh, uint32_t *ftype) +{ + const size_t sz = sizeof(*ftype); + + if (rdev_readat(&fh->metadata, ftype, + offsetof(struct cbfs_file, type), sz) != sz) + return -1; + + *ftype = read_be32(ftype); + + return 0; +} + int cbfs_locate(struct cbfsf *fh, const struct region_device *cbfs, const char *name, uint32_t *type) { @@ -148,13 +161,9 @@ int cbfs_locate(struct cbfsf *fh, const struct region_device *cbfs, if (type != NULL) { uint32_t ftype;
- if (rdev_readat(&fh->metadata, &ftype, - offsetof(struct cbfs_file, type), - sizeof(ftype)) != sizeof(ftype)) + if (cbfsf_file_type(fh, &ftype)) break;
- ftype = read_be32(&ftype); - if (*type != ftype) { DEBUG(" Unmatched type %x at %zx\n", ftype, rdev_relative_offset(cbfs, @@ -174,3 +183,142 @@ int cbfs_locate(struct cbfsf *fh, const struct region_device *cbfs, LOG("'%s' not found.\n", name); return -1; } + +static int cbfs_extend_hash_buffer(struct vb2_digest_context *ctx, + void *buf, size_t sz) +{ + return vb2_digest_extend(ctx, buf, sz); +} + +static int cbfs_extend_hash(struct vb2_digest_context *ctx, + const struct region_device *rdev) +{ + uint8_t buffer[1024]; + size_t sz_left; + size_t offset; + + sz_left = region_device_sz(rdev); + offset = 0; + + while (sz_left) { + int rv; + size_t block_sz = MIN(sz_left, sizeof(buffer)); + + if (rdev_readat(rdev, buffer, offset, block_sz) != block_sz) + return VB2_ERROR_UNKNOWN; + + rv = cbfs_extend_hash_buffer(ctx, buffer, block_sz); + + if (rv) + return rv; + + sz_left -= block_sz; + offset += block_sz; + } + + return VB2_SUCCESS; +} + +/* Include offsets of child regions within the parent into the hash. */ +static int cbfs_extend_hash_with_offset(struct vb2_digest_context *ctx, + const struct region_device *p, + const struct region_device *c) +{ + int32_t soffset; + int rv; + + soffset = rdev_relative_offset(p, c); + + if (soffset < 0) + return VB2_ERROR_UNKNOWN; + + /* All offsets in big endian format. */ + write_be32(&soffset, soffset); + + rv = cbfs_extend_hash_buffer(ctx, &soffset, sizeof(soffset)); + + if (rv) + return rv; + + return cbfs_extend_hash(ctx, c); +} + +/* Hash in the potential CBFS header sitting at the beginning of the CBFS + * region as well as relative offset at the end. */ +static int cbfs_extend_hash_master_header(struct vb2_digest_context *ctx, + const struct region_device *cbfs) +{ + struct region_device rdev; + int rv; + + if (rdev_chain(&rdev, cbfs, 0, sizeof(struct cbfs_header))) + return VB2_ERROR_UNKNOWN; + + rv = cbfs_extend_hash_with_offset(ctx, cbfs, &rdev); + + if (rv) + return rv; + + /* Include potential relative offset at end of region. */ + if (rdev_chain(&rdev, cbfs, region_device_sz(cbfs) - sizeof(int32_t), + sizeof(int32_t))) + return VB2_ERROR_UNKNOWN; + + return cbfs_extend_hash_with_offset(ctx, cbfs, &rdev); +} + +int cbfs_vb2_hash_contents(const struct region_device *cbfs, + enum vb2_hash_algorithm hash_alg, void *digest, + size_t digest_sz) +{ + struct vb2_digest_context ctx; + int rv; + struct cbfsf f; + struct cbfsf *prev; + struct cbfsf *fh; + + rv = vb2_digest_init(&ctx, hash_alg); + + if (rv) + return rv; + + rv = cbfs_extend_hash_master_header(&ctx, cbfs); + if (rv) + return rv; + + prev = NULL; + fh = &f; + + while (1) { + uint32_t ftype; + + rv = cbfs_for_each_file(cbfs, prev, fh); + prev = fh; + + if (rv < 0) + return VB2_ERROR_UNKNOWN; + + /* End of CBFS. */ + if (rv > 0) + break; + + rv = cbfs_extend_hash_with_offset(&ctx, cbfs, &fh->metadata); + + if (rv) + return rv; + + /* Include data contents in hash if file is non-empty. */ + if (cbfsf_file_type(fh, &ftype)) + return VB2_ERROR_UNKNOWN; + + if (ftype == CBFS_TYPE_DELETED || ftype == CBFS_TYPE_DELETED2) + continue; + + rv = cbfs_extend_hash_with_offset(&ctx, cbfs, &fh->data); + + if (rv) + return rv; + } + + return vb2_digest_finalize(&ctx, digest, digest_sz); +} diff --git a/src/commonlib/include/commonlib/cbfs.h b/src/commonlib/include/commonlib/cbfs.h index b0a468c..e1019c6 100644 --- a/src/commonlib/include/commonlib/cbfs.h +++ b/src/commonlib/include/commonlib/cbfs.h @@ -18,6 +18,9 @@
#include <commonlib/cbfs_serialized.h> #include <commonlib/region.h> +/* TODO: remove me! This is for vboot_handoff.c's benefit. */ +#define NEED_VB20_INTERNALS +#include <vb2_api.h>
/* Object representing cbfs files. */ struct cbfsf { @@ -52,4 +55,13 @@ static inline void cbfs_file_metadata(struct region_device *metadata, int cbfs_for_each_file(const struct region_device *cbfs, const struct cbfsf *prev, struct cbfsf *fh);
+/* + * Perform the vb2 hash over the CBFS region skipping empty file contents. + * Caller is responsiblef or providing the hash algorithm as well as storage + * for the final digest. Return 0 on success or non-zero on error. + */ +int cbfs_vb2_hash_contents(const struct region_device *cbfs, + enum vb2_hash_algorithm hash_alg, void *digest, + size_t digest_sz); + #endif diff --git a/src/vendorcode/amd/pi/Makefile.inc b/src/vendorcode/amd/pi/Makefile.inc index bb383b9..79d6171 100644 --- a/src/vendorcode/amd/pi/Makefile.inc +++ b/src/vendorcode/amd/pi/Makefile.inc @@ -62,6 +62,7 @@ AGESA_INC += -I$(src)/southbridge/amd/pi/hudson AGESA_INC += -I$(src)/arch/x86/include AGESA_INC += -I$(src)/include AGESA_INC += -I$(src)/commonlib/include +AGESA_INC += -I$(VB_SOURCE)/firmware/include
AGESA_CFLAGS += -march=amdfam10 -mno-3dnow -fno-zero-initialized-in-bss -fno-strict-aliasing CFLAGS_x86_32 += $(AGESA_CFLAGS) diff --git a/src/vendorcode/google/chromeos/Makefile.inc b/src/vendorcode/google/chromeos/Makefile.inc index ef84798..00fcd2f 100644 --- a/src/vendorcode/google/chromeos/Makefile.inc +++ b/src/vendorcode/google/chromeos/Makefile.inc @@ -49,6 +49,4 @@ else CFLAGS_common += -DMOCK_TPM=0 endif
-VB_SOURCE ?= 3rdparty/vboot subdirs-$(CONFIG_VBOOT_VERIFY_FIRMWARE) += vboot2 -CPPFLAGS_common += -I$(VB_SOURCE)/firmware/include