diff options
Diffstat (limited to 'src/commonlib/bsd/include')
-rw-r--r-- | src/commonlib/bsd/include/commonlib/bsd/cb_err.h | 5 | ||||
-rw-r--r-- | src/commonlib/bsd/include/commonlib/bsd/cbfs_private.h | 116 | ||||
-rw-r--r-- | src/commonlib/bsd/include/commonlib/bsd/cbfs_serialized.h | 6 |
3 files changed, 124 insertions, 3 deletions
diff --git a/src/commonlib/bsd/include/commonlib/bsd/cb_err.h b/src/commonlib/bsd/include/commonlib/bsd/cb_err.h index ab419a7709..e5aa852617 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 @@ enum cb_err { 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 0000000000..aaee62f4c3 --- /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 3c76a49f55..7171634c8e 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 @@ struct cbfs_file_attr_compression { 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 { |