diff options
author | Aaron Durbin <adurbin@chromium.org> | 2015-12-15 15:57:11 -0600 |
---|---|---|
committer | Aaron Durbin <adurbin@chromium.org> | 2016-01-06 01:12:04 +0100 |
commit | cbb6c75061c5435f115629b1546e21157de3d194 (patch) | |
tree | 14a3ce70c8c780a1a5b7c5f7f38e29d2f40e92c9 | |
parent | 3e6303ebe20889235418e08706302f7976fdf33a (diff) | |
download | coreboot-cbb6c75061c5435f115629b1546e21157de3d194.tar.xz |
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>
Reviewed-on: https://review.coreboot.org/12786
Reviewed-by: Patrick Georgi <pgeorgi@google.com>
Tested-by: build bot (Jenkins)
-rw-r--r-- | Makefile.inc | 2 | ||||
-rw-r--r-- | src/commonlib/cbfs.c | 158 | ||||
-rw-r--r-- | src/commonlib/include/commonlib/cbfs.h | 12 | ||||
-rw-r--r-- | src/vendorcode/amd/pi/Makefile.inc | 1 | ||||
-rw-r--r-- | src/vendorcode/google/chromeos/Makefile.inc | 2 |
5 files changed, 168 insertions, 7 deletions
diff --git a/Makefile.inc b/Makefile.inc index 000ad639eb..76a828a4fb 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 06d31ed71e..56faf286ef 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 b0a468cdc9..c74dd708e3 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 responsible for 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 bb383b99a0..79d6171d95 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 ef84798521..00fcd2fb2b 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 |