summaryrefslogtreecommitdiffstats
path: root/src/commonlib/bsd/include/commonlib/bsd/cbfs_private.h
blob: b72463aba3dfb68e49651815c979f49ed908db04 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
/* 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);

/* Both base address and size of CBFS mcaches must be aligned to this value! */
#define CBFS_MCACHE_ALIGNMENT	sizeof(uint32_t)	/* Largest data type used in CBFS */

/* Build an in-memory CBFS metadata cache out of the CBFS on |dev| into a |mcache_size| bytes
 * memory area at |mcache|. Also verify |metadata_hash| unless it is NULL. If this returns
 * CB_CBFS_CACHE_FULL, the mcache is still valid and can be used, but lookups may return
 * CB_CBFS_CACHE_FULL for files that didn't fit to indicate that the caller needs to fall back
 * to cbfs_lookup(). */
cb_err_t cbfs_mcache_build(cbfs_dev_t dev, void *mcache, size_t mcache_size,
			   struct vb2_hash *metadata_hash);

/*
 * Find a file named |name| in a CBFS metadata cache and copy its metadata into |mdata_out|.
 * Pass out offset to the file data (on the original CBFS device used for cbfs_mcache_build()).
 */
cb_err_t cbfs_mcache_lookup(const void *mcache, size_t mcache_size, const char *name,
			    union cbfs_mdata *mdata_out, size_t *data_offset_out);

/* Returns the amount of bytes actually used by the CBFS metadata cache in |mcache|. */
size_t cbfs_mcache_real_size(const void *mcache, size_t mcache_size);

/* Finds a CBFS attribute in a metadata block. Attribute returned as-is (still big-endian).
   If |size| is not 0, will check that it matches the length of the attribute (if found)...
   else caller is responsible for checking the |len| field to avoid reading out-of-bounds. */
const void *cbfs_find_attr(const union cbfs_mdata *mdata, uint32_t attr_tag, size_t size_check);

#endif	/* _COMMONLIB_BSD_CBFS_PRIVATE_H_ */