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)
This commit is contained in:
Aaron Durbin 2015-12-15 15:57:11 -06:00
parent 3e6303ebe2
commit cbb6c75061
5 changed files with 168 additions and 7 deletions

View File

@ -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

View File

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

View File

@ -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

View File

@ -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)

View File

@ -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