Hello Aaron Durbin,
I'd like you to do a code review. Please visit
https://review.coreboot.org/c/coreboot/+/38421
to review the following change.
Change subject: commonlib/bsd: Add new CBFS core implementation ......................................................................
commonlib/bsd: Add new CBFS core implementation
This patch adds a new CBFS implementation that is intended to replace the existing commonlib/cbfs.c. The new implementation is designed to meet a bunch of current and future goals that in aggregate make it easier to start from scratch than to adapt the exisiting implementation:
1. Be BSD-licensed so it can evetually be shared with libpayload. 2. Allow generating/verifying a master hash for future CBFS per-file verification (see [1][2]). 3. Be very careful about reading (not mmaping) all data only once, to be suitable for eventual TOCTOU-safe verification. 4. Make it possibly to efficiently implement all current and future firmware use cases (both with and without verification).
The main primitive is the cbfs_walk() function which will traverse a CBFS and call a callback for every file. cbfs_lookup() uses this to implement the most common use case of finding a file so that it can be read. A host application using this code (e.g. coreboot, libpayload, cbfstool) will need to provide a <cbfs_glue.h> header to provide the glue to access the respective CBFS storage backend implementation.
This patch merely adds the code, the next patch will integrate it into coreboot.
[1]: https://www.youtube.com/watch?v=Hs_EhewBgtM [2]: https://osfc.io/uploads/talk/paper/47/The_future_of_firmware_verification_in...
Change-Id: Ica64c1751fa37686814c0247460c399261d5814c Signed-off-by: Julius Werner jwerner@chromium.org --- M MAINTAINERS A src/commonlib/bsd/cbfs_private.c M src/commonlib/bsd/include/commonlib/bsd/cb_err.h A src/commonlib/bsd/include/commonlib/bsd/cbfs_private.h M src/commonlib/bsd/include/commonlib/bsd/cbfs_serialized.h 5 files changed, 284 insertions(+), 5 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/21/38421/1
diff --git a/MAINTAINERS b/MAINTAINERS index 77769c0..b5cad10 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -489,8 +489,13 @@ F: src/device/oprom/
CBFS -F: src/include/cbfs.h -F: src/commonlib/bsd/include/commonlib/bsd/cbfs_serialized.h +M: Julius Werner jwerner@chromium.org +F: src/include/cbfs* +F: src/commonlib/bsd/include/commonlib/bsd/cbfs* +F: src/commonlib/bsd/cbfs* +F: src/lib/cbfs.c + +CBFSTOOL F: util/cbfstool/
CBMEM diff --git a/src/commonlib/bsd/cbfs_private.c b/src/commonlib/bsd/cbfs_private.c new file mode 100644 index 0000000..4dd14cb --- /dev/null +++ b/src/commonlib/bsd/cbfs_private.c @@ -0,0 +1,174 @@ +/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0-or-later */ + +#include <commonlib/bsd/cbfs_private.h> +#include <assert.h> + +static cb_err_t read_next_header(cbfs_dev_t dev, size_t *offset, struct cbfs_file *buffer) +{ + DEBUG("Looking for next file @%#zx...\n", *offset); + *offset = ALIGN_UP(*offset, CBFS_ALIGNMENT); + while (*offset + sizeof(*buffer) < cbfs_dev_size(dev)) { + if (cbfs_dev_read(dev, buffer, *offset, sizeof(*buffer)) != sizeof(*buffer)) + return CB_CBFS_IO; + + if (memcmp(buffer->magic, CBFS_FILE_MAGIC, sizeof(buffer->magic)) == 0) + return CB_SUCCESS; + + *offset += CBFS_ALIGNMENT; + } + + DEBUG("End of CBFS reached\n"); + return CB_CBFS_NOT_FOUND; +} + +cb_err_t cbfs_walk(cbfs_dev_t dev, cb_err_t (*walker)(cbfs_dev_t dev, size_t offset, + union cbfs_mdata *mdata, bool do_hash, + void *arg), + void *arg, struct vb2_hash *master_hash, enum cbfs_walk_flags flags) +{ + bool do_hash = ENABLE_HASHING && master_hash; + struct vb2_digest_context dc; + vb2_error_t vbrv; + + assert(ENABLE_HASHING || (!master_hash && !(flags & CBFS_WALK_WRITEBACK_HASH))); + if (do_hash && (vbrv = vb2_digest_init(&dc, master_hash->algo))) { + ERROR("Master hash algo %d digest init error: %#x\n", master_hash->algo, vbrv); + return CB_ERR_ARG; + } + + size_t offset = 0; + cb_err_t ret_header; + cb_err_t ret_walker = CB_CBFS_NOT_FOUND; + union cbfs_mdata mdata; + while ((ret_header = read_next_header(dev, &offset, &mdata.h)) == CB_SUCCESS) { + const uint32_t attr_offset = be32toh(mdata.h.attributes_offset); + const uint32_t data_offset = be32toh(mdata.h.offset); + const uint32_t data_length = be32toh(mdata.h.len); + const uint32_t type = be32toh(mdata.h.type); + const bool empty = (type == CBFS_TYPE_DELETED || type == CBFS_TYPE_DELETED2); + + DEBUG("Found CBFS header @%#zx (type %d, attr +%#x, data +%#x, length %#x)\n", + offset, be32toh(mdata.h.type), attr_offset, data_offset, data_length); + if (data_offset > sizeof(mdata)) { + ERROR("File metadata @%#zx too large\n", offset); + goto next_file; + } + if (offset + data_offset >= cbfs_dev_size(dev)) { + ERROR("Device ends in middle of metadata @%#zx\n", offset); + goto next_file; + } + + if (empty && !(flags & CBFS_WALK_INCLUDE_EMPTY)) + goto next_file; + + /* When hashing we need to read everything. Otherwise skip the attributes. + attr_offset may be 0, which means there are no attributes. */ + ssize_t todo; + if (do_hash || attr_offset == 0) + todo = data_offset - sizeof(mdata.h); + else + todo = attr_offset - sizeof(mdata.h); + if (todo <= 0 || data_offset < attr_offset) { + ERROR("Corrupt file header @%#zx\n", offset); + goto next_file; + } + + /* Read the rest of the metadata (filename, and possibly attributes). */ + if (cbfs_dev_read(dev, (uint8_t *)&mdata + sizeof(mdata.h), + offset + sizeof(mdata.h), todo) != todo) + return CB_CBFS_IO; + DEBUG("File name: '%s'\n", mdata.filename); + + if (do_hash && !empty && vb2_digest_extend(&dc, (void *)&mdata, data_offset)) + return CB_ERR; + + if (ret_walker == CB_CBFS_NOT_FOUND) + ret_walker = walker(dev, offset, &mdata, do_hash, arg); + + /* Return IO errors immediately. For others, finish the hash first if needed. */ + if (ret_walker == CB_CBFS_IO || (ret_walker != CB_CBFS_NOT_FOUND && !do_hash)) + return ret_walker; + +next_file: + offset += data_offset + data_length; + } + + if (ret_header != CB_CBFS_NOT_FOUND) + return ret_header; + + if (do_hash) { + uint8_t real_hash[VB2_MAX_DIGEST_SIZE]; + size_t hash_size = vb2_digest_size(master_hash->algo); + if (vb2_digest_finalize(&dc, real_hash, sizeof(real_hash))) + return CB_ERR; + if (flags & CBFS_WALK_WRITEBACK_HASH) + memcpy(master_hash->bytes.raw, real_hash, hash_size); + else if (memcmp(master_hash->bytes.raw, real_hash, hash_size) != 0) + return CB_CBFS_HASH; + } + + return ret_walker; +} + +cb_err_t cbfs_copy_fill_metadata(union cbfs_mdata *dst, union cbfs_mdata *src, + cbfs_dev_t dev, size_t offset, bool do_hash) +{ + const size_t attr_offset = be32toh(src->h.attributes_offset); + + /* In the hashing case or when there are no attributes, we already have everything. */ + if (do_hash || attr_offset == 0) { + memcpy(dst, src, be32toh(src->h.offset)); + return CB_SUCCESS; + } + + /* Otherwise we'll need to copy what we have and read in the rest. */ + const size_t todo = be32toh(src->h.offset) - attr_offset; + memcpy(dst, src, attr_offset); + void *dst_attrs = (uint8_t *)dst + attr_offset; + if (cbfs_dev_read(dev, dst_attrs, offset + attr_offset, todo) != todo) + return CB_CBFS_IO; + return CB_SUCCESS; +} + +uint32_t cbfs_filename_size(struct cbfs_file *h) +{ + uint32_t end_offset = be32toh(h->attributes_offset); + if (end_offset == 0) + end_offset = be32toh(h->offset); + return end_offset - sizeof(struct cbfs_file); +} + +struct cbfs_lookup_args { + union cbfs_mdata *mdata_out; + const char *name; + size_t namesize; + size_t *data_offset_out; +}; + +static cb_err_t lookup_walker(cbfs_dev_t dev, size_t offset, union cbfs_mdata *mdata, + bool do_hash, void *arg) +{ + struct cbfs_lookup_args *args = arg; + if (args->namesize > cbfs_filename_size(&mdata->h) || + memcmp(args->name, mdata->filename, args->namesize) != 0) + return CB_CBFS_NOT_FOUND; + + LOG("Found '%s' @%#zx size %#x\n", args->name, offset, be32toh(mdata->h.len)); + if (cbfs_copy_fill_metadata(args->mdata_out, mdata, dev, offset, do_hash) != CB_SUCCESS) + return CB_CBFS_IO; + + *args->data_offset_out = offset + be32toh(mdata->h.offset); + return CB_SUCCESS; +} + +cb_err_t cbfs_lookup(cbfs_dev_t dev, const char *name, union cbfs_mdata *mdata_out, + size_t *data_offset_out, struct vb2_hash *master_hash) +{ + struct cbfs_lookup_args args = { + .mdata_out = mdata_out, + .name = name, + .namesize = strlen(name) + 1, /* Count trailing \0 so we can memcmp() it. */ + .data_offset_out = data_offset_out, + }; + return cbfs_walk(dev, lookup_walker, &args, master_hash, 0); +} diff --git a/src/commonlib/bsd/include/commonlib/bsd/cb_err.h b/src/commonlib/bsd/include/commonlib/bsd/cb_err.h index ab419a7..ab422e1 100644 --- a/src/commonlib/bsd/include/commonlib/bsd/cb_err.h +++ b/src/commonlib/bsd/include/commonlib/bsd/cb_err.h @@ -34,6 +34,11 @@ CB_I2C_PROTOCOL_ERROR = -302, /**< Data lost or spurious slave device response, try again? */ CB_I2C_TIMEOUT = -303, /**< Transmission timed out */ + + /* CBFS errors */ + CB_CBFS_IO = -400, /**< Underlying I/O error */ + CB_CBFS_NOT_FOUND = -401, /**< File not found in directory */ + CB_CBFS_HASH = -402, /**< Master hash validation failed */ };
/* Don't typedef the enum directly, so the size is unambiguous for serialization. */ diff --git a/src/commonlib/bsd/include/commonlib/bsd/cbfs_private.h b/src/commonlib/bsd/include/commonlib/bsd/cbfs_private.h new file mode 100644 index 0000000..b4fc1c7 --- /dev/null +++ b/src/commonlib/bsd/include/commonlib/bsd/cbfs_private.h @@ -0,0 +1,95 @@ +/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0-or-later */ + +#ifndef _COMMONLIB_BSD_CBFS_PRIVATE_H_ +#define _COMMONLIB_BSD_CBFS_PRIVATE_H_ + +#include <commonlib/bsd/cb_err.h> +#include <commonlib/bsd/cbfs_serialized.h> +#include <endian.h> +#include <stdbool.h> +#include <stdint.h> +#include <vb2_sha.h> + +/* + * This file needs to be provided by the host application using this CBFS library. It must + * define the following type, macros and functions: + * + * cbfs_dev_t An opaque type representing a CBFS storage backend. + * ENABLE_HASHING Should be 0 to avoid linking hashing features, 1 otherwise. + * ERROR(...) printf-style macro to print errors. + * LOG(...) printf-style macro to print normal-operation log messages. + * DEBUG(...) printf-style macro to print detailed debug output. + * + * ssize_t cbfs_dev_read(cbfs_dev_t dev, void *buffer, size_t offset, size_t size); + * Read |size| bytes starting at |offset| from |dev| into |buffer|. + * Returns amount of bytes read on success and < 0 on error. + * + * size_t cbfs_dev_size(cbfs_dev_t dev); + * Return the total size in bytes of the CBFS storage (actual CBFS area). + */ +#include <cbfs_glue.h> + +/* Helper structure to allocate space for a blob of metadata on the stack. */ +#define CBFS_METADATA_MAX_SIZE 256 +union cbfs_mdata { + struct { + struct cbfs_file h; + char filename[]; + }; + uint8_t raw[CBFS_METADATA_MAX_SIZE]; +}; + +/* Flags that modify behavior of cbfs_walk(). */ +enum cbfs_walk_flags { + /* Write the calculated hash back out to |master_hash->hash|, rather than comparing it. + |master_hash->algo| must still have been initialized by the caller. */ + CBFS_WALK_WRITEBACK_HASH = (1 << 0), + /* Call |walker| for empty file entries. Otherwise, empty entries will be skipped. + Either way, empty entries are never included in master_hash calculation. */ + CBFS_WALK_INCLUDE_EMPTY = (1 << 1), +}; + +/* + * Traverse a CBFS and call a |walker| callback function for every file. Can additionally + * calculate a master hash over the metadata of all files in the CBFS. If |master_hash| is NULL, + * hashing is disabled. + * + * |arg| and |dev| will be passed through to |walker| unmodified. |do_hash| is true iff + * hashing is enabled (master_hash != NULL). |offset| is the total offset in |dev| at which the + * current file metadata starts. |mdata| is a temporary buffer (only valid for the duration of + * this call to |walker|) containing already read metadata from the current file: if |do_hash| + * is true, all metadata in |mdata| (header, filename and attributes) will be valid, otherwise + * only the header and the filename (not attributes) will be valid. |walker| should call into + * cbfs_copy_fill_medadata() to copy the metadata of a file to a persistent buffer and + * automatically load remaining attributes from |dev| as needed based on |do_hash|. + * + * |walker| should return CB_CBFS_NOT_FOUND if it wants to continue being called for further + * files. Any other return code will be used as the final return code for cbfs_walk(). It will + * return immediately unless it needs to calculate a hash in which case it will still traverse + * the remaining CBFS (but not call |walker| anymore). + */ +cb_err_t cbfs_walk(cbfs_dev_t dev, cb_err_t (*walker)(cbfs_dev_t dev, size_t offset, + union cbfs_mdata *mdata, bool do_hash, + void *arg), + void *arg, struct vb2_hash *master_hash, enum cbfs_walk_flags); + + +/* + * Helper function that can be used by a |walker| callback to cbfs_walk() to copy the metadata + * of a file into a permanent buffer. Will copy the metadata from |src| into |dst| and load + * additional attributes from |dev| to copy behind that if |do_hash| is false. (|offset| is the + * offset of the whole file metadata, not just of the attributes.) + */ +cb_err_t cbfs_copy_fill_metadata(union cbfs_mdata *dst, union cbfs_mdata *src, + cbfs_dev_t dev, size_t offset, bool do_hash); + +/* Helper function to determine the size of the filename part in a CBFS header. The actual + filename is NUL-terminated and due to alignment likely a bit shorter than this. */ +uint32_t cbfs_filename_size(struct cbfs_file *h); + +/* Find a file named |name| in the CBFS on |dev| and copy its metadata (including attributes) + * into |mdata_out|. Pass out offset to the file data and verify |master_hash| (if provided). */ +cb_err_t cbfs_lookup(cbfs_dev_t dev, const char *name, union cbfs_mdata *mdata_out, + size_t *data_offset_out, struct vb2_hash *master_hash); + +#endif /* _COMMONLIB_BSD_CBFS_PRIVATE_H_ */ diff --git a/src/commonlib/bsd/include/commonlib/bsd/cbfs_serialized.h b/src/commonlib/bsd/include/commonlib/bsd/cbfs_serialized.h index d2fc626..556c8e4 100644 --- a/src/commonlib/bsd/include/commonlib/bsd/cbfs_serialized.h +++ b/src/commonlib/bsd/include/commonlib/bsd/cbfs_serialized.h @@ -4,6 +4,7 @@ #define _CBFS_SERIALIZED_H_
#include <stdint.h> +#include <vb2_sha.h>
/** These are standard values for the known compression algorithms that coreboot knows about for stages and @@ -123,12 +124,11 @@ uint32_t decompressed_size; } __packed;
+/* Actual size in CBFS may be larger/smaller than struct size! */ struct cbfs_file_attr_hash { uint32_t tag; uint32_t len; - uint32_t hash_type; - /* hash_data is len - sizeof(struct) bytes */ - uint8_t hash_data[]; + struct vb2_hash hash; } __packed;
struct cbfs_file_attr_position {
build bot (Jenkins) has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/38421 )
Change subject: commonlib/bsd: Add new CBFS core implementation ......................................................................
Patch Set 1:
(1 comment)
https://review.coreboot.org/c/coreboot/+/38421/1/src/commonlib/bsd/cbfs_priv... File src/commonlib/bsd/cbfs_private.c:
https://review.coreboot.org/c/coreboot/+/38421/1/src/commonlib/bsd/cbfs_priv... PS1, Line 34: if (do_hash && (vbrv = vb2_digest_init(&dc, master_hash->algo))) { do not use assignment in if condition
Julius Werner has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/38421 )
Change subject: commonlib/bsd: Add new CBFS core implementation ......................................................................
Patch Set 1:
(1 comment)
https://review.coreboot.org/c/coreboot/+/38421/1/src/commonlib/bsd/include/c... File src/commonlib/bsd/include/commonlib/bsd/cbfs_serialized.h:
https://review.coreboot.org/c/coreboot/+/38421/1/src/commonlib/bsd/include/c... PS1, Line 131: struct vb2_hash hash; This is from CL:1963614 which still needs to land.
build bot (Jenkins) has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/38421 )
Change subject: commonlib/bsd: Add new CBFS core implementation ......................................................................
Patch Set 2:
(1 comment)
https://review.coreboot.org/c/coreboot/+/38421/2/src/commonlib/bsd/cbfs_priv... File src/commonlib/bsd/cbfs_private.c:
https://review.coreboot.org/c/coreboot/+/38421/2/src/commonlib/bsd/cbfs_priv... PS2, Line 34: if (do_hash && (vbrv = vb2_digest_init(&dc, master_hash->algo))) { do not use assignment in if condition
build bot (Jenkins) has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/38421 )
Change subject: commonlib/bsd: Add new CBFS core implementation ......................................................................
Patch Set 3:
(1 comment)
https://review.coreboot.org/c/coreboot/+/38421/3/src/commonlib/bsd/cbfs_priv... File src/commonlib/bsd/cbfs_private.c:
https://review.coreboot.org/c/coreboot/+/38421/3/src/commonlib/bsd/cbfs_priv... PS3, Line 34: if (do_hash && (vbrv = vb2_digest_init(&dc, master_hash->algo))) { do not use assignment in if condition
Julius Werner has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/38421 )
Change subject: commonlib/bsd: Add new CBFS core implementation ......................................................................
Patch Set 3:
(1 comment)
https://review.coreboot.org/c/coreboot/+/38421/1/src/commonlib/bsd/include/c... File src/commonlib/bsd/include/commonlib/bsd/cbfs_serialized.h:
https://review.coreboot.org/c/coreboot/+/38421/1/src/commonlib/bsd/include/c... PS1, Line 131: struct vb2_hash hash;
This is from CL:1963614 which still needs to land.
Done
build bot (Jenkins) has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/38421 )
Change subject: commonlib/bsd: Add new CBFS core implementation ......................................................................
Patch Set 4:
(1 comment)
https://review.coreboot.org/c/coreboot/+/38421/4/src/commonlib/bsd/cbfs_priv... File src/commonlib/bsd/cbfs_private.c:
https://review.coreboot.org/c/coreboot/+/38421/4/src/commonlib/bsd/cbfs_priv... PS4, Line 34: if (do_hash && (vbrv = vb2_digest_init(&dc, master_hash->algo))) { do not use assignment in if condition
Aaron Durbin has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/38421 )
Change subject: commonlib/bsd: Add new CBFS core implementation ......................................................................
Patch Set 4:
(16 comments)
https://review.coreboot.org/c/coreboot/+/38421/4/src/commonlib/bsd/cbfs_priv... File src/commonlib/bsd/cbfs_private.c:
https://review.coreboot.org/c/coreboot/+/38421/4/src/commonlib/bsd/cbfs_priv... PS4, Line 10: cbfs_dev_size(dev) Shouldn't we just call this once? The size of dev shouldn't change.
https://review.coreboot.org/c/coreboot/+/38421/4/src/commonlib/bsd/cbfs_priv... PS4, Line 29: ENABLE_HASHING This should probably be namespaced better.
https://review.coreboot.org/c/coreboot/+/38421/4/src/commonlib/bsd/cbfs_priv... PS4, Line 54: goto next_file; Shouldn't this be a major error? If we're wanting to ensure we touch every file this algo just bypasses things that aren't the correct size.
https://review.coreboot.org/c/coreboot/+/38421/4/src/commonlib/bsd/cbfs_priv... PS4, Line 56: if (offset + data_offset >= cbfs_dev_size(dev)) { Wouldn't this fail on the read()? But if you are wanting to check this shouldn't you be ensuring the data length doesn't exceed the device size too?
https://review.coreboot.org/c/coreboot/+/38421/4/src/commonlib/bsd/cbfs_priv... PS4, Line 77: (uint8_t *)&mdata Shouldn't we be reading into the byte array here and above? Then interpret through the union for the cbfs_file?
https://review.coreboot.org/c/coreboot/+/38421/4/src/commonlib/bsd/cbfs_priv... PS4, Line 88: For others, finish the hash first if needed. Could you please elaborate on why?
https://review.coreboot.org/c/coreboot/+/38421/4/src/commonlib/bsd/cbfs_priv... PS4, Line 102: sizeof(real_hash) sorry for not being familiar w/ vb2 APIs, but it seems weird to pass in sizeof(real_hash) when it's just the possible max -- not the actual digest size.
https://review.coreboot.org/c/coreboot/+/38421/4/src/commonlib/bsd/cbfs_priv... PS4, Line 123: There doesn't appear to be any checks against the size of the structures. offset and attributes_offset could exceed the size of cbf_mdata. You're checking data_offset above. But not that the data fits.
https://review.coreboot.org/c/coreboot/+/38421/4/src/commonlib/bsd/include/c... File src/commonlib/bsd/include/commonlib/bsd/cbfs_private.h:
https://review.coreboot.org/c/coreboot/+/38421/4/src/commonlib/bsd/include/c... PS4, Line 61: header, filename and attributes Shouldn't we be passing along the metadata size? Why is the callback needing the logic to figure out where the attributes and filename live? I know's it's some addition, but it seems better to calculate that up front?
https://review.coreboot.org/c/coreboot/+/38421/4/src/commonlib/bsd/include/c... PS4, Line 69: * the remaining CBFS (but not call |walker| anymore). This function seems a bit overloaded. Can't we wrap all this with some entry points that provide the semantics we need w/o throwing everything into a single call?
https://review.coreboot.org/c/coreboot/+/38421/4/src/commonlib/bsd/include/c... PS4, Line 72: union cbfs_mdata *mdata Why isn't this const?
https://review.coreboot.org/c/coreboot/+/38421/4/src/commonlib/bsd/include/c... PS4, Line 80: to copy behind that I don't understand what this is saying. If do_hash is true it won't copy additional attributes? What is additional? Is it just omitting the hash attributes?
https://review.coreboot.org/c/coreboot/+/38421/4/src/commonlib/bsd/include/c... PS4, Line 83: union cbfs_mdata *src const
https://review.coreboot.org/c/coreboot/+/38421/4/src/commonlib/bsd/include/c... PS4, Line 87: bit shorter than this 'This' being the size returned?
https://review.coreboot.org/c/coreboot/+/38421/4/src/commonlib/bsd/include/c... PS4, Line 91: offset to the file data relative or absolute within |dev| ?
Also, what is master_hash at this point? Is the assumption that all of cbfs metadata is checked prior to filling in the parameters? Or is this the hash for the metadata itself?
https://review.coreboot.org/c/coreboot/+/38421/4/src/commonlib/bsd/include/c... File src/commonlib/bsd/include/commonlib/bsd/cbfs_serialized.h:
https://review.coreboot.org/c/coreboot/+/38421/4/src/commonlib/bsd/include/c... PS4, Line 131: struct vb2_hash hash;
-------union { ------->-------uint8_t raw[0];
#if VB2_SUPPORT_SHA1
------->-------uint8_t sha1[VB2_SHA1_DIGEST_SIZE];
#endif #if VB2_SUPPORT_SHA256
------->-------uint8_t sha256[VB2_SHA256_DIGEST_SIZE];
#endif #if VB2_SUPPORT_SHA512
------->-------uint8_t sha512[VB2_SHA512_DIGEST_SIZE];
#endif
-------} bytes;
How are we envisioning dealing with this? From your added comment it'll be dynamic as before?
The other thing that you've done here is changed the serialized format by changing hash_type from a 32-bit value to a single byte. Shouldn't we add a new type and tag so things can be backwards compatible?
Hello Aaron Durbin, build bot (Jenkins),
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/coreboot/+/38421
to look at the new patch set (#5).
Change subject: commonlib/bsd: Add new CBFS core implementation ......................................................................
commonlib/bsd: Add new CBFS core implementation
This patch adds a new CBFS implementation that is intended to replace the existing commonlib/cbfs.c. The new implementation is designed to meet a bunch of current and future goals that in aggregate make it easier to start from scratch than to adapt the exisiting implementation:
1. Be BSD-licensed so it can evetually be shared with libpayload. 2. Allow generating/verifying a master hash for future CBFS per-file verification (see [1][2]). 3. Be very careful about reading (not mmaping) all data only once, to be suitable for eventual TOCTOU-safe verification. 4. Make it possibly to efficiently implement all current and future firmware use cases (both with and without verification).
The main primitive is the cbfs_walk() function which will traverse a CBFS and call a callback for every file. cbfs_lookup() uses this to implement the most common use case of finding a file so that it can be read. A host application using this code (e.g. coreboot, libpayload, cbfstool) will need to provide a <cbfs_glue.h> header to provide the glue to access the respective CBFS storage backend implementation.
This patch merely adds the code, the next patch will integrate it into coreboot.
[1]: https://www.youtube.com/watch?v=Hs_EhewBgtM [2]: https://osfc.io/uploads/talk/paper/47/The_future_of_firmware_verification_in...
Change-Id: Ica64c1751fa37686814c0247460c399261d5814c Signed-off-by: Julius Werner jwerner@chromium.org --- M MAINTAINERS A src/commonlib/bsd/cbfs_private.c M src/commonlib/bsd/include/commonlib/bsd/cb_err.h A src/commonlib/bsd/include/commonlib/bsd/cbfs_private.h M src/commonlib/bsd/include/commonlib/bsd/cbfs_serialized.h 5 files changed, 269 insertions(+), 5 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/21/38421/5
build bot (Jenkins) has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/38421 )
Change subject: commonlib/bsd: Add new CBFS core implementation ......................................................................
Patch Set 5:
(1 comment)
https://review.coreboot.org/c/coreboot/+/38421/5/src/commonlib/bsd/cbfs_priv... File src/commonlib/bsd/cbfs_private.c:
https://review.coreboot.org/c/coreboot/+/38421/5/src/commonlib/bsd/cbfs_priv... PS5, Line 35: if (do_hash && (vbrv = vb2_digest_init(&dc, master_hash->algo))) { do not use assignment in if condition
Julius Werner has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/38421 )
Change subject: commonlib/bsd: Add new CBFS core implementation ......................................................................
Patch Set 5:
(16 comments)
https://review.coreboot.org/c/coreboot/+/38421/4/src/commonlib/bsd/cbfs_priv... File src/commonlib/bsd/cbfs_private.c:
https://review.coreboot.org/c/coreboot/+/38421/4/src/commonlib/bsd/cbfs_priv... PS4, Line 10: cbfs_dev_size(dev)
Shouldn't we just call this once? The size of dev shouldn't change.
I mean... it's the cost for what's probably a small inline function, compared to the cost of a SPI read in the loop. But okay, I can factor it out.
https://review.coreboot.org/c/coreboot/+/38421/4/src/commonlib/bsd/cbfs_priv... PS4, Line 29: ENABLE_HASHING
This should probably be namespaced better.
Changed to CBFS_ENABLE_HASHING.
https://review.coreboot.org/c/coreboot/+/38421/4/src/commonlib/bsd/cbfs_priv... PS4, Line 54: goto next_file;
Shouldn't this be a major error? If we're wanting to ensure we touch every file this algo just bypas […]
I was just trying to continue where possible and skip over broken files rather than abort completely. This just checks that the metadata fits in my arbitrarily-defined CBFS_METADATA_MAX_SIZE. Eventually cbfstool should ensure it doesn't write headers larger than that, but it doesn't do that yet... and just in case someone somehow manages to write a file with a larger header, I think skipping over it makes more sense than aborting completely. In the hashing case you'll likely fail anyway, of course, but in the non-hashing case you might still find what you were looking for.
https://review.coreboot.org/c/coreboot/+/38421/4/src/commonlib/bsd/cbfs_priv... PS4, Line 56: if (offset + data_offset >= cbfs_dev_size(dev)) {
Wouldn't this fail on the read()? But if you are wanting to check this shouldn't you be ensuring the […]
Yeah, I don't remember why I added this. Will take it out.
https://review.coreboot.org/c/coreboot/+/38421/4/src/commonlib/bsd/cbfs_priv... PS4, Line 77: (uint8_t *)&mdata
Shouldn't we be reading into the byte array here and above? Then interpret through the union for the […]
Good point, that's cleaner.
https://review.coreboot.org/c/coreboot/+/38421/4/src/commonlib/bsd/cbfs_priv... PS4, Line 88: For others, finish the hash first if needed.
Could you please elaborate on why?
To make the API more flexible, so that callers can use return codes for things that aren't catastrophic errors. For example, the mcache code can return CB_CBFS_CACHE_FULL out of its walker() function when it runs out of memory to cache things in. Then the function that called cbfs_walk() can recognize that the cache wasn't fully built, but it can still continue booting with a half-usable cache. However, if the hash didn't verify it still needs to know that, so CB_CBFS_HASH must have priority over the errors returned from walker(). And the only way to check if the hash verified is to walk all the way to the end.
For IO errors the assumption is that the cbfs_dev is busted anyway and any further reading would be pointless (and earlier parts of this function could have already returned that anyway). So the return code priority is CB_CBFS_IO -> CB_CBFS_HASH -> other errors/CB_SUCCESS -> CB_CBFS_NOT_FOUND. Clarified this in the header file comment.
https://review.coreboot.org/c/coreboot/+/38421/4/src/commonlib/bsd/cbfs_priv... PS4, Line 102: sizeof(real_hash)
sorry for not being familiar w/ vb2 APIs, but it seems weird to pass in sizeof(real_hash) when it's […]
I can pass hash_size too, doesn't really make a difference.
https://review.coreboot.org/c/coreboot/+/38421/4/src/commonlib/bsd/cbfs_priv... PS4, Line 123:
There doesn't appear to be any checks against the size of the structures. […]
cbfs_walk() checks (data_offset > sizeof(mdata)) and (data_offset < attr_offset), so I think these cases should be handled? The idea is that cbfs_walk() will do these basic sanity checks on stuff it passes to walker() so we don't have to do it here anymore.
https://review.coreboot.org/c/coreboot/+/38421/4/src/commonlib/bsd/include/c... File src/commonlib/bsd/include/commonlib/bsd/cbfs_private.h:
https://review.coreboot.org/c/coreboot/+/38421/4/src/commonlib/bsd/include/c... PS4, Line 61: header, filename and attributes
Shouldn't we be passing along the metadata size? Why is the callback needing the logic to figure out […]
You mean pass the size of the metadata that was already read, rather than a boolean? Yeah, actually, it looks like that would work out pretty well. Rewritten.
https://review.coreboot.org/c/coreboot/+/38421/4/src/commonlib/bsd/include/c... PS4, Line 69: * the remaining CBFS (but not call |walker| anymore).
This function seems a bit overloaded. […]
This is already supposed to be the underlying workhorse function, the wrappers are things like cbfs_lookup() and cbfs_mcache_build(). coreboot is never supposed to call into this directly (cbfstool might or I might create more wrappers for those use cases when I get there, haven't looked into that part much yet).
I agree it's a bit complex but I tried to come up with something that can support all the use cases (normal lookup, mcache, cbfstool stuff) from one piece of core code. I think that will be better in the end than e.g. implementing the cbfstool stuff completely separately (because the hashing is tied through everything and it always needs to calculate it in exactly the same way).
https://review.coreboot.org/c/coreboot/+/38421/4/src/commonlib/bsd/include/c... PS4, Line 72: union cbfs_mdata *mdata
Why isn't this const?
Done
https://review.coreboot.org/c/coreboot/+/38421/4/src/commonlib/bsd/include/c... PS4, Line 80: to copy behind that
I don't understand what this is saying. […]
I meant "load additional metadata which is the attributes". It's never splitting attributes. If do_hash is true that means all attributes are already loaded, if it is false that means no attributes have been loaded yet.
Changed this whole thing according to the suggestion above which I think resolves this confusion as well (you just tell it exactly how many bytes are already valid in |src| now).
https://review.coreboot.org/c/coreboot/+/38421/4/src/commonlib/bsd/include/c... PS4, Line 83: union cbfs_mdata *src
const
Done
https://review.coreboot.org/c/coreboot/+/38421/4/src/commonlib/bsd/include/c... PS4, Line 87: bit shorter than this
'This' being the size returned?
Yes, but I decided to remove this function anyway
https://review.coreboot.org/c/coreboot/+/38421/4/src/commonlib/bsd/include/c... PS4, Line 91: offset to the file data
relative or absolute within |dev| ? […]
Not sure what you mean, relative to what? This is absolute. (Absolute to the cbfs_dev_t, that is, which may of course be relative to the whole SPI flash -- but this API doesn't have knowledge of that layer.)
"master_hash" is always supposed to be the metadata hash (I'll make sure to call the individual file hashes something else when I add that part). The point of this function is to return the (verified) metadata and data offset for a given file. The file data itself is not touched in any way, loading and verifying the file will be up to the caller.
Rewrote a bit, let me know if it's clearer now.
https://review.coreboot.org/c/coreboot/+/38421/4/src/commonlib/bsd/include/c... File src/commonlib/bsd/include/commonlib/bsd/cbfs_serialized.h:
https://review.coreboot.org/c/coreboot/+/38421/4/src/commonlib/bsd/include/c... PS4, Line 131: struct vb2_hash hash; Yes, this struct is supposed to have a somewhat dynamic length. The 'bytes' union shall only be valid up to the length of the current hash_type. I wanted something that can be easily allocated on the stack (then it would just be the length of the longest compiled-in hash) but is also compatible with the existing serialized attribute format (so you can just pass a pointer into a metadata blob to vboot without having to copy it out). cbfstool would have to ensure to write out the right amount of bytes for the hash_type when serializing it, and coreboot functions using the raw attribute data should sanity-check that the attribute size fits vb2_digest_size(hash.algo) before passing it around.
The other thing that you've done here is changed the serialized format by changing hash_type from a 32-bit value to a single byte. Shouldn't we add a new type and tag so things can be backwards compatible?
Oh crap, I'm a moron... this was meant to be backwards compatible, but I just realized I screwed it up. The idea was to change the 4 byte into 1 byte and 3 reserved so that it still matches the old bit representation but isn't going to cause any endianness problems going forward anymore. But of course the correct way to do that for a 4-byte big endian where we've only ever used the lowest byte is
uint8_t reserved[3]; uint8_t algo;
not the way I did it. I uploaded CL:2019952 to fix that in vboot.
Patrick Rudolph has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/38421 )
Change subject: commonlib/bsd: Add new CBFS core implementation ......................................................................
Patch Set 5:
(1 comment)
https://review.coreboot.org/c/coreboot/+/38421/5/src/commonlib/bsd/include/c... File src/commonlib/bsd/include/commonlib/bsd/cbfs_serialized.h:
https://review.coreboot.org/c/coreboot/+/38421/5/src/commonlib/bsd/include/c... PS5, Line 7: #include <vb2_sha.h> is this going to be part of commonlib? I'm asking as 3rdparty software might want to ship src/commonlib/*/include as coreboot-dev distro package, which would be unusable without that header.
Julius Werner has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/38421 )
Change subject: commonlib/bsd: Add new CBFS core implementation ......................................................................
Patch Set 5:
(1 comment)
https://review.coreboot.org/c/coreboot/+/38421/5/src/commonlib/bsd/include/c... File src/commonlib/bsd/include/commonlib/bsd/cbfs_serialized.h:
https://review.coreboot.org/c/coreboot/+/38421/5/src/commonlib/bsd/include/c... PS5, Line 7: #include <vb2_sha.h>
is this going to be part of commonlib? […]
Yes, all software that wants to build commonlib code may also need to build vboot. That's just unavoidable if I want to have all this hashing stuff integrated in the commonlib CBFS stack. vboot is already BSD licensed so this would not be a restriction in that area.
I'm not sure how it would make sense to ship this header individually anywhere. This is only interesting to CBFS readers, and my goal with all this is to unify all CBFS readers into using the same cbfs_walk() commonlib code anyway.
build bot (Jenkins) has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/38421 )
Change subject: commonlib/bsd: Add new CBFS core implementation ......................................................................
Patch Set 6:
(1 comment)
https://review.coreboot.org/c/coreboot/+/38421/6/src/commonlib/bsd/cbfs_priv... File src/commonlib/bsd/cbfs_private.c:
https://review.coreboot.org/c/coreboot/+/38421/6/src/commonlib/bsd/cbfs_priv... PS6, Line 35: if (do_hash && (vbrv = vb2_digest_init(&dc, master_hash->algo))) { do not use assignment in if condition
Patrick Rudolph has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/38421 )
Change subject: commonlib/bsd: Add new CBFS core implementation ......................................................................
Patch Set 6:
(1 comment)
https://review.coreboot.org/c/coreboot/+/38421/5/src/commonlib/bsd/include/c... File src/commonlib/bsd/include/commonlib/bsd/cbfs_serialized.h:
https://review.coreboot.org/c/coreboot/+/38421/5/src/commonlib/bsd/include/c... PS5, Line 7: #include <vb2_sha.h>
Yes, all software that wants to build commonlib code may also need to build vboot. […]
I like the idea of having a shared code base, but in order to use it in 3rdparty apps we might need to move it to a single repo. Now that verification is an essential part of the cbfs itself it might make even more sense. The coreboot support for FWTS will make use of distros shipping coreboot-dev, and with a dependency to vboot-dev this seems even more unlikely to see a broad distribution.
Julius Werner has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/38421 )
Change subject: commonlib/bsd: Add new CBFS core implementation ......................................................................
Patch Set 6:
(1 comment)
https://review.coreboot.org/c/coreboot/+/38421/5/src/commonlib/bsd/include/c... File src/commonlib/bsd/include/commonlib/bsd/cbfs_serialized.h:
https://review.coreboot.org/c/coreboot/+/38421/5/src/commonlib/bsd/include/c... PS5, Line 7: #include <vb2_sha.h>
I like the idea of having a shared code base, but in order to use it in 3rdparty apps we might need […]
I don't think we'd want to pull all of vboot into the coreboot repository. It's a big codebase and it is intended to be usable by other firmware stacks as well. The submodule model has served us pretty well for those cases for now and I think we'd want to keep that. If you want to build a coreboot-dev header package for a certain distro, you're welcome to throw in vboot headers there if you want though.
One other thing I could do here is to #include <cbfs_glue.h> and then put an #if CBFS_ENABLE_HASHING block around both the #include and the hash attribute definition. That way if another codebase wants to use CBFS stuff without checking out the vboot sources somewhere, they can just supply a <cbfs_glue.h> with #define CBFS_ENABLE_HASHING 0 and use it like that. (It goes against my general rule of never preprocessor-guarding #includes, but in this case I can agree that it may make sense in some situations.) Would that help your use case?
build bot (Jenkins) has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/38421 )
Change subject: commonlib/bsd: Add new CBFS core implementation ......................................................................
Patch Set 7:
(1 comment)
https://review.coreboot.org/c/coreboot/+/38421/7/src/commonlib/bsd/cbfs_priv... File src/commonlib/bsd/cbfs_private.c:
https://review.coreboot.org/c/coreboot/+/38421/7/src/commonlib/bsd/cbfs_priv... PS7, Line 35: if (do_hash && (vbrv = vb2_digest_init(&dc, master_hash->algo))) { do not use assignment in if condition
Angel Pons has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/38421 )
Change subject: commonlib/bsd: Add new CBFS core implementation ......................................................................
Patch Set 7: Code-Review+1
(1 comment)
https://review.coreboot.org/c/coreboot/+/38421/7/src/commonlib/bsd/include/c... File src/commonlib/bsd/include/commonlib/bsd/cb_err.h:
https://review.coreboot.org/c/coreboot/+/38421/7/src/commonlib/bsd/include/c... PS7, Line 41: CB_CBFS_HASH I would add some word to this to make its meaning a bit clearer, how about `CB_CBFS_HASH_CHECK_FAIL` ?
Julius Werner has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/38421 )
Change subject: commonlib/bsd: Add new CBFS core implementation ......................................................................
Patch Set 7:
(1 comment)
https://review.coreboot.org/c/coreboot/+/38421/7/src/commonlib/bsd/include/c... File src/commonlib/bsd/include/commonlib/bsd/cb_err.h:
https://review.coreboot.org/c/coreboot/+/38421/7/src/commonlib/bsd/include/c... PS7, Line 41: CB_CBFS_HASH
I would add some word to this to make its meaning a bit clearer, how about `CB_CBFS_HASH_CHECK_FAIL` […]
I prefer to avoid words like "fail" or "error" in error codes because the fact that it's an error code already makes that clear. This is similar in philosophy to POSIX errno (e.g. it's EACCES and EIO, not EACCESSDENIED and EIOERROR). But I could settle for CB_CBFS_HASH_MISMATCH if you like.
Angel Pons has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/38421 )
Change subject: commonlib/bsd: Add new CBFS core implementation ......................................................................
Patch Set 7:
(1 comment)
https://review.coreboot.org/c/coreboot/+/38421/7/src/commonlib/bsd/include/c... File src/commonlib/bsd/include/commonlib/bsd/cb_err.h:
https://review.coreboot.org/c/coreboot/+/38421/7/src/commonlib/bsd/include/c... PS7, Line 41: CB_CBFS_HASH
I prefer to avoid words like "fail" or "error" in error codes because the fact that it's an error co […]
I understand your reasons. And yes, `CB_CBFS_HASH_MISMATCH` is great, thanks for coming up with it 😄
Nico Huber has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/38421 )
Change subject: commonlib/bsd: Add new CBFS core implementation ......................................................................
Patch Set 7: Code-Review+1
Hello build bot (Jenkins), Nico Huber, Angel Pons, Aaron Durbin,
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/coreboot/+/38421
to look at the new patch set (#8).
Change subject: commonlib/bsd: Add new CBFS core implementation ......................................................................
commonlib/bsd: Add new CBFS core implementation
This patch adds a new CBFS implementation that is intended to replace the existing commonlib/cbfs.c. The new implementation is designed to meet a bunch of current and future goals that in aggregate make it easier to start from scratch than to adapt the exisiting implementation:
1. Be BSD-licensed so it can evetually be shared with libpayload. 2. Allow generating/verifying a master hash for future CBFS per-file verification (see [1][2]). 3. Be very careful about reading (not mmaping) all data only once, to be suitable for eventual TOCTOU-safe verification. 4. Make it possibly to efficiently implement all current and future firmware use cases (both with and without verification).
The main primitive is the cbfs_walk() function which will traverse a CBFS and call a callback for every file. cbfs_lookup() uses this to implement the most common use case of finding a file so that it can be read. A host application using this code (e.g. coreboot, libpayload, cbfstool) will need to provide a <cbfs_glue.h> header to provide the glue to access the respective CBFS storage backend implementation.
This patch merely adds the code, the next patch will integrate it into coreboot.
[1]: https://www.youtube.com/watch?v=Hs_EhewBgtM [2]: https://osfc.io/uploads/talk/paper/47/The_future_of_firmware_verification_in...
Change-Id: Ica64c1751fa37686814c0247460c399261d5814c Signed-off-by: Julius Werner jwerner@chromium.org --- M MAINTAINERS A src/commonlib/bsd/cbfs_private.c M src/commonlib/bsd/include/commonlib/bsd/cb_err.h A src/commonlib/bsd/include/commonlib/bsd/cbfs_private.h M src/commonlib/bsd/include/commonlib/bsd/cbfs_serialized.h 5 files changed, 269 insertions(+), 5 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/21/38421/8
build bot (Jenkins) has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/38421 )
Change subject: commonlib/bsd: Add new CBFS core implementation ......................................................................
Patch Set 8:
(1 comment)
https://review.coreboot.org/c/coreboot/+/38421/8/src/commonlib/bsd/cbfs_priv... File src/commonlib/bsd/cbfs_private.c:
https://review.coreboot.org/c/coreboot/+/38421/8/src/commonlib/bsd/cbfs_priv... PS8, Line 35: if (do_hash && (vbrv = vb2_digest_init(&dc, master_hash->algo))) { do not use assignment in if condition
Julius Werner has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/38421 )
Change subject: commonlib/bsd: Add new CBFS core implementation ......................................................................
Patch Set 8:
(1 comment)
https://review.coreboot.org/c/coreboot/+/38421/7/src/commonlib/bsd/include/c... File src/commonlib/bsd/include/commonlib/bsd/cb_err.h:
https://review.coreboot.org/c/coreboot/+/38421/7/src/commonlib/bsd/include/c... PS7, Line 41: CB_CBFS_HASH
I understand your reasons. […]
Done
Angel Pons has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/38421 )
Change subject: commonlib/bsd: Add new CBFS core implementation ......................................................................
Patch Set 8: Code-Review+1
Patrick Rudolph has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/38421 )
Change subject: commonlib/bsd: Add new CBFS core implementation ......................................................................
Patch Set 8: Code-Review+1
(1 comment)
Seems to implement what is specified in the referenced documents.
https://review.coreboot.org/c/coreboot/+/38421/8/src/commonlib/bsd/cbfs_priv... File src/commonlib/bsd/cbfs_private.c:
https://review.coreboot.org/c/coreboot/+/38421/8/src/commonlib/bsd/cbfs_priv... PS8, Line 44: while ((ret_header = read_next_header(dev, &offset, &mdata.h)) == CB_SUCCESS) { isn't that the same as "do not use assignment in if condition"?
Philipp Deppenwiese has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/38421 )
Change subject: commonlib/bsd: Add new CBFS core implementation ......................................................................
Patch Set 8:
If we go that far we really should think about merging vboot into coreboot
Julius Werner has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/38421 )
Change subject: commonlib/bsd: Add new CBFS core implementation ......................................................................
Patch Set 8:
(1 comment)
https://review.coreboot.org/c/coreboot/+/38421/8/src/commonlib/bsd/cbfs_priv... File src/commonlib/bsd/cbfs_private.c:
https://review.coreboot.org/c/coreboot/+/38421/8/src/commonlib/bsd/cbfs_priv... PS8, Line 44: while ((ret_header = read_next_header(dev, &offset, &mdata.h)) == CB_SUCCESS) {
isn't that the same as "do not use assignment in if condition"?
Who knows what it does...
FWIW, I'm not planning to fix any of these unless anyone really wants me to. This is just checkpatch stuff that was written for Linux, I'm not aware that that the coreboot style forbids these explicitly, and I think in the few places I use them they enhance readability (e.g. you couldn't really write this while-loop otherwise, you'd have to work around it by calling read_next_header() in multiple places instead and it would just make it way harder to understand the fundamental flow here).
Angel Pons has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/38421 )
Change subject: commonlib/bsd: Add new CBFS core implementation ......................................................................
Patch Set 8:
(4 comments)
https://review.coreboot.org/c/coreboot/+/38421/8/src/commonlib/bsd/cbfs_priv... File src/commonlib/bsd/cbfs_private.c:
https://review.coreboot.org/c/coreboot/+/38421/8/src/commonlib/bsd/cbfs_priv... PS8, Line 8: size_t devsize Maybe constify this?
https://review.coreboot.org/c/coreboot/+/38421/8/src/commonlib/bsd/cbfs_priv... PS8, Line 30: bool do_hash Maybe constify this?
https://review.coreboot.org/c/coreboot/+/38421/8/src/commonlib/bsd/cbfs_priv... PS8, Line 44: while ((ret_header = read_next_header(dev, &offset, &mdata.h)) == CB_SUCCESS) {
Who knows what it does... […]
In the case above, fixing it would result in two nested if's, and it would bring the line length past 96 characters. So I wouldn't touch it 😄
I think checkpatch only complains on instances inside if statements. It does not seem to complain on loops, maybe because it does makes sense to use such a construct for loops.
https://review.coreboot.org/c/coreboot/+/38421/8/src/commonlib/bsd/include/c... File src/commonlib/bsd/include/commonlib/bsd/cbfs_serialized.h:
https://review.coreboot.org/c/coreboot/+/38421/8/src/commonlib/bsd/include/c... PS8, Line 127: /* Actual size in CBFS may be larger/smaller than struct size! */ Silly question: what does this mean?
Julius Werner has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/38421 )
Change subject: commonlib/bsd: Add new CBFS core implementation ......................................................................
Patch Set 8:
(1 comment)
https://review.coreboot.org/c/coreboot/+/38421/8/src/commonlib/bsd/include/c... File src/commonlib/bsd/include/commonlib/bsd/cbfs_serialized.h:
https://review.coreboot.org/c/coreboot/+/38421/8/src/commonlib/bsd/include/c... PS8, Line 127: /* Actual size in CBFS may be larger/smaller than struct size! */
Silly question: what does this mean?
The size of the attribute on flash is variable, and it always has been (it's 12 + <size of the hash>). Previously, hash_data was a zero-length array so sizeof(struct cbfs_file_attr_hash) could be used to conveniently get the size of the attribute header (12) and then you only had to add the size of the hash to that. With this change, that no longer works because the size of struct vb2_hash is larger (however, it is not necessarily equal to the full size of the attribute either). So, basically, you shouldn't use sizeof(struct cbfs_file_attr_hash) for anything, that's why I put that comment there.
This attribute is currently only read by cbfstool which has its own copy of the definition. When I update that to use this file, I'll make sure I deal with this issue appropriately.
Hello build bot (Jenkins), Nico Huber, Patrick Georgi, Patrick Rudolph, Angel Pons, Aaron Durbin,
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/coreboot/+/38421
to look at the new patch set (#9).
Change subject: commonlib/bsd: Add new CBFS core implementation ......................................................................
commonlib/bsd: Add new CBFS core implementation
This patch adds a new CBFS implementation that is intended to replace the existing commonlib/cbfs.c. The new implementation is designed to meet a bunch of current and future goals that in aggregate make it easier to start from scratch than to adapt the exisiting implementation:
1. Be BSD-licensed so it can evetually be shared with libpayload. 2. Allow generating/verifying a master hash for future CBFS per-file verification (see [1][2]). 3. Be very careful about reading (not mmaping) all data only once, to be suitable for eventual TOCTOU-safe verification. 4. Make it possibly to efficiently implement all current and future firmware use cases (both with and without verification).
The main primitive is the cbfs_walk() function which will traverse a CBFS and call a callback for every file. cbfs_lookup() uses this to implement the most common use case of finding a file so that it can be read. A host application using this code (e.g. coreboot, libpayload, cbfstool) will need to provide a <cbfs_glue.h> header to provide the glue to access the respective CBFS storage backend implementation.
This patch merely adds the code, the next patch will integrate it into coreboot.
[1]: https://www.youtube.com/watch?v=Hs_EhewBgtM [2]: https://osfc.io/uploads/talk/paper/47/The_future_of_firmware_verification_in...
Change-Id: Ica64c1751fa37686814c0247460c399261d5814c Signed-off-by: Julius Werner jwerner@chromium.org --- M MAINTAINERS A src/commonlib/bsd/cbfs_private.c M src/commonlib/bsd/include/commonlib/bsd/cb_err.h A src/commonlib/bsd/include/commonlib/bsd/cbfs_private.h M src/commonlib/bsd/include/commonlib/bsd/cbfs_serialized.h 5 files changed, 270 insertions(+), 5 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/21/38421/9
build bot (Jenkins) has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/38421 )
Change subject: commonlib/bsd: Add new CBFS core implementation ......................................................................
Patch Set 9:
(1 comment)
https://review.coreboot.org/c/coreboot/+/38421/9/src/commonlib/bsd/cbfs_priv... File src/commonlib/bsd/cbfs_private.c:
https://review.coreboot.org/c/coreboot/+/38421/9/src/commonlib/bsd/cbfs_priv... PS9, Line 35: if (do_hash && (vbrv = vb2_digest_init(&dc, master_hash->algo))) { do not use assignment in if condition
build bot (Jenkins) has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/38421 )
Change subject: commonlib/bsd: Add new CBFS core implementation ......................................................................
Patch Set 10:
(1 comment)
https://review.coreboot.org/c/coreboot/+/38421/10/src/commonlib/bsd/cbfs_pri... File src/commonlib/bsd/cbfs_private.c:
https://review.coreboot.org/c/coreboot/+/38421/10/src/commonlib/bsd/cbfs_pri... PS10, Line 35: if (do_hash && (vbrv = vb2_digest_init(&dc, master_hash->algo))) { do not use assignment in if condition
build bot (Jenkins) has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/38421 )
Change subject: commonlib/bsd: Add new CBFS core implementation ......................................................................
Patch Set 11:
(1 comment)
https://review.coreboot.org/c/coreboot/+/38421/11/src/commonlib/bsd/cbfs_pri... File src/commonlib/bsd/cbfs_private.c:
https://review.coreboot.org/c/coreboot/+/38421/11/src/commonlib/bsd/cbfs_pri... PS11, Line 35: if (do_hash && (vbrv = vb2_digest_init(&dc, master_hash->algo))) { do not use assignment in if condition
Aaron Durbin has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/38421 )
Change subject: commonlib/bsd: Add new CBFS core implementation ......................................................................
Patch Set 11:
(15 comments)
https://review.coreboot.org/c/coreboot/+/38421/11//COMMIT_MSG Commit Message:
https://review.coreboot.org/c/coreboot/+/38421/11//COMMIT_MSG@19 PS11, Line 19: y e
https://review.coreboot.org/c/coreboot/+/38421/11/src/commonlib/bsd/cbfs_pri... File src/commonlib/bsd/cbfs_private.c:
https://review.coreboot.org/c/coreboot/+/38421/11/src/commonlib/bsd/cbfs_pri... PS11, Line 8: size_t devsize = cbfs_dev_size(dev); Maybe not terrible, but I think you should call this in cbfs_walk() and pass the value to this function. Otherwise, we'll be doing the size lookup for every file.
https://review.coreboot.org/c/coreboot/+/38421/11/src/commonlib/bsd/cbfs_pri... PS11, Line 52: be32toh(mdata.h.type) You already have local variable, 'type', for this.
https://review.coreboot.org/c/coreboot/+/38421/11/src/commonlib/bsd/cbfs_pri... PS11, Line 70: goto next_file; I can see where this might be the correct action for certain circumstances. Wouldn't we want to this to be fatal in others?
https://review.coreboot.org/c/coreboot/+/38421/11/src/commonlib/bsd/cbfs_pri... PS11, Line 75: offset + sizeof(mdata.h), todo) != todo) I have a comment below related to this as well, but I don't see how we're guaranteed the mdata has enough buffer.
https://review.coreboot.org/c/coreboot/+/38421/11/src/commonlib/bsd/cbfs_pri... PS11, Line 117: const size_t todo = be32toh(src->h.offset) - already_read; How do we know that: 1. cbfs_mdata is sufficiently large? 2. src->h.offset is >= already_read?
For the 2nd, I think we're relying on cbfs_walk() implementation to be the only sequence one would call copy_fill_metadata?
https://review.coreboot.org/c/coreboot/+/38421/11/src/commonlib/bsd/cbfs_pri... PS11, Line 135: args->namesize > already_read - offsetof(union cbfs_mdata, filename) Separate this out into its own condition with a comment? It seems this check doesn't concern itself with the attributes -- only the filename. I'm not understanding the logic. And the || below then assumes we can read into filename when it's not entirely clear. Were you intending || to be &&?
https://review.coreboot.org/c/coreboot/+/38421/11/src/commonlib/bsd/cbfs_pri... PS11, Line 136: memcmp(args->name, mdata->filename, args->namesize) != 0) We aren't ensuring filename (and CBFS_METADATA_MAX_SIZE coverage) is not being exceeded for out of bounds accesses.
https://review.coreboot.org/c/coreboot/+/38421/11/src/commonlib/bsd/include/... File src/commonlib/bsd/include/commonlib/bsd/cbfs_private.h:
https://review.coreboot.org/c/coreboot/+/38421/11/src/commonlib/bsd/include/... PS11, Line 4: PRIVATE What is the intention of private? Only a predetermined set of users should call these functions?
https://review.coreboot.org/c/coreboot/+/38421/11/src/commonlib/bsd/include/... PS11, Line 14: This Perhaps call out the name (cbfs_glue.h) since this comment is large and it makes it clear what 'this' is referring to?
https://review.coreboot.org/c/coreboot/+/38421/11/src/commonlib/bsd/include/... PS11, Line 18: * CBFS_ENABLE_HASHING Should be 0 to avoid linking hashing features, 1 otherwise. I think this should be more explicit as to what hashing is covered. It's just the metadata.
https://review.coreboot.org/c/coreboot/+/38421/11/src/commonlib/bsd/include/... PS11, Line 49: empty entries What exactly does this mean? cbfs_file w/ no data, only metadata?
https://review.coreboot.org/c/coreboot/+/38421/11/src/commonlib/bsd/include/... PS11, Line 82: enum cbfs_walk_flags Since this is a bit field shouldn't we be passing in an unsigned type for the flags? Those flags are not mutually exclusive.
https://review.coreboot.org/c/coreboot/+/38421/11/src/commonlib/bsd/include/... PS11, Line 87: * |dst| and load remaining metadata from |dev| as required. I know we say copy here, but I think we should note that the fields are still in serialized format, i.e. big endian. I guess we should note the same is true everywhere w.r.t. this API. All cbfs_mdata is in serialized form?
https://review.coreboot.org/c/coreboot/+/38421/11/src/commonlib/bsd/include/... PS11, Line 94: Verify the metadata with |master_hash| if provided. From this description it's not clear what master_hash is representing for the target file. If it's truly the master hash for the entirety of cbfs metadata that would imply a full read of cbfs metadata to perform the calculation.
Also, if this is about verification why isn't master_hash object marked const?
Angel Pons has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/38421 )
Change subject: commonlib/bsd: Add new CBFS core implementation ......................................................................
Patch Set 11:
(1 comment)
https://review.coreboot.org/c/coreboot/+/38421/11/src/commonlib/bsd/include/... File src/commonlib/bsd/include/commonlib/bsd/cbfs_private.h:
https://review.coreboot.org/c/coreboot/+/38421/11/src/commonlib/bsd/include/... PS11, Line 4: PRIVATE
What is the intention of private? Only a predetermined set of users should call these functions?
Or are these considered to be implementation details?
Hello build bot (Jenkins), Nico Huber, Patrick Georgi, Patrick Rudolph, Angel Pons, Aaron Durbin, HAOUAS Elyes,
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/coreboot/+/38421
to look at the new patch set (#12).
Change subject: commonlib/bsd: Add new CBFS core implementation ......................................................................
commonlib/bsd: Add new CBFS core implementation
This patch adds a new CBFS implementation that is intended to replace the existing commonlib/cbfs.c. The new implementation is designed to meet a bunch of current and future goals that in aggregate make it easier to start from scratch than to adapt the exisiting implementation:
1. Be BSD-licensed so it can evetually be shared with libpayload. 2. Allow generating/verifying a metadata hash for future CBFS per-file verification (see [1][2]). 3. Be very careful about reading (not mmaping) all data only once, to be suitable for eventual TOCTOU-safe verification. 4. Make it possible to efficiently implement all current and future firmware use cases (both with and without verification).
The main primitive is the cbfs_walk() function which will traverse a CBFS and call a callback for every file. cbfs_lookup() uses this to implement the most common use case of finding a file so that it can be read. A host application using this code (e.g. coreboot, libpayload, cbfstool) will need to provide a <cbfs_glue.h> header to provide the glue to access the respective CBFS storage backend implementation.
This patch merely adds the code, the next patch will integrate it into coreboot.
[1]: https://www.youtube.com/watch?v=Hs_EhewBgtM [2]: https://osfc.io/uploads/talk/paper/47/The_future_of_firmware_verification_in... (Note: In early discussions the metadata hash was called "master hash".)
Change-Id: Ica64c1751fa37686814c0247460c399261d5814c Signed-off-by: Julius Werner jwerner@chromium.org --- M MAINTAINERS A src/commonlib/bsd/cbfs_private.c M src/commonlib/bsd/include/commonlib/bsd/cb_err.h A src/commonlib/bsd/include/commonlib/bsd/cbfs_private.h M src/commonlib/bsd/include/commonlib/bsd/cbfs_serialized.h 5 files changed, 280 insertions(+), 5 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/21/38421/12
build bot (Jenkins) has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/38421 )
Change subject: commonlib/bsd: Add new CBFS core implementation ......................................................................
Patch Set 12:
(1 comment)
https://review.coreboot.org/c/coreboot/+/38421/12/src/commonlib/bsd/cbfs_pri... File src/commonlib/bsd/cbfs_private.c:
https://review.coreboot.org/c/coreboot/+/38421/12/src/commonlib/bsd/cbfs_pri... PS12, Line 35: if (do_hash && (vbrv = vb2_digest_init(&dc, metadata_hash->algo))) { do not use assignment in if condition
Julius Werner has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/38421 )
Change subject: commonlib/bsd: Add new CBFS core implementation ......................................................................
Patch Set 12:
(15 comments)
https://review.coreboot.org/c/coreboot/+/38421/11//COMMIT_MSG Commit Message:
https://review.coreboot.org/c/coreboot/+/38421/11//COMMIT_MSG@19 PS11, Line 19: y
e
Done
https://review.coreboot.org/c/coreboot/+/38421/11/src/commonlib/bsd/cbfs_pri... File src/commonlib/bsd/cbfs_private.c:
https://review.coreboot.org/c/coreboot/+/38421/11/src/commonlib/bsd/cbfs_pri... PS11, Line 8: size_t devsize = cbfs_dev_size(dev);
Maybe not terrible, but I think you should call this in cbfs_walk() and pass the value to this funct […]
It doesn't, actually, both cbfs_dev_size() and everything called by it are static inlines, so the compiler can fold the whole thing (including this function) and should be able to hoist it out of the loop if that's an improvement.
https://review.coreboot.org/c/coreboot/+/38421/11/src/commonlib/bsd/cbfs_pri... PS11, Line 52: be32toh(mdata.h.type)
You already have local variable, 'type', for this.
Done
https://review.coreboot.org/c/coreboot/+/38421/11/src/commonlib/bsd/cbfs_pri... PS11, Line 70: goto next_file;
I can see where this might be the correct action for certain circumstances. […]
I'm just trying to continue as far as possible here. I think that's probably the best philosophy for the classic, basic coreboot user who has no recovery mode and might accidentally incur some flash corruption somehow. Of course the chance that this particular check fails but the rest is good enough to boot is still tiny, so it doesn't really matter much either way.
Note that when hashing is enabled, this skips the digest_extend() for this file header which guarantees it will result in a hash failure at the end.
https://review.coreboot.org/c/coreboot/+/38421/11/src/commonlib/bsd/cbfs_pri... PS11, Line 75: offset + sizeof(mdata.h), todo) != todo)
I have a comment below related to this as well, but I don't see how we're guaranteed the mdata has e […]
Line 53 guarantees sizeof(mdata) >= data_offset
Then either:
Line 65 makes todo = data_offset - sizeof(mdata.h), or
Line 67 makes todo = attr_offset - sizeof(mdata.h) and line 68 guarantees attr_offset <= data_offset
Therefore todo <= data_offset - sizeof(mdata.h), which means we know we can fit todo bytes behind mdata.raw + sizeof(mdata.h).
https://review.coreboot.org/c/coreboot/+/38421/11/src/commonlib/bsd/cbfs_pri... PS11, Line 117: const size_t todo = be32toh(src->h.offset) - already_read;
How do we know that: […]
cbfs_copy_fill_metadata() is only meant to be called from a |walker| callback to cbfs_walk(), where |src| and |already_read| must be the same that cbfs_walk() passed to |walker| (see docstrings in cbfs_private.h... let me know if you think something needs to be more explicit). So already_read is (sizeof(mdata.h) + todo) from cbfs_walk(), and cbfs_walk() guarantees that (todo <= data_offset - sizeof(mdata.h)) (see above) and that data_offset <= sizeof(union cbfs_mdata). data_offset in cbfs_walk() is be32toh(src->h.offset) here.
https://review.coreboot.org/c/coreboot/+/38421/11/src/commonlib/bsd/cbfs_pri... PS11, Line 135: args->namesize > already_read - offsetof(union cbfs_mdata, filename)
Separate this out into its own condition with a comment? It seems this check doesn't concern itself […]
No, both of these checks together form the filename check. |already_read| is the amount of valid bytes in |mdata| (and we know that this should include the full filename for a well-formed CBFS header), so
args->namesize > already_read - offsetof(union cbfs_mdata, filename)
checks if the name we're looking for is so large that it doesn't even fit in the header we have -- in that case we can fastpath out to NOT_FOUND. If it does fit, we can do
memcmp(args->name, mdata->filename, args->namesize)
to check if the name actually matches. We know that there's args->namesize bytes in args->name because that's where that number comes from, and we know that there's that many bytes in mdata->filename because that's what the first check was about. So we cannot run over the end of a buffer. We _can_ technically run over the filename in the CBFS header and into the attribute part (if that's part of |already_read|), but I don't think that's a problem... if the filename is malformed (not null-terminated) the header is garbage anyway, then attr_offset might have been garbage too.
Added a comment to clarify what this is checking and why.
https://review.coreboot.org/c/coreboot/+/38421/11/src/commonlib/bsd/cbfs_pri... PS11, Line 136: memcmp(args->name, mdata->filename, args->namesize) != 0)
We aren't ensuring filename (and CBFS_METADATA_MAX_SIZE coverage) is not being exceeded for out of b […]
See above.
https://review.coreboot.org/c/coreboot/+/38421/11/src/commonlib/bsd/include/... File src/commonlib/bsd/include/commonlib/bsd/cbfs_private.h:
https://review.coreboot.org/c/coreboot/+/38421/11/src/commonlib/bsd/include/... PS11, Line 4: PRIVATE
Or are these considered to be implementation details?
It's supposed to be APIs private to the CBFS stack that shouldn't be called directly by any other parts of coreboot. I could also call it <cbfs_internal.h> or maybe <cbfs_unsafe.h> if you prefer?
The core issue here is how to make sure people don't accidentally break verification by using APIs in a way they weren't intended. The per-file verification approach absolutely requires that every file accessed (whether it's a stage, an SPD blob, an FSP image, etc.) is actually hashed and verified, or your whole verification system could be insecure because of one small mistake buried deep in src/soc/xxx code. I'm really trying to come up with the best way to design the code so that this can't happen by accident.
The basic idea is that all other coreboot code accessing CBFS will call high level functions like cbfs_read() or cbfs_map() (see later patches) which are implemented in src/lib/cbfs.c and will automatically hash and verify the file contents if CONFIG(CBFS_VERIFICATION) is on. src/lib/cbfs.c should be the only file that actually includes <cbfs_private.h> and calls the low-level APIs implemented here. That way we only have to monitor and carefully review changes to one file.
I haven't finished porting all use cases to the new API yet so I'm not sure how ultimately feasible this will be, but that's the rough goal. Some of them will definitely be tricky (e.g. that idea of streaming decompression for pre-RAM EC updates) so I'll have to come up with new high-level APIs to properly encapsulate something like that. Of course, the other issue is that there's no easy way to prevent someone from including the low-level header anyway. I've thought about maybe also adding something like
#if CONFIG(CBFS_VERIFICATION) && !defined(THIS_FILE_WAS_SECURITY_REVIEWED_FOR_DIRECT_LOW_LEVEL_CBFS_ACCESS) #error "Please don't access low-level CBFS APIs directly." #endif
so that there's at least one extra conscious step you need to take when including this to clarify that you're really aware of the risks involved. I've also considered creating another Kconfig like CONFIG(CBFS_VERIFICATION_STRICT) to block certain APIs and/or enable the extra check above, so it wouldn't stop everyone from playing with CBFS stuff but it would alert extra paranoid users (like us) that some dangerous API use might have not been fully reviewed.
I'm not really sure what the best answers here are yet, let me know what you think!
https://review.coreboot.org/c/coreboot/+/38421/11/src/commonlib/bsd/include/... PS11, Line 14: This
Perhaps call out the name (cbfs_glue. […]
Done
https://review.coreboot.org/c/coreboot/+/38421/11/src/commonlib/bsd/include/... PS11, Line 18: * CBFS_ENABLE_HASHING Should be 0 to avoid linking hashing features, 1 otherwise.
I think this should be more explicit as to what hashing is covered. It's just the metadata.
Done. (This is just about how the code can be statically configured anyway, the exact explanation of when what is hashed is in the docstrings for cbfs_walk()/cbfs_lookup() below.)
https://review.coreboot.org/c/coreboot/+/38421/11/src/commonlib/bsd/include/... PS11, Line 49: empty entries
What exactly does this mean? cbfs_file w/ no data, only metadata?
It's about entries with the DELETED type (i.e. free space). Clarified comment.
https://review.coreboot.org/c/coreboot/+/38421/11/src/commonlib/bsd/include/... PS11, Line 82: enum cbfs_walk_flags
Since this is a bit field shouldn't we be passing in an unsigned type for the flags? Those flags are […]
Is it illegal / frowned upon to use an enum type for values that are ORed together from valid enum values? I wasn't aware. I think using the enum type serves as a little extra self-documentation, but I can make it unsigned int if you prefer. (Note that GCC always makes enum types that don't have negative members unsigned, so I don't think there could be a signedness concern.)
https://review.coreboot.org/c/coreboot/+/38421/11/src/commonlib/bsd/include/... PS11, Line 87: * |dst| and load remaining metadata from |dev| as required.
I know we say copy here, but I think we should note that the fields are still in serialized format, […]
Yes... I've thought about this for a bit and my take is that it's less confusing to just always leave the data big endian while it's in the header struct. If you try to rewrite the header in memory to convert stuff to CPU byte order I think you just risk introducing a ton of confusion about at what point it's still big-endian and when it isn't. It's easier to say "everything in a union cbfs_mdata is always big-endian".
I've added a comment to the structure definition above to clarify.
https://review.coreboot.org/c/coreboot/+/38421/11/src/commonlib/bsd/include/... PS11, Line 94: Verify the metadata with |master_hash| if provided.
From this description it's not clear what master_hash is representing for the target file. […]
Yes, I always use the term "master hash" only for the hash over the metadata of the whole CBFS (the others are "file hashes"... don't have much code related to them yet). With the whole inclusive language thing I wanted to rename it everywhere to metadata_hash anyway, that should be a bit clearer too. (And yes, when master_hash is provided it always needs to read the full metadata for every lookup, that's a core constraint of this design.)
The reason it's not const is just API weirdness, basically. The master_hash argument to cbfs_walk() cannot be const because if CBFS_WALK_WRITEBACK_HASH is set it will get modified. So since cbfs_lookup() calls cbfs_walk() it was easiest to not make it const here as well. I could also make it const here and then cast the const away inside the function if you prefer?
Angel Pons has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/38421 )
Change subject: commonlib/bsd: Add new CBFS core implementation ......................................................................
Patch Set 12: Code-Review+1
(3 comments)
https://review.coreboot.org/c/coreboot/+/38421/11/src/commonlib/bsd/include/... File src/commonlib/bsd/include/commonlib/bsd/cbfs_private.h:
https://review.coreboot.org/c/coreboot/+/38421/11/src/commonlib/bsd/include/... PS11, Line 4: PRIVATE
It's supposed to be APIs private to the CBFS stack that shouldn't be called directly by any other pa […]
Thanks for the explanation. This sounds good, but please make sure to write a page in documentation to point people at.
https://review.coreboot.org/c/coreboot/+/38421/11/src/commonlib/bsd/include/... PS11, Line 82: enum cbfs_walk_flags
Is it illegal / frowned upon to use an enum type for values that are ORed together from valid enum v […]
I much prefer using an enum over a plain unsigned int. Another option would be to use a struct with custom storage sizes, but I don't know if that would be too cursed.
https://review.coreboot.org/c/coreboot/+/38421/11/src/commonlib/bsd/include/... PS11, Line 94: Verify the metadata with |master_hash| if provided.
Yes, I always use the term "master hash" only for the hash over the metadata of the whole CBFS (the […]
Discarding a const qualifier is a very bad idea, IMHO.
Aaron Durbin has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/38421 )
Change subject: commonlib/bsd: Add new CBFS core implementation ......................................................................
Patch Set 12:
(4 comments)
https://review.coreboot.org/c/coreboot/+/38421/11/src/commonlib/bsd/cbfs_pri... File src/commonlib/bsd/cbfs_private.c:
https://review.coreboot.org/c/coreboot/+/38421/11/src/commonlib/bsd/cbfs_pri... PS11, Line 75: offset + sizeof(mdata.h), todo) != todo)
Line 53 guarantees sizeof(mdata) >= data_offset
Should line 55 return an error then instead of continuing? I am concerned about silently missing the assumption that data_offset will always be <= sizeof(mdata).
https://review.coreboot.org/c/coreboot/+/38421/11/src/commonlib/bsd/include/... File src/commonlib/bsd/include/commonlib/bsd/cbfs_private.h:
https://review.coreboot.org/c/coreboot/+/38421/11/src/commonlib/bsd/include/... PS11, Line 4: PRIVATE
Thanks for the explanation. […]
I think having a comment about intention that you provided above, Julius, would be helpful. Obviously it doesn't need to be as long as what wrote, but explain the intention. That way we can point people at it if we see violations of the original intent.
https://review.coreboot.org/c/coreboot/+/38421/11/src/commonlib/bsd/include/... PS11, Line 82: enum cbfs_walk_flags
I much prefer using an enum over a plain unsigned int. […]
It is helpful to provide that extra hint, but an enum tells me that it's a single value of that enumeration -- not a combination of values from the enumeration. I guess I'm in the minority on that, but enum doesn't scream combination of flags.
https://review.coreboot.org/c/coreboot/+/38421/11/src/commonlib/bsd/include/... PS11, Line 94: Verify the metadata with |master_hash| if provided.
Discarding a const qualifier is a very bad idea, IMHO.
Ya. I wouldn't cast off the const.
Hello build bot (Jenkins), Nico Huber, Patrick Georgi, Patrick Rudolph, Angel Pons, Aaron Durbin, HAOUAS Elyes,
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/coreboot/+/38421
to look at the new patch set (#13).
Change subject: commonlib/bsd: Add new CBFS core implementation ......................................................................
commonlib/bsd: Add new CBFS core implementation
This patch adds a new CBFS implementation that is intended to replace the existing commonlib/cbfs.c. The new implementation is designed to meet a bunch of current and future goals that in aggregate make it easier to start from scratch than to adapt the exisiting implementation:
1. Be BSD-licensed so it can evetually be shared with libpayload. 2. Allow generating/verifying a metadata hash for future CBFS per-file verification (see [1][2]). 3. Be very careful about reading (not mmaping) all data only once, to be suitable for eventual TOCTOU-safe verification. 4. Make it possible to efficiently implement all current and future firmware use cases (both with and without verification).
The main primitive is the cbfs_walk() function which will traverse a CBFS and call a callback for every file. cbfs_lookup() uses this to implement the most common use case of finding a file so that it can be read. A host application using this code (e.g. coreboot, libpayload, cbfstool) will need to provide a <cbfs_glue.h> header to provide the glue to access the respective CBFS storage backend implementation.
This patch merely adds the code, the next patch will integrate it into coreboot.
[1]: https://www.youtube.com/watch?v=Hs_EhewBgtM [2]: https://osfc.io/uploads/talk/paper/47/The_future_of_firmware_verification_in... (Note: In early discussions the metadata hash was called "master hash".)
Change-Id: Ica64c1751fa37686814c0247460c399261d5814c Signed-off-by: Julius Werner jwerner@chromium.org --- M MAINTAINERS A src/commonlib/bsd/cbfs_private.c M src/commonlib/bsd/include/commonlib/bsd/cb_err.h A src/commonlib/bsd/include/commonlib/bsd/cbfs_private.h M src/commonlib/bsd/include/commonlib/bsd/cbfs_serialized.h 5 files changed, 290 insertions(+), 5 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/21/38421/13
build bot (Jenkins) has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/38421 )
Change subject: commonlib/bsd: Add new CBFS core implementation ......................................................................
Patch Set 13:
(1 comment)
https://review.coreboot.org/c/coreboot/+/38421/13/src/commonlib/bsd/cbfs_pri... File src/commonlib/bsd/cbfs_private.c:
https://review.coreboot.org/c/coreboot/+/38421/13/src/commonlib/bsd/cbfs_pri... PS13, Line 35: if (do_hash && (vbrv = vb2_digest_init(&dc, metadata_hash->algo))) { do not use assignment in if condition
Julius Werner has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/38421 )
Change subject: commonlib/bsd: Add new CBFS core implementation ......................................................................
Patch Set 13:
(2 comments)
https://review.coreboot.org/c/coreboot/+/38421/11/src/commonlib/bsd/cbfs_pri... File src/commonlib/bsd/cbfs_private.c:
https://review.coreboot.org/c/coreboot/+/38421/11/src/commonlib/bsd/cbfs_pri... PS11, Line 75: offset + sizeof(mdata.h), todo) != todo)
Line 53 guarantees sizeof(mdata) >= data_offset […]
Well, again, I'm trying to go for the general concept of "continue as far as possible". This one in particular would help a bit in the odd chance that someone uses an old version of cbfstool to add some file with more than 256 bytes metadata that's needed by their payload.
The line prevents any of the code that further parses that file entry from running, so I think it still serves the purpose of guaranteeing that invariant across the rest of this CBFS stack? I don't think it makes a difference for safety there if we abort or just go on searching at the next file entry.
https://review.coreboot.org/c/coreboot/+/38421/11/src/commonlib/bsd/include/... File src/commonlib/bsd/include/commonlib/bsd/cbfs_private.h:
https://review.coreboot.org/c/coreboot/+/38421/11/src/commonlib/bsd/include/... PS11, Line 4: PRIVATE
I think having a comment about intention that you provided above, Julius, would be helpful. […]
Sounds good, added comment. (Note that CB:39327 also adds src/include/cbfs_private.h for the coreboot-specific parts of the "unsafe" API. I think I'll need direct access to some of that for program loading so I can't have it all local in lib/cbfs.c. I also have a warning comment there, I may flesh it out a bit more once I have all the use cases implemented and a better idea what APIs need to be exposed for what.)
I agree with Angel that this should also have a page in Documentation/ later, but since I don't have all the answers yet I'd say I'll finish writing the code first, and then document it later when all the design decisions are final.
Angel Pons has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/38421 )
Change subject: commonlib/bsd: Add new CBFS core implementation ......................................................................
Patch Set 13:
(1 comment)
https://review.coreboot.org/c/coreboot/+/38421/11/src/commonlib/bsd/include/... File src/commonlib/bsd/include/commonlib/bsd/cbfs_private.h:
https://review.coreboot.org/c/coreboot/+/38421/11/src/commonlib/bsd/include/... PS11, Line 4: PRIVATE
Sounds good, added comment. (Note that CB:39327 also adds src/include/cbfs_private.h for the coreboot-specific parts of the "unsafe" API. I think I'll need direct access to some of that for program loading so I can't have it all local in lib/cbfs.c. I also have a warning comment there, I may flesh it out a bit more once I have all the use cases implemented and a better idea what APIs need to be exposed for what.)
I agree with Angel that this should also have a page in Documentation/ later, but since I don't have all the answers yet I'd say I'll finish writing the code first, and then document it later when all the design decisions are final.
I read this and just thought of something: how about writing the documentation first, and use it to discuss the design decisions? It might be less work than to redesign the code later should any of the decisions not be accepted (which I expect to be unlikely, but not impossible).
Aaron Durbin has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/38421 )
Change subject: commonlib/bsd: Add new CBFS core implementation ......................................................................
Patch Set 13:
(1 comment)
https://review.coreboot.org/c/coreboot/+/38421/11/src/commonlib/bsd/cbfs_pri... File src/commonlib/bsd/cbfs_private.c:
https://review.coreboot.org/c/coreboot/+/38421/11/src/commonlib/bsd/cbfs_pri... PS11, Line 75: offset + sizeof(mdata.h), todo) != todo)
Well, again, I'm trying to go for the general concept of "continue as far as possible". […]
How far does one go? And how easily can we identify such conditions early? I very much worry about relying on people to read the messages and decide something isn't working. That has not worked well in the past. I would rather we fail fast over letting things sneak by. Propagating an error up helps one apply a particular policy in an affirmative manner vs implicit behavior.
Julius Werner has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/38421 )
Change subject: commonlib/bsd: Add new CBFS core implementation ......................................................................
Patch Set 13:
(2 comments)
https://review.coreboot.org/c/coreboot/+/38421/11/src/commonlib/bsd/cbfs_pri... File src/commonlib/bsd/cbfs_private.c:
https://review.coreboot.org/c/coreboot/+/38421/11/src/commonlib/bsd/cbfs_pri... PS11, Line 75: offset + sizeof(mdata.h), todo) != todo)
How far does one go? And how easily can we identify such conditions early? I very much worry about r […]
Sorry, I'm not really following anymore here... what does reading the message have to do with anything? My code is safe, with or without the change you're asking for... it's not executing the parts that rely on the size limit if that limit is exceeded. What does it matter for safety whether it jumps away towards examining the next entry or towards returning immediately? As long as it doesn't pass the overflowing file entry back out to anywhere, I don't see the difference.
If you're worried about people not noticing that they hit that line, well... first of all, with the new version of cbfstool (https://review.coreboot.org/c/coreboot/+/41117/5/util/cbfstool/cbfs_image.c#...) it becomes impossible to create such an entry. Also, if coreboot itself is actually trying to use this stack to look up that file, it's going to fail with a CB_CBFS_NOT_FOUND (because the entry is skipped before its name can be matched). So the only way this case can be encountered but not fail hard is when that file exists in CBFS, added by an old copy of cbfstool, but isn't directly looked up by coreboot itself and metadata verification is not enabled. That probably means that the user added it themselves outside the coreboot build system to either be read by a payload (likely with an equally old CBFS implementation that could find and read this) or just serve some other informational purpose. In that case, I don't see why I should brick their whole boot when coreboot could just as well just ignore it.
Since I'm the one introducing a (tiny) backwards-incompatible change in the CBFS format here, I think it's just appropriate to try to make a best effort to not break anyone with it where possible.
https://review.coreboot.org/c/coreboot/+/38421/11/src/commonlib/bsd/include/... File src/commonlib/bsd/include/commonlib/bsd/cbfs_private.h:
https://review.coreboot.org/c/coreboot/+/38421/11/src/commonlib/bsd/include/... PS11, Line 4: PRIVATE
Sounds good, added comment. (Note that CB:39327 also adds src/include/cbfs_private. […]
Well, I have the high level design documentation (see links in the commit message), it's not like I'm going in completely blind here. It's just that some of the finer details you only really understand when you try to implement them and see where problems pop up. For example, when implementing the metadata hash generation in cbfstool I noticed that some SoC's have special header checksums for the bootblock that need to be recalculated every time, so I had to implement CB:41122. When trying to pull stage loading into the new API I realized that I can't trust the stage header before I loaded and hashed the whole file, but I can't load the whole file without info from the stage header, so I had to factor the stage header out into a CBFS attribute (patch coming soon). I tried hard to document all possible details beforehand, but you just can't think of everything... that's why I'm saying some decisions (especially about code organization) are still outstanding until I've ported every existing use case and thus know exactly what APIs we need where.
Aaron Durbin has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/38421 )
Change subject: commonlib/bsd: Add new CBFS core implementation ......................................................................
Patch Set 13:
(1 comment)
https://review.coreboot.org/c/coreboot/+/38421/11/src/commonlib/bsd/cbfs_pri... File src/commonlib/bsd/cbfs_private.c:
https://review.coreboot.org/c/coreboot/+/38421/11/src/commonlib/bsd/cbfs_pri... PS11, Line 75: offset + sizeof(mdata.h), todo) != todo)
As long as it doesn't pass the overflowing file entry back out to anywhere, I don't see the difference.
If we are confident about our builds not getting into situation like that w/ the corresponding cbfstool changes then I think that is sufficient.
In that case, I don't see why I should brick their whole boot when coreboot could just as well just ignore it.
This is why I was asking about introducing policies that work for us, but not necessarily for others to handle the exceptional cases.
Julius Werner has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/38421 )
Change subject: commonlib/bsd: Add new CBFS core implementation ......................................................................
Patch Set 13:
(1 comment)
https://review.coreboot.org/c/coreboot/+/38421/11/src/commonlib/bsd/cbfs_pri... File src/commonlib/bsd/cbfs_private.c:
https://review.coreboot.org/c/coreboot/+/38421/11/src/commonlib/bsd/cbfs_pri... PS11, Line 75: offset + sizeof(mdata.h), todo) != todo)
As long as it doesn't pass the overflowing file entry back out to anywhere, I don't see the differ […]
Right, for Chrome OS specifically, I see no way this could cause a problem that wouldn't immediately be obvious. It's really just backwards-compatibility to edge cases that used to be technically legal but aren't anymore (and cbfstool will make sure not to generate them going forward). I don't think there's a need to put in extra Kconfigs or something, because for Chrome OS we always use the newest cbfstool anyway.
Angel Pons has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/38421 )
Change subject: commonlib/bsd: Add new CBFS core implementation ......................................................................
Patch Set 13:
(1 comment)
https://review.coreboot.org/c/coreboot/+/38421/11/src/commonlib/bsd/cbfs_pri... File src/commonlib/bsd/cbfs_private.c:
https://review.coreboot.org/c/coreboot/+/38421/11/src/commonlib/bsd/cbfs_pri... PS11, Line 75: offset + sizeof(mdata.h), todo) != todo)
Right, for Chrome OS specifically, I see no way this could cause a problem that wouldn't immediately […]
Why not use an assert() here? I've decided to use assertions when I've already verified the condition, but not nearby (e.g. in different files).
For example, I ensure the value for tWR can be programmed into the DDR3 MR0 (Mode Register 0) when computing the timings to use, but the code that programs the MR0 is on a different file.
Hello build bot (Jenkins), Nico Huber, Patrick Georgi, Patrick Rudolph, Angel Pons, Aaron Durbin, HAOUAS Elyes,
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/coreboot/+/38421
to look at the new patch set (#14).
Change subject: commonlib/bsd: Add new CBFS core implementation ......................................................................
commonlib/bsd: Add new CBFS core implementation
This patch adds a new CBFS implementation that is intended to replace the existing commonlib/cbfs.c. The new implementation is designed to meet a bunch of current and future goals that in aggregate make it easier to start from scratch than to adapt the exisiting implementation:
1. Be BSD-licensed so it can evetually be shared with libpayload. 2. Allow generating/verifying a metadata hash for future CBFS per-file verification (see [1][2]). 3. Be very careful about reading (not mmaping) all data only once, to be suitable for eventual TOCTOU-safe verification. 4. Make it possible to efficiently implement all current and future firmware use cases (both with and without verification).
The main primitive is the cbfs_walk() function which will traverse a CBFS and call a callback for every file. cbfs_lookup() uses this to implement the most common use case of finding a file so that it can be read. A host application using this code (e.g. coreboot, libpayload, cbfstool) will need to provide a <cbfs_glue.h> header to provide the glue to access the respective CBFS storage backend implementation.
This patch merely adds the code, the next patch will integrate it into coreboot.
[1]: https://www.youtube.com/watch?v=Hs_EhewBgtM [2]: https://osfc.io/uploads/talk/paper/47/The_future_of_firmware_verification_in... (Note: In early discussions the metadata hash was called "master hash".)
Change-Id: Ica64c1751fa37686814c0247460c399261d5814c Signed-off-by: Julius Werner jwerner@chromium.org --- M MAINTAINERS A src/commonlib/bsd/cbfs_private.c M src/commonlib/bsd/include/commonlib/bsd/cb_err.h A src/commonlib/bsd/include/commonlib/bsd/cbfs_private.h M src/commonlib/bsd/include/commonlib/bsd/cbfs_serialized.h 5 files changed, 292 insertions(+), 5 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/21/38421/14
Julius Werner has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/38421 )
Change subject: commonlib/bsd: Add new CBFS core implementation ......................................................................
Patch Set 13:
(2 comments)
https://review.coreboot.org/c/coreboot/+/38421/11/src/commonlib/bsd/cbfs_pri... File src/commonlib/bsd/cbfs_private.c:
https://review.coreboot.org/c/coreboot/+/38421/11/src/commonlib/bsd/cbfs_pri... PS11, Line 75: offset + sizeof(mdata.h), todo) != todo)
Why not use an assert() here? I've decided to use assertions when I've already verified the conditio […]
Uhh... yeah, sure, why not. Unfortunately GCC is surprisingly bad at analyzing this and can't eliminate it (I filed https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97434 because I was curious). But I guess one more check shouldn't break the bank.
https://review.coreboot.org/c/coreboot/+/38421/11/src/commonlib/bsd/cbfs_pri... PS11, Line 117: const size_t todo = be32toh(src->h.offset) - already_read;
cbfs_copy_fill_metadata() is only meant to be called from a |walker| callback to cbfs_walk(), where […]
Added an assert() here as well.
build bot (Jenkins) has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/38421 )
Change subject: commonlib/bsd: Add new CBFS core implementation ......................................................................
Patch Set 14:
(1 comment)
https://review.coreboot.org/c/coreboot/+/38421/14/src/commonlib/bsd/cbfs_pri... File src/commonlib/bsd/cbfs_private.c:
https://review.coreboot.org/c/coreboot/+/38421/14/src/commonlib/bsd/cbfs_pri... PS14, Line 35: if (do_hash && (vbrv = vb2_digest_init(&dc, metadata_hash->algo))) { do not use assignment in if condition
build bot (Jenkins) has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/38421 )
Change subject: commonlib/bsd: Add new CBFS core implementation ......................................................................
Patch Set 15:
(1 comment)
https://review.coreboot.org/c/coreboot/+/38421/15/src/commonlib/bsd/cbfs_pri... File src/commonlib/bsd/cbfs_private.c:
https://review.coreboot.org/c/coreboot/+/38421/15/src/commonlib/bsd/cbfs_pri... PS15, Line 35: if (do_hash && (vbrv = vb2_digest_init(&dc, metadata_hash->algo))) { do not use assignment in if condition
Aaron Durbin has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/38421 )
Change subject: commonlib/bsd: Add new CBFS core implementation ......................................................................
Patch Set 15:
(1 comment)
https://review.coreboot.org/c/coreboot/+/38421/11/src/commonlib/bsd/cbfs_pri... File src/commonlib/bsd/cbfs_private.c:
https://review.coreboot.org/c/coreboot/+/38421/11/src/commonlib/bsd/cbfs_pri... PS11, Line 75: offset + sizeof(mdata.h), todo) != todo)
Uhh... yeah, sure, why not. […]
I do think for Chrome OS we should be providing belts and suspenders to make sure we don't accidentally get ourselves into a situation. That, however, can be done in a followup.
Aaron Durbin has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/38421 )
Change subject: commonlib/bsd: Add new CBFS core implementation ......................................................................
Patch Set 15: Code-Review+2
(1 comment)
https://review.coreboot.org/c/coreboot/+/38421/15/src/commonlib/bsd/cbfs_pri... File src/commonlib/bsd/cbfs_private.c:
https://review.coreboot.org/c/coreboot/+/38421/15/src/commonlib/bsd/cbfs_pri... PS15, Line 119: assert(todo <= sizeof(*dst) - already_read); When !FATAL_ASSERTS won't the following read overflow the buffer?
Angel Pons has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/38421 )
Change subject: commonlib/bsd: Add new CBFS core implementation ......................................................................
Patch Set 15: Code-Review+1
(1 comment)
https://review.coreboot.org/c/coreboot/+/38421/15/src/commonlib/bsd/cbfs_pri... File src/commonlib/bsd/cbfs_private.c:
https://review.coreboot.org/c/coreboot/+/38421/15/src/commonlib/bsd/cbfs_pri... PS15, Line 119: assert(todo <= sizeof(*dst) - already_read);
When !FATAL_ASSERTS won't the following read overflow the buffer?
I think the previous code ensures this doesn't happen here. I suggested in earlier patchsets to use assertions when the conditions are checked elsewhere but it's not immediately obvious.
Aaron Durbin has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/38421 )
Change subject: commonlib/bsd: Add new CBFS core implementation ......................................................................
Patch Set 15:
(1 comment)
https://review.coreboot.org/c/coreboot/+/38421/15/src/commonlib/bsd/cbfs_pri... File src/commonlib/bsd/cbfs_private.c:
https://review.coreboot.org/c/coreboot/+/38421/15/src/commonlib/bsd/cbfs_pri... PS15, Line 119: assert(todo <= sizeof(*dst) - already_read);
I think the previous code ensures this doesn't happen here. […]
I'm not following? What previous code? the lookup_walker() code? Yes, when called w/ the proper wrapper. However, this is function is in the global namespace. Calling this function under the conditions I described would lead to overflowing buffers.
Angel Pons has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/38421 )
Change subject: commonlib/bsd: Add new CBFS core implementation ......................................................................
Patch Set 15:
(1 comment)
https://review.coreboot.org/c/coreboot/+/38421/15/src/commonlib/bsd/cbfs_pri... File src/commonlib/bsd/cbfs_private.c:
https://review.coreboot.org/c/coreboot/+/38421/15/src/commonlib/bsd/cbfs_pri... PS15, Line 119: assert(todo <= sizeof(*dst) - already_read);
I'm not following? What previous code? the lookup_walker() code? Yes, when called w/ the proper wrap […]
I didn't look too closely, but if so then it's bad
Julius Werner has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/38421 )
Change subject: commonlib/bsd: Add new CBFS core implementation ......................................................................
Patch Set 15:
(1 comment)
https://review.coreboot.org/c/coreboot/+/38421/15/src/commonlib/bsd/cbfs_pri... File src/commonlib/bsd/cbfs_private.c:
https://review.coreboot.org/c/coreboot/+/38421/15/src/commonlib/bsd/cbfs_pri... PS15, Line 119: assert(todo <= sizeof(*dst) - already_read);
I didn't look too closely, but if so then it's bad
This was the discussion from https://review.coreboot.org/c/coreboot/+/38421/11/src/commonlib/bsd/cbfs_pri.... This function is only intended to be called with the arguments that cbfs_walk() passed out to a walker() callback and if used that way, it should be guaranteed to be safe. Of course if you call a function with random garbage and ignore the intention explained in the docstring, bad things may happen. But this whole API is designed so that you can only really get access to cbfs_mdata structs that have passed the basic checks in cbfs_walk().
Running into this would signify a severe programming error so I think assert() is the appropriate construct. It's not here for input validation. (FWIW I wouldn't mind turning FATAL_ASSERTS on by default everywhere but that's a completly separate topic.)
Hello build bot (Jenkins), Nico Huber, Patrick Georgi, Patrick Rudolph, Angel Pons, Aaron Durbin, HAOUAS Elyes,
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/coreboot/+/38421
to look at the new patch set (#16).
Change subject: commonlib/bsd: Add new CBFS core implementation ......................................................................
commonlib/bsd: Add new CBFS core implementation
This patch adds a new CBFS implementation that is intended to replace the existing commonlib/cbfs.c. The new implementation is designed to meet a bunch of current and future goals that in aggregate make it easier to start from scratch than to adapt the exisiting implementation:
1. Be BSD-licensed so it can evetually be shared with libpayload. 2. Allow generating/verifying a metadata hash for future CBFS per-file verification (see [1][2]). 3. Be very careful about reading (not mmaping) all data only once, to be suitable for eventual TOCTOU-safe verification. 4. Make it possible to efficiently implement all current and future firmware use cases (both with and without verification).
The main primitive is the cbfs_walk() function which will traverse a CBFS and call a callback for every file. cbfs_lookup() uses this to implement the most common use case of finding a file so that it can be read. A host application using this code (e.g. coreboot, libpayload, cbfstool) will need to provide a <cbfs_glue.h> header to provide the glue to access the respective CBFS storage backend implementation.
This patch merely adds the code, the next patch will integrate it into coreboot.
[1]: https://www.youtube.com/watch?v=Hs_EhewBgtM [2]: https://osfc.io/uploads/talk/paper/47/The_future_of_firmware_verification_in... (Note: In early discussions the metadata hash was called "master hash".)
Change-Id: Ica64c1751fa37686814c0247460c399261d5814c Signed-off-by: Julius Werner jwerner@chromium.org --- M MAINTAINERS A src/commonlib/bsd/cbfs_private.c M src/commonlib/bsd/include/commonlib/bsd/cb_err.h A src/commonlib/bsd/include/commonlib/bsd/cbfs_private.h M src/commonlib/bsd/include/commonlib/bsd/cbfs_serialized.h 5 files changed, 292 insertions(+), 5 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/21/38421/16
Julius Werner has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/38421 )
Change subject: commonlib/bsd: Add new CBFS core implementation ......................................................................
Patch Set 16:
(7 comments)
https://review.coreboot.org/c/coreboot/+/38421/4/src/commonlib/bsd/cbfs_priv... File src/commonlib/bsd/cbfs_private.c:
https://review.coreboot.org/c/coreboot/+/38421/4/src/commonlib/bsd/cbfs_priv... PS4, Line 54: goto next_file;
I was just trying to continue where possible and skip over broken files rather than abort completely […]
(Continued in https://review.coreboot.org/c/coreboot/+/38421/11/src/commonlib/bsd/cbfs_pri...)
https://review.coreboot.org/c/coreboot/+/38421/4/src/commonlib/bsd/cbfs_priv... PS4, Line 123:
cbfs_walk() checks (data_offset > sizeof(mdata)) and (data_offset < attr_offset), so I think these c […]
(Continued in https://review.coreboot.org/c/coreboot/+/38421/11/src/commonlib/bsd/cbfs_pri...)
https://review.coreboot.org/c/coreboot/+/38421/8/src/commonlib/bsd/cbfs_priv... File src/commonlib/bsd/cbfs_private.c:
https://review.coreboot.org/c/coreboot/+/38421/8/src/commonlib/bsd/cbfs_priv... PS8, Line 8: size_t devsize
Maybe constify this?
Done
https://review.coreboot.org/c/coreboot/+/38421/8/src/commonlib/bsd/cbfs_priv... PS8, Line 30: bool do_hash
Maybe constify this?
Done
https://review.coreboot.org/c/coreboot/+/38421/4/src/commonlib/bsd/include/c... File src/commonlib/bsd/include/commonlib/bsd/cbfs_private.h:
https://review.coreboot.org/c/coreboot/+/38421/4/src/commonlib/bsd/include/c... PS4, Line 69: * the remaining CBFS (but not call |walker| anymore).
This is already supposed to be the underlying workhorse function, the wrappers are things like cbfs_ […]
Resolved?
https://review.coreboot.org/c/coreboot/+/38421/4/src/commonlib/bsd/include/c... PS4, Line 91: offset to the file data
Not sure what you mean, relative to what? This is absolute. […]
Done
https://review.coreboot.org/c/coreboot/+/38421/4/src/commonlib/bsd/include/c... File src/commonlib/bsd/include/commonlib/bsd/cbfs_serialized.h:
https://review.coreboot.org/c/coreboot/+/38421/4/src/commonlib/bsd/include/c... PS4, Line 131: struct vb2_hash hash;
Yes, this struct is supposed to have a somewhat dynamic length. […]
Done
build bot (Jenkins) has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/38421 )
Change subject: commonlib/bsd: Add new CBFS core implementation ......................................................................
Patch Set 16:
(1 comment)
https://review.coreboot.org/c/coreboot/+/38421/16/src/commonlib/bsd/cbfs_pri... File src/commonlib/bsd/cbfs_private.c:
https://review.coreboot.org/c/coreboot/+/38421/16/src/commonlib/bsd/cbfs_pri... PS16, Line 35: if (do_hash && (vbrv = vb2_digest_init(&dc, metadata_hash->algo))) { do not use assignment in if condition
Aaron Durbin has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/38421 )
Change subject: commonlib/bsd: Add new CBFS core implementation ......................................................................
Patch Set 16:
(1 comment)
https://review.coreboot.org/c/coreboot/+/38421/4/src/commonlib/bsd/include/c... File src/commonlib/bsd/include/commonlib/bsd/cbfs_private.h:
https://review.coreboot.org/c/coreboot/+/38421/4/src/commonlib/bsd/include/c... PS4, Line 69: * the remaining CBFS (but not call |walker| anymore).
Resolved?
sure
build bot (Jenkins) has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/38421 )
Change subject: commonlib/bsd: Add new CBFS core implementation ......................................................................
Patch Set 17:
(1 comment)
https://review.coreboot.org/c/coreboot/+/38421/17/src/commonlib/bsd/cbfs_pri... File src/commonlib/bsd/cbfs_private.c:
https://review.coreboot.org/c/coreboot/+/38421/17/src/commonlib/bsd/cbfs_pri... PS17, Line 35: if (do_hash && (vbrv = vb2_digest_init(&dc, metadata_hash->algo))) { do not use assignment in if condition
Aaron Durbin has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/38421 )
Change subject: commonlib/bsd: Add new CBFS core implementation ......................................................................
Patch Set 17: Code-Review+2
Philipp Deppenwiese has submitted this change. ( https://review.coreboot.org/c/coreboot/+/38421 )
Change subject: commonlib/bsd: Add new CBFS core implementation ......................................................................
commonlib/bsd: Add new CBFS core implementation
This patch adds a new CBFS implementation that is intended to replace the existing commonlib/cbfs.c. The new implementation is designed to meet a bunch of current and future goals that in aggregate make it easier to start from scratch than to adapt the exisiting implementation:
1. Be BSD-licensed so it can evetually be shared with libpayload. 2. Allow generating/verifying a metadata hash for future CBFS per-file verification (see [1][2]). 3. Be very careful about reading (not mmaping) all data only once, to be suitable for eventual TOCTOU-safe verification. 4. Make it possible to efficiently implement all current and future firmware use cases (both with and without verification).
The main primitive is the cbfs_walk() function which will traverse a CBFS and call a callback for every file. cbfs_lookup() uses this to implement the most common use case of finding a file so that it can be read. A host application using this code (e.g. coreboot, libpayload, cbfstool) will need to provide a <cbfs_glue.h> header to provide the glue to access the respective CBFS storage backend implementation.
This patch merely adds the code, the next patch will integrate it into coreboot.
[1]: https://www.youtube.com/watch?v=Hs_EhewBgtM [2]: https://osfc.io/uploads/talk/paper/47/The_future_of_firmware_verification_in... (Note: In early discussions the metadata hash was called "master hash".)
Change-Id: Ica64c1751fa37686814c0247460c399261d5814c Signed-off-by: Julius Werner jwerner@chromium.org Reviewed-on: https://review.coreboot.org/c/coreboot/+/38421 Reviewed-by: Aaron Durbin adurbin@chromium.org Tested-by: build bot (Jenkins) no-reply@coreboot.org --- M MAINTAINERS A src/commonlib/bsd/cbfs_private.c M src/commonlib/bsd/include/commonlib/bsd/cb_err.h A src/commonlib/bsd/include/commonlib/bsd/cbfs_private.h M src/commonlib/bsd/include/commonlib/bsd/cbfs_serialized.h 5 files changed, 292 insertions(+), 5 deletions(-)
Approvals: build bot (Jenkins): Verified Aaron Durbin: Looks good to me, approved
diff --git a/MAINTAINERS b/MAINTAINERS index d867c78..ba88813 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -694,8 +694,13 @@ F: src/device/oprom/
CBFS -F: src/include/cbfs.h -F: src/commonlib/bsd/include/commonlib/bsd/cbfs_serialized.h +M: Julius Werner jwerner@chromium.org +F: src/include/cbfs* +F: src/commonlib/bsd/include/commonlib/bsd/cbfs* +F: src/commonlib/bsd/cbfs* +F: src/lib/cbfs.c + +CBFSTOOL F: util/cbfstool/
CBMEM diff --git a/src/commonlib/bsd/cbfs_private.c b/src/commonlib/bsd/cbfs_private.c new file mode 100644 index 0000000..035684b --- /dev/null +++ b/src/commonlib/bsd/cbfs_private.c @@ -0,0 +1,161 @@ +/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0-or-later */ + +#include <commonlib/bsd/cbfs_private.h> +#include <assert.h> + +static cb_err_t read_next_header(cbfs_dev_t dev, size_t *offset, struct cbfs_file *buffer) +{ + const size_t devsize = cbfs_dev_size(dev); + DEBUG("Looking for next file @%#zx...\n", *offset); + *offset = ALIGN_UP(*offset, CBFS_ALIGNMENT); + while (*offset + sizeof(*buffer) < devsize) { + if (cbfs_dev_read(dev, buffer, *offset, sizeof(*buffer)) != sizeof(*buffer)) + return CB_CBFS_IO; + + if (memcmp(buffer->magic, CBFS_FILE_MAGIC, sizeof(buffer->magic)) == 0) + return CB_SUCCESS; + + *offset += CBFS_ALIGNMENT; + } + + DEBUG("End of CBFS reached\n"); + return CB_CBFS_NOT_FOUND; +} + +cb_err_t cbfs_walk(cbfs_dev_t dev, cb_err_t (*walker)(cbfs_dev_t dev, size_t offset, + const union cbfs_mdata *mdata, + size_t already_read, void *arg), + void *arg, struct vb2_hash *metadata_hash, enum cbfs_walk_flags flags) +{ + const bool do_hash = CBFS_ENABLE_HASHING && metadata_hash; + struct vb2_digest_context dc; + vb2_error_t vbrv; + + assert(CBFS_ENABLE_HASHING || (!metadata_hash && !(flags & CBFS_WALK_WRITEBACK_HASH))); + if (do_hash && (vbrv = vb2_digest_init(&dc, metadata_hash->algo))) { + ERROR("Metadata hash digest (%d) init error: %#x\n", metadata_hash->algo, vbrv); + return CB_ERR_ARG; + } + + size_t offset = 0; + cb_err_t ret_header; + cb_err_t ret_walker = CB_CBFS_NOT_FOUND; + union cbfs_mdata mdata; + while ((ret_header = read_next_header(dev, &offset, &mdata.h)) == CB_SUCCESS) { + const uint32_t attr_offset = be32toh(mdata.h.attributes_offset); + const uint32_t data_offset = be32toh(mdata.h.offset); + const uint32_t data_length = be32toh(mdata.h.len); + const uint32_t type = be32toh(mdata.h.type); + const bool empty = (type == CBFS_TYPE_DELETED || type == CBFS_TYPE_DELETED2); + + DEBUG("Found CBFS header @%#zx (type %d, attr +%#x, data +%#x, length %#x)\n", + offset, type, attr_offset, data_offset, data_length); + if (data_offset > sizeof(mdata)) { + ERROR("File metadata @%#zx too large\n", offset); + goto next_file; + } + + if (empty && !(flags & CBFS_WALK_INCLUDE_EMPTY)) + goto next_file; + + /* When hashing we need to read everything. Otherwise skip the attributes. + attr_offset may be 0, which means there are no attributes. */ + ssize_t todo; + if (do_hash || attr_offset == 0) + todo = data_offset - sizeof(mdata.h); + else + todo = attr_offset - sizeof(mdata.h); + if (todo <= 0 || data_offset < attr_offset) { + ERROR("Corrupt file header @%#zx\n", offset); + goto next_file; + } + + /* Read the rest of the metadata (filename, and possibly attributes). */ + assert(todo > 0 && todo <= sizeof(mdata) - sizeof(mdata.h)); + if (cbfs_dev_read(dev, mdata.raw + sizeof(mdata.h), + offset + sizeof(mdata.h), todo) != todo) + return CB_CBFS_IO; + DEBUG("File name: '%s'\n", mdata.filename); + + if (do_hash && !empty && vb2_digest_extend(&dc, mdata.raw, data_offset)) + return CB_ERR; + + if (walker && ret_walker == CB_CBFS_NOT_FOUND) + ret_walker = walker(dev, offset, &mdata, sizeof(mdata.h) + todo, arg); + + /* Return IO errors immediately. For others, finish the hash first if needed. */ + if (ret_walker == CB_CBFS_IO || (ret_walker != CB_CBFS_NOT_FOUND && !do_hash)) + return ret_walker; + +next_file: + offset += data_offset + data_length; + } + + if (ret_header != CB_CBFS_NOT_FOUND) + return ret_header; + + if (do_hash) { + uint8_t real_hash[VB2_MAX_DIGEST_SIZE]; + size_t hash_size = vb2_digest_size(metadata_hash->algo); + if (vb2_digest_finalize(&dc, real_hash, hash_size)) + return CB_ERR; + if (flags & CBFS_WALK_WRITEBACK_HASH) + memcpy(metadata_hash->raw, real_hash, hash_size); + else if (memcmp(metadata_hash->raw, real_hash, hash_size) != 0) + return CB_CBFS_HASH_MISMATCH; + } + + return ret_walker; +} + +cb_err_t cbfs_copy_fill_metadata(union cbfs_mdata *dst, const union cbfs_mdata *src, + size_t already_read, cbfs_dev_t dev, size_t offset) +{ + /* First, copy the stuff that cbfs_walk() already read for us. */ + memcpy(dst, src, already_read); + + /* Then read in whatever metadata may be left (will only happen in non-hashing case). */ + const size_t todo = be32toh(src->h.offset) - already_read; + assert(todo <= sizeof(*dst) - already_read); + if (todo && cbfs_dev_read(dev, dst->raw + already_read, offset + already_read, + todo) != todo) + return CB_CBFS_IO; + return CB_SUCCESS; +} + +struct cbfs_lookup_args { + union cbfs_mdata *mdata_out; + const char *name; + size_t namesize; + size_t *data_offset_out; +}; + +static cb_err_t lookup_walker(cbfs_dev_t dev, size_t offset, const union cbfs_mdata *mdata, + size_t already_read, void *arg) +{ + struct cbfs_lookup_args *args = arg; + + /* Check if the name we're looking for could fit, then we can safely memcmp() it. */ + if (args->namesize > already_read - offsetof(union cbfs_mdata, filename) || + memcmp(args->name, mdata->filename, args->namesize) != 0) + return CB_CBFS_NOT_FOUND; + + LOG("Found '%s' @%#zx size %#x\n", args->name, offset, be32toh(mdata->h.len)); + if (cbfs_copy_fill_metadata(args->mdata_out, mdata, already_read, dev, offset)) + return CB_CBFS_IO; + + *args->data_offset_out = offset + be32toh(mdata->h.offset); + return CB_SUCCESS; +} + +cb_err_t cbfs_lookup(cbfs_dev_t dev, const char *name, union cbfs_mdata *mdata_out, + size_t *data_offset_out, struct vb2_hash *metadata_hash) +{ + struct cbfs_lookup_args args = { + .mdata_out = mdata_out, + .name = name, + .namesize = strlen(name) + 1, /* Count trailing \0 so we can memcmp() it. */ + .data_offset_out = data_offset_out, + }; + return cbfs_walk(dev, lookup_walker, &args, metadata_hash, 0); +} diff --git a/src/commonlib/bsd/include/commonlib/bsd/cb_err.h b/src/commonlib/bsd/include/commonlib/bsd/cb_err.h index ab419a7..e5aa852 100644 --- a/src/commonlib/bsd/include/commonlib/bsd/cb_err.h +++ b/src/commonlib/bsd/include/commonlib/bsd/cb_err.h @@ -34,6 +34,11 @@ CB_I2C_PROTOCOL_ERROR = -302, /**< Data lost or spurious slave device response, try again? */ CB_I2C_TIMEOUT = -303, /**< Transmission timed out */ + + /* CBFS errors */ + CB_CBFS_IO = -400, /**< Underlying I/O error */ + CB_CBFS_NOT_FOUND = -401, /**< File not found in directory */ + CB_CBFS_HASH_MISMATCH = -402, /**< Master hash validation failed */ };
/* Don't typedef the enum directly, so the size is unambiguous for serialization. */ diff --git a/src/commonlib/bsd/include/commonlib/bsd/cbfs_private.h b/src/commonlib/bsd/include/commonlib/bsd/cbfs_private.h new file mode 100644 index 0000000..aaee62f --- /dev/null +++ b/src/commonlib/bsd/include/commonlib/bsd/cbfs_private.h @@ -0,0 +1,116 @@ +/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0-or-later */ + +#ifndef _COMMONLIB_BSD_CBFS_PRIVATE_H_ +#define _COMMONLIB_BSD_CBFS_PRIVATE_H_ + + +#include <commonlib/bsd/cb_err.h> +#include <commonlib/bsd/cbfs_serialized.h> +#include <endian.h> +#include <stdbool.h> +#include <stdint.h> +#include <vb2_sha.h> + +/* + * This header implements low-level CBFS access APIs that can be shared across different + * host applications (e.g. coreboot, libpayload, cbfstool). For verification purposes it + * implements the metadata hashing part but not the file hashing part, so the host application + * will need to verify file hashes itself after loading each file. Host applications that use + * verification should implement wrapper APIs that combine the lookup, loading and hashing steps + * into a single, safe function call and outside of the code implementing those APIs should not + * be accessing the low-level APIs in this file directly (e.g. coreboot SoC/driver code should + * never directly #include this file, and always use the higher level APIs in src/lib/cbfs.c). + * + * <cbfs_glue.h> needs to be provided by the host application using this CBFS library. It must + * define the following type, macros and functions: + * + * cbfs_dev_t An opaque type representing a CBFS storage backend. + * CBFS_ENABLE_HASHING Should be 0 to avoid linking hashing features, 1 otherwise. (Only for + * metadata hashing. Host application needs to check file hashes itself.) + * ERROR(...) printf-style macro to print errors. + * LOG(...) printf-style macro to print normal-operation log messages. + * DEBUG(...) printf-style macro to print detailed debug output. + * + * ssize_t cbfs_dev_read(cbfs_dev_t dev, void *buffer, size_t offset, size_t size); + * Read |size| bytes starting at |offset| from |dev| into |buffer|. + * Returns amount of bytes read on success and < 0 on error. + * This function *MUST* sanity-check offset/size on its own. + * + * size_t cbfs_dev_size(cbfs_dev_t dev); + * Return the total size in bytes of the CBFS storage (actual CBFS area). + */ +#include <cbfs_glue.h> + +/* + * Helper structure to allocate space for a blob of metadata on the stack. + * NOTE: The fields in any union cbfs_mdata or any of its substructures from cbfs_serialized.h + * should always remain in the same byte order as they are stored on flash (= big endian). To + * avoid byte-order confusion, fields should always and only be converted to host byte order at + * exactly the time they are read from one of these structures into their own separate variable. + */ +#define CBFS_METADATA_MAX_SIZE 256 +union cbfs_mdata { + struct { + struct cbfs_file h; + char filename[]; + }; + uint8_t raw[CBFS_METADATA_MAX_SIZE]; +}; + +/* Flags that modify behavior of cbfs_walk(). */ +enum cbfs_walk_flags { + /* Write the calculated hash back out to |metadata_hash->hash| rather than comparing it. + |metadata_hash->algo| must still have been initialized by the caller. */ + CBFS_WALK_WRITEBACK_HASH = (1 << 0), + /* Call |walker| for empty file entries (i.e. entries with one of the CBFS_TYPE_DELETED + types that mark free space in the CBFS). Otherwise, those entries will be skipped. + Either way, these entries are never included in the metadata_hash calculation. */ + CBFS_WALK_INCLUDE_EMPTY = (1 << 1), +}; + +/* + * Traverse a CBFS and call a |walker| callback function for every file. Can additionally + * calculate a hash over the metadata of all files in the CBFS. If |metadata_hash| is NULL, + * hashing is disabled. If |walker| is NULL, will just traverse and hash the CBFS without + * invoking any callbacks (and always return CB_CBFS_NOT_FOUND unless there was another error). + * + * |arg| and |dev| will be passed through to |walker| unmodified. |offset| is the absolute + * offset in |dev| at which the current file metadata starts. |mdata| is a temporary buffer + * (only valid for the duration of this call to |walker|) containing already read metadata from + * the current file, up to |already_read| bytes. This will always at least contain the header + * fields and filename, but may contain more (i.e. attributes), depending on whether hashing is + * enabled. |walker| should call into cbfs_copy_fill_medadata() to copy the metadata of a file + * to a persistent buffer and automatically load remaining metadata from |dev| as needed based + * on the value of |already_read|. + * + * |walker| should return CB_CBFS_NOT_FOUND if it wants to continue being called for further + * files. Any other return code will be used as the final return code for cbfs_walk(). It will + * return immediately unless it needs to calculate a hash in which case it will still traverse + * the remaining CBFS (but not call |walker| anymore). + * + * Returns, from highest to lowest priority: + * CB_CBFS_IO - There was an IO error with the CBFS device (always considered fatal) + * CB_CBFS_HASH_MISMATCH - |metadata_hash| was provided and did not match the CBFS + * CB_SUCCESS/<other> - First non-CB_CBFS_NOT_FOUND code returned by walker() + * CB_CBFS_NOT_FOUND - walker() returned CB_CBFS_NOT_FOUND for every file in the CBFS + */ +cb_err_t cbfs_walk(cbfs_dev_t dev, cb_err_t (*walker)(cbfs_dev_t dev, size_t offset, + const union cbfs_mdata *mdata, + size_t already_read, void *arg), + void *arg, struct vb2_hash *metadata_hash, enum cbfs_walk_flags); + +/* + * Helper function that can be used by a |walker| callback to cbfs_walk() to copy the metadata + * of a file into a permanent buffer. Will copy the |already_read| metadata from |src| into + * |dst| and load remaining metadata from |dev| as required. + */ +cb_err_t cbfs_copy_fill_metadata(union cbfs_mdata *dst, const union cbfs_mdata *src, + size_t already_read, cbfs_dev_t dev, size_t offset); + +/* Find a file named |name| in the CBFS on |dev|. Copy its metadata (including attributes) + * into |mdata_out| and pass out the offset to the file data on the CBFS device. + * Verify the metadata with |metadata_hash| if provided. */ +cb_err_t cbfs_lookup(cbfs_dev_t dev, const char *name, union cbfs_mdata *mdata_out, + size_t *data_offset_out, struct vb2_hash *metadata_hash); + +#endif /* _COMMONLIB_BSD_CBFS_PRIVATE_H_ */ diff --git a/src/commonlib/bsd/include/commonlib/bsd/cbfs_serialized.h b/src/commonlib/bsd/include/commonlib/bsd/cbfs_serialized.h index 3c76a49..7171634 100644 --- a/src/commonlib/bsd/include/commonlib/bsd/cbfs_serialized.h +++ b/src/commonlib/bsd/include/commonlib/bsd/cbfs_serialized.h @@ -4,6 +4,7 @@ #define _CBFS_SERIALIZED_H_
#include <stdint.h> +#include <vb2_sha.h>
/** These are standard values for the known compression algorithms that coreboot knows about for stages and @@ -124,12 +125,11 @@ uint32_t decompressed_size; } __packed;
+/* Actual size in CBFS may be larger/smaller than struct size! */ struct cbfs_file_attr_hash { uint32_t tag; uint32_t len; - uint32_t hash_type; - /* hash_data is len - sizeof(struct) bytes */ - uint8_t hash_data[]; + struct vb2_hash hash; } __packed;
struct cbfs_file_attr_position {