xref: /aosp_15_r20/external/coreboot/payloads/libpayload/tests/libcbfs/cbfs-verification-test.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <cbfs.h>
4 #include <cbfs_glue.h>
5 #include <string.h>
6 #include <mocks/cbfs_util.h>
7 #include <tests/test.h>
8 
9 #include "../libcbfs/cbfs.c"
10 
11 /* Mocks */
12 
13 unsigned long virtual_offset = 0;
14 struct sysinfo_t lib_sysinfo;
15 
vb2_digest_size(enum vb2_hash_algorithm hash_alg)16 size_t vb2_digest_size(enum vb2_hash_algorithm hash_alg)
17 {
18 	if (hash_alg != VB2_HASH_SHA256) {
19 		fail_msg("Unsupported hash algorithm: %d\n", hash_alg);
20 		return 0;
21 	}
22 
23 	return VB2_SHA256_DIGEST_SIZE;
24 }
25 
vb2_hash_verify(bool allow_hwcrypto,const void * buf,uint32_t size,const struct vb2_hash * hash)26 vb2_error_t vb2_hash_verify(bool allow_hwcrypto, const void *buf, uint32_t size,
27 			    const struct vb2_hash *hash)
28 {
29 	assert_true(allow_hwcrypto);
30 	check_expected_ptr(buf);
31 	check_expected(size);
32 
33 	assert_int_equal(hash->algo, VB2_HASH_SHA256);
34 
35 	if (!memcmp(hash->sha256, good_hash, sizeof(good_hash)))
36 		return VB2_SUCCESS;
37 
38 	if (!memcmp(hash->sha256, bad_hash, sizeof(bad_hash)))
39 		return VB2_ERROR_SHA_MISMATCH;
40 
41 	fail_msg("%s called with bad hash", __func__);
42 	return VB2_ERROR_SHA_MISMATCH;
43 }
44 
vb2api_hwcrypto_allowed(struct vb2_context * ctx)45 bool vb2api_hwcrypto_allowed(struct vb2_context *ctx)
46 {
47 	return true;
48 }
49 
vboot_get_context(void)50 struct vb2_context *vboot_get_context(void)
51 {
52 	return NULL;
53 }
54 
ulzman(const unsigned char * src,unsigned long srcn,unsigned char * dst,unsigned long dstn)55 unsigned long ulzman(const unsigned char *src, unsigned long srcn, unsigned char *dst,
56 		     unsigned long dstn)
57 {
58 	size_t copy_size = MIN(srcn, dstn);
59 	function_called();
60 	memcpy(dst, src, copy_size);
61 	return copy_size;
62 }
63 
ulz4fn(const void * src,size_t srcn,void * dst,size_t dstn)64 size_t ulz4fn(const void *src, size_t srcn, void *dst, size_t dstn)
65 {
66 	size_t copy_size = MIN(srcn, dstn);
67 	function_called();
68 	memcpy(dst, src, copy_size);
69 	return copy_size;
70 }
71 
cbfs_mcache_lookup(const void * mcache,size_t mcache_size,const char * name,union cbfs_mdata * mdata_out,size_t * data_offset_out)72 enum cb_err cbfs_mcache_lookup(const void *mcache, size_t mcache_size, const char *name,
73 			       union cbfs_mdata *mdata_out, size_t *data_offset_out)
74 {
75 	return CB_CBFS_CACHE_FULL;
76 }
77 
cbfs_lookup(cbfs_dev_t dev,const char * name,union cbfs_mdata * mdata_out,size_t * data_offset_out,struct vb2_hash * metadata_hash)78 enum cb_err cbfs_lookup(cbfs_dev_t dev, const char *name, union cbfs_mdata *mdata_out,
79 			size_t *data_offset_out, struct vb2_hash *metadata_hash)
80 {
81 	assert_non_null(dev);
82 	check_expected(name);
83 
84 	enum cb_err ret = mock_type(enum cb_err);
85 	if (ret != CB_SUCCESS)
86 		return ret;
87 
88 	memcpy(mdata_out, mock_ptr_type(const union cbfs_mdata *), sizeof(union cbfs_mdata));
89 	*data_offset_out = mock_type(size_t);
90 	return CB_SUCCESS;
91 }
92 
expect_cbfs_lookup(const char * name,enum cb_err err,const union cbfs_mdata * mdata,size_t data_offset_out)93 static void expect_cbfs_lookup(const char *name, enum cb_err err, const union cbfs_mdata *mdata,
94 			       size_t data_offset_out)
95 {
96 	expect_string(cbfs_lookup, name, name);
97 	will_return(cbfs_lookup, err);
98 
99 	if (err == CB_SUCCESS) {
100 		will_return(cbfs_lookup, mdata);
101 		will_return(cbfs_lookup, data_offset_out);
102 	}
103 }
104 
cbfs_find_attr(const union cbfs_mdata * mdata,uint32_t attr_tag,size_t size_check)105 const void *cbfs_find_attr(const union cbfs_mdata *mdata, uint32_t attr_tag, size_t size_check)
106 {
107 	return mock_ptr_type(void *);
108 }
109 
fmap_locate_area(const char * name,size_t * offset,size_t * size)110 enum cb_err fmap_locate_area(const char *name, size_t *offset, size_t *size)
111 {
112 	*offset = 0;
113 	*size = 0;
114 	return CB_SUCCESS;
115 }
116 
boot_device_read(void * buf,size_t offset,size_t size)117 ssize_t boot_device_read(void *buf, size_t offset, size_t size)
118 {
119 	/* Offset should be based on an address from lib_sysinfo.cbfs_offset */
120 	memcpy(buf, (void *)offset, size);
121 
122 	return size;
123 }
124 
cbfs_file_hash(const union cbfs_mdata * mdata)125 const struct vb2_hash *cbfs_file_hash(const union cbfs_mdata *mdata)
126 {
127 	return mock_ptr_type(const struct vb2_hash *);
128 }
129 
130 /* Utils */
131 
clear_cbfs_boot_devices(void)132 static void clear_cbfs_boot_devices(void)
133 {
134 	lib_sysinfo.cbfs_ro_mcache_offset = 0;
135 	lib_sysinfo.cbfs_ro_mcache_size = 0;
136 	lib_sysinfo.cbfs_offset = 0;
137 	lib_sysinfo.cbfs_size = 0;
138 	lib_sysinfo.cbfs_rw_mcache_offset = 0;
139 	lib_sysinfo.cbfs_rw_mcache_size = 0;
140 	memset((void *)cbfs_get_boot_device(true), 0, sizeof(struct cbfs_boot_device));
141 	memset((void *)cbfs_get_boot_device(false), 0, sizeof(struct cbfs_boot_device));
142 }
143 
set_cbfs(uint64_t offset,size_t size)144 void set_cbfs(uint64_t offset, size_t size)
145 {
146 	clear_cbfs_boot_devices();
147 	lib_sysinfo.cbfs_offset = offset;
148 	lib_sysinfo.cbfs_size = size;
149 }
150 
151 /* Tests */
152 
setup_test_cbfs(void ** state)153 static int setup_test_cbfs(void **state)
154 {
155 	clear_cbfs_boot_devices();
156 	return 0;
157 }
158 
test_cbfs_map_no_hash(void ** state)159 static void test_cbfs_map_no_hash(void **state)
160 {
161 	void *mapping = NULL;
162 	size_t size = 0;
163 
164 	set_cbfs((uint64_t)&file_no_hash, sizeof(file_no_hash));
165 
166 	expect_cbfs_lookup(TEST_DATA_1_FILENAME, CB_SUCCESS,
167 			   (const union cbfs_mdata *)&file_no_hash,
168 			   be32toh(file_no_hash.header.offset));
169 	will_return(cbfs_find_attr, NULL);
170 
171 	if (CONFIG(LP_CBFS_VERIFICATION)) {
172 		/* File with no hash. No hash causes hash mismatch by default,
173 		   so mapping will not be completed successfully. */
174 		will_return(cbfs_file_hash, NULL);
175 		mapping = cbfs_map(TEST_DATA_1_FILENAME, NULL);
176 		assert_null(mapping);
177 	} else {
178 		mapping = cbfs_map(TEST_DATA_1_FILENAME, &size);
179 		assert_non_null(mapping);
180 		assert_int_equal(TEST_DATA_1_SIZE, size);
181 		assert_memory_equal(test_data_1, mapping, size);
182 		cbfs_unmap(mapping);
183 	}
184 }
185 
test_cbfs_map_valid_hash_impl(void ** state,bool lz4_compressed)186 static void test_cbfs_map_valid_hash_impl(void **state, bool lz4_compressed)
187 {
188 	void *mapping = NULL;
189 	size_t size = 0;
190 	struct vb2_hash hash = {
191 		.algo = VB2_HASH_SHA256,
192 	};
193 	memcpy(&hash.sha256, good_hash, VB2_SHA256_DIGEST_SIZE);
194 
195 	set_cbfs((uint64_t)&file_valid_hash, sizeof(file_valid_hash));
196 
197 	expect_cbfs_lookup(TEST_DATA_1_FILENAME, CB_SUCCESS,
198 			   (const union cbfs_mdata *)&file_valid_hash,
199 			   be32toh(file_valid_hash.header.offset));
200 
201 	if (lz4_compressed) {
202 		struct cbfs_file_attr_compression cattr = {
203 			.compression = htobe32(CBFS_COMPRESS_LZ4),
204 			.decompressed_size = htobe32(TEST_DATA_1_SIZE),
205 		};
206 		will_return(cbfs_find_attr, &cattr);
207 		expect_function_call(ulz4fn);
208 	} else {
209 		will_return(cbfs_find_attr, NULL);
210 	}
211 
212 	if (CONFIG(LP_CBFS_VERIFICATION)) {
213 		will_return(cbfs_file_hash, &hash);
214 		expect_memory(vb2_hash_verify, buf,
215 			      &file_valid_hash.attrs_and_data[HASH_ATTR_SIZE], HASH_ATTR_SIZE);
216 		expect_value(vb2_hash_verify, size, TEST_DATA_1_SIZE);
217 		mapping = cbfs_map(TEST_DATA_1_FILENAME, &size);
218 		assert_non_null(mapping);
219 		assert_int_equal(TEST_DATA_1_SIZE, size);
220 		assert_memory_equal(mapping, &file_valid_hash.attrs_and_data[HASH_ATTR_SIZE],
221 				    size);
222 	} else {
223 		mapping = cbfs_map(TEST_DATA_1_FILENAME, &size);
224 		assert_non_null(mapping);
225 		assert_int_equal(TEST_DATA_1_SIZE, size);
226 		assert_memory_equal(test_data_1, mapping, size);
227 		cbfs_unmap(mapping);
228 	}
229 }
230 
test_cbfs_map_valid_hash(void ** state)231 static void test_cbfs_map_valid_hash(void **state)
232 {
233 	test_cbfs_map_valid_hash_impl(state, false);
234 }
235 
test_cbfs_map_valid_hash_with_lz4(void ** state)236 static void test_cbfs_map_valid_hash_with_lz4(void **state)
237 {
238 	test_cbfs_map_valid_hash_impl(state, true);
239 }
240 
test_cbfs_map_invalid_hash(void ** state)241 static void test_cbfs_map_invalid_hash(void **state)
242 {
243 	void *mapping = NULL;
244 	size_t size = 0;
245 	struct vb2_hash hash = {
246 		.algo = VB2_HASH_SHA256,
247 	};
248 	memcpy(&hash.sha256, bad_hash, VB2_SHA256_DIGEST_SIZE);
249 
250 	set_cbfs((uint64_t)&file_broken_hash, sizeof(file_broken_hash));
251 
252 	expect_cbfs_lookup(TEST_DATA_1_FILENAME, CB_SUCCESS,
253 			   (const union cbfs_mdata *)&file_broken_hash,
254 			   be32toh(file_broken_hash.header.offset));
255 	will_return(cbfs_find_attr, NULL);
256 
257 	if (CONFIG(LP_CBFS_VERIFICATION)) {
258 		will_return(cbfs_file_hash, &hash);
259 		expect_memory(vb2_hash_verify, buf,
260 			      &file_broken_hash.attrs_and_data[HASH_ATTR_SIZE], HASH_ATTR_SIZE);
261 		expect_value(vb2_hash_verify, size, TEST_DATA_1_SIZE);
262 		mapping = cbfs_map(TEST_DATA_1_FILENAME, NULL);
263 		assert_null(mapping);
264 	} else {
265 		mapping = cbfs_map(TEST_DATA_1_FILENAME, &size);
266 		assert_non_null(mapping);
267 		assert_int_equal(TEST_DATA_1_SIZE, size);
268 		assert_memory_equal(test_data_1, mapping, size);
269 		cbfs_unmap(mapping);
270 	}
271 }
272 
main(void)273 int main(void)
274 {
275 	const struct CMUnitTest tests[] = {
276 		cmocka_unit_test_setup(test_cbfs_map_no_hash, setup_test_cbfs),
277 		cmocka_unit_test_setup(test_cbfs_map_valid_hash, setup_test_cbfs),
278 		cmocka_unit_test_setup(test_cbfs_map_valid_hash_with_lz4, setup_test_cbfs),
279 		cmocka_unit_test_setup(test_cbfs_map_invalid_hash, setup_test_cbfs),
280 	};
281 
282 	return lp_run_group_tests(tests, NULL, NULL);
283 }
284