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:
@ -301,6 +301,8 @@ endif
|
|||||||
|
|
||||||
CPPFLAGS_common := -Isrc -Isrc/include -Isrc/commonlib/include -I$(obj)
|
CPPFLAGS_common := -Isrc -Isrc/include -Isrc/commonlib/include -I$(obj)
|
||||||
CPPFLAGS_common += -Isrc/device/oprom/include
|
CPPFLAGS_common += -Isrc/device/oprom/include
|
||||||
|
VB_SOURCE ?= 3rdparty/vboot
|
||||||
|
CPPFLAGS_common += -I$(VB_SOURCE)/firmware/include
|
||||||
CPPFLAGS_common += -include $(src)/include/kconfig.h
|
CPPFLAGS_common += -include $(src)/include/kconfig.h
|
||||||
|
|
||||||
CFLAGS_common += -pipe -g -nostdinc
|
CFLAGS_common += -pipe -g -nostdinc
|
||||||
|
@ -108,6 +108,19 @@ int cbfs_for_each_file(const struct region_device *cbfs,
|
|||||||
return -1;
|
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,
|
int cbfs_locate(struct cbfsf *fh, const struct region_device *cbfs,
|
||||||
const char *name, uint32_t *type)
|
const char *name, uint32_t *type)
|
||||||
{
|
{
|
||||||
@ -148,13 +161,9 @@ int cbfs_locate(struct cbfsf *fh, const struct region_device *cbfs,
|
|||||||
if (type != NULL) {
|
if (type != NULL) {
|
||||||
uint32_t ftype;
|
uint32_t ftype;
|
||||||
|
|
||||||
if (rdev_readat(&fh->metadata, &ftype,
|
if (cbfsf_file_type(fh, &ftype))
|
||||||
offsetof(struct cbfs_file, type),
|
|
||||||
sizeof(ftype)) != sizeof(ftype))
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
ftype = read_be32(&ftype);
|
|
||||||
|
|
||||||
if (*type != ftype) {
|
if (*type != ftype) {
|
||||||
DEBUG(" Unmatched type %x at %zx\n", ftype,
|
DEBUG(" Unmatched type %x at %zx\n", ftype,
|
||||||
rdev_relative_offset(cbfs,
|
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);
|
LOG("'%s' not found.\n", name);
|
||||||
return -1;
|
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);
|
||||||
|
}
|
||||||
|
@ -18,6 +18,9 @@
|
|||||||
|
|
||||||
#include <commonlib/cbfs_serialized.h>
|
#include <commonlib/cbfs_serialized.h>
|
||||||
#include <commonlib/region.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. */
|
/* Object representing cbfs files. */
|
||||||
struct cbfsf {
|
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,
|
int cbfs_for_each_file(const struct region_device *cbfs,
|
||||||
const struct cbfsf *prev, struct cbfsf *fh);
|
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
|
#endif
|
||||||
|
@ -62,6 +62,7 @@ AGESA_INC += -I$(src)/southbridge/amd/pi/hudson
|
|||||||
AGESA_INC += -I$(src)/arch/x86/include
|
AGESA_INC += -I$(src)/arch/x86/include
|
||||||
AGESA_INC += -I$(src)/include
|
AGESA_INC += -I$(src)/include
|
||||||
AGESA_INC += -I$(src)/commonlib/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
|
AGESA_CFLAGS += -march=amdfam10 -mno-3dnow -fno-zero-initialized-in-bss -fno-strict-aliasing
|
||||||
CFLAGS_x86_32 += $(AGESA_CFLAGS)
|
CFLAGS_x86_32 += $(AGESA_CFLAGS)
|
||||||
|
@ -49,6 +49,4 @@ else
|
|||||||
CFLAGS_common += -DMOCK_TPM=0
|
CFLAGS_common += -DMOCK_TPM=0
|
||||||
endif
|
endif
|
||||||
|
|
||||||
VB_SOURCE ?= 3rdparty/vboot
|
|
||||||
subdirs-$(CONFIG_VBOOT_VERIFY_FIRMWARE) += vboot2
|
subdirs-$(CONFIG_VBOOT_VERIFY_FIRMWARE) += vboot2
|
||||||
CPPFLAGS_common += -I$(VB_SOURCE)/firmware/include
|
|
||||||
|
Reference in New Issue
Block a user