summaryrefslogtreecommitdiff
path: root/src/commonlib
diff options
context:
space:
mode:
authorAaron Durbin <adurbin@chromium.org>2015-12-15 15:57:11 -0600
committerAaron Durbin <adurbin@chromium.org>2016-01-06 01:12:04 +0100
commitcbb6c75061c5435f115629b1546e21157de3d194 (patch)
tree14a3ce70c8c780a1a5b7c5f7f38e29d2f40e92c9 /src/commonlib
parent3e6303ebe20889235418e08706302f7976fdf33a (diff)
downloadcoreboot-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)
Diffstat (limited to 'src/commonlib')
-rw-r--r--src/commonlib/cbfs.c158
-rw-r--r--src/commonlib/include/commonlib/cbfs.h12
2 files changed, 165 insertions, 5 deletions
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