blob: 8e50f39d451b63ea1b6debd6486ab3e333f5693a [file] [log] [blame]
Jakub Czapiga63e54272021-11-15 08:36:07 +00001/* 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
13unsigned long virtual_offset = 0;
14struct sysinfo_t lib_sysinfo;
15
16size_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
26vb2_error_t vb2_hash_verify(const void *buf, uint32_t size, const struct vb2_hash *hash)
27{
28 check_expected_ptr(buf);
29 check_expected(size);
30
31 assert_int_equal(hash->algo, VB2_HASH_SHA256);
32
33 if (!memcmp(hash->sha256, good_hash, sizeof(good_hash)))
34 return VB2_SUCCESS;
35
36 if (!memcmp(hash->sha256, bad_hash, sizeof(bad_hash)))
37 return VB2_ERROR_SHA_MISMATCH;
38
39 fail_msg("%s called with bad hash", __func__);
40 return VB2_ERROR_SHA_MISMATCH;
41}
42
43unsigned long ulzman(const unsigned char *src, unsigned long srcn, unsigned char *dst,
44 unsigned long dstn)
45{
Yu-Ping Wuc1d7d892022-06-15 15:03:04 +080046 size_t copy_size = MIN(srcn, dstn);
47 function_called();
48 memcpy(dst, src, copy_size);
49 return copy_size;
Jakub Czapiga63e54272021-11-15 08:36:07 +000050}
51
52size_t ulz4fn(const void *src, size_t srcn, void *dst, size_t dstn)
53{
Yu-Ping Wuc1d7d892022-06-15 15:03:04 +080054 size_t copy_size = MIN(srcn, dstn);
55 function_called();
56 memcpy(dst, src, copy_size);
57 return copy_size;
Jakub Czapiga63e54272021-11-15 08:36:07 +000058}
59
Julius Werner69cc5572022-03-04 17:49:56 -080060enum cb_err cbfs_mcache_lookup(const void *mcache, size_t mcache_size, const char *name,
61 union cbfs_mdata *mdata_out, size_t *data_offset_out)
Jakub Czapiga63e54272021-11-15 08:36:07 +000062{
63 return CB_CBFS_CACHE_FULL;
64}
65
Julius Werner69cc5572022-03-04 17:49:56 -080066enum cb_err cbfs_lookup(cbfs_dev_t dev, const char *name, union cbfs_mdata *mdata_out,
67 size_t *data_offset_out, struct vb2_hash *metadata_hash)
Jakub Czapiga63e54272021-11-15 08:36:07 +000068{
69 assert_non_null(dev);
70 check_expected(name);
71
Julius Werner69cc5572022-03-04 17:49:56 -080072 enum cb_err ret = mock_type(enum cb_err);
Jakub Czapiga63e54272021-11-15 08:36:07 +000073 if (ret != CB_SUCCESS)
74 return ret;
75
76 memcpy(mdata_out, mock_ptr_type(const union cbfs_mdata *), sizeof(union cbfs_mdata));
77 *data_offset_out = mock_type(size_t);
78 return CB_SUCCESS;
79}
80
Julius Werner69cc5572022-03-04 17:49:56 -080081static void expect_cbfs_lookup(const char *name, enum cb_err err, const union cbfs_mdata *mdata,
Jakub Czapiga63e54272021-11-15 08:36:07 +000082 size_t data_offset_out)
83{
84 expect_string(cbfs_lookup, name, name);
85 will_return(cbfs_lookup, err);
86
87 if (err == CB_SUCCESS) {
88 will_return(cbfs_lookup, mdata);
89 will_return(cbfs_lookup, data_offset_out);
90 }
91}
92
93const void *cbfs_find_attr(const union cbfs_mdata *mdata, uint32_t attr_tag, size_t size_check)
94{
95 return mock_ptr_type(void *);
96}
97
Julius Werner69cc5572022-03-04 17:49:56 -080098enum cb_err fmap_locate_area(const char *name, size_t *offset, size_t *size)
Jakub Czapiga63e54272021-11-15 08:36:07 +000099{
100 *offset = 0;
101 *size = 0;
102 return CB_SUCCESS;
103}
104
105ssize_t boot_device_read(void *buf, size_t offset, size_t size)
106{
107 /* Offset should be based on an address from lib_sysinfo.cbfs_offset */
108 memcpy(buf, (void *)offset, size);
109
110 return size;
111}
112
113const struct vb2_hash *cbfs_file_hash(const union cbfs_mdata *mdata)
114{
115 return mock_ptr_type(const struct vb2_hash *);
116}
117
118/* Utils */
119
120static void clear_cbfs_boot_devices(void)
121{
122 lib_sysinfo.cbfs_ro_mcache_offset = 0;
123 lib_sysinfo.cbfs_ro_mcache_size = 0;
124 lib_sysinfo.cbfs_offset = 0;
125 lib_sysinfo.cbfs_size = 0;
126 lib_sysinfo.cbfs_rw_mcache_offset = 0;
127 lib_sysinfo.cbfs_rw_mcache_size = 0;
128 memset((void *)cbfs_get_boot_device(true), 0, sizeof(struct cbfs_boot_device));
129 memset((void *)cbfs_get_boot_device(false), 0, sizeof(struct cbfs_boot_device));
130}
131
132void set_cbfs(uint64_t offset, size_t size)
133{
134 clear_cbfs_boot_devices();
135 lib_sysinfo.cbfs_offset = offset;
136 lib_sysinfo.cbfs_size = size;
137}
138
139/* Tests */
140
141static int setup_test_cbfs(void **state)
142{
143 clear_cbfs_boot_devices();
144 return 0;
145}
146
147static void test_cbfs_map_no_hash(void **state)
148{
149 void *mapping = NULL;
150 size_t size = 0;
151
152 set_cbfs((uint64_t)&file_no_hash, sizeof(file_no_hash));
153
154 expect_cbfs_lookup(TEST_DATA_1_FILENAME, CB_SUCCESS,
155 (const union cbfs_mdata *)&file_no_hash,
156 be32toh(file_no_hash.header.offset));
157 will_return(cbfs_find_attr, NULL);
158
159 if (CONFIG(LP_CBFS_VERIFICATION)) {
160 /* File with no hash. No hash causes hash mismatch by default,
161 so mapping will not be completed successfully. */
162 will_return(cbfs_file_hash, NULL);
163 mapping = cbfs_map(TEST_DATA_1_FILENAME, NULL);
164 assert_null(mapping);
165 } else {
166 mapping = cbfs_map(TEST_DATA_1_FILENAME, &size);
167 assert_non_null(mapping);
168 assert_int_equal(TEST_DATA_1_SIZE, size);
169 assert_memory_equal(test_data_1, mapping, size);
170 cbfs_unmap(mapping);
171 }
172}
173
Yu-Ping Wuc1d7d892022-06-15 15:03:04 +0800174static void test_cbfs_map_valid_hash_impl(void **state, bool lz4_compressed)
Jakub Czapiga63e54272021-11-15 08:36:07 +0000175{
176 void *mapping = NULL;
177 size_t size = 0;
178 struct vb2_hash hash = {
179 .algo = VB2_HASH_SHA256,
180 };
181 memcpy(&hash.sha256, good_hash, VB2_SHA256_DIGEST_SIZE);
182
183 set_cbfs((uint64_t)&file_valid_hash, sizeof(file_valid_hash));
184
185 expect_cbfs_lookup(TEST_DATA_1_FILENAME, CB_SUCCESS,
186 (const union cbfs_mdata *)&file_valid_hash,
187 be32toh(file_valid_hash.header.offset));
Jakub Czapiga63e54272021-11-15 08:36:07 +0000188
Yu-Ping Wuc1d7d892022-06-15 15:03:04 +0800189 if (lz4_compressed) {
190 struct cbfs_file_attr_compression cattr = {
191 .compression = htobe32(CBFS_COMPRESS_LZ4),
192 .decompressed_size = htobe32(TEST_DATA_1_SIZE),
193 };
194 will_return(cbfs_find_attr, &cattr);
195 expect_function_call(ulz4fn);
196 } else {
197 will_return(cbfs_find_attr, NULL);
198 }
Jakub Czapiga63e54272021-11-15 08:36:07 +0000199
200 if (CONFIG(LP_CBFS_VERIFICATION)) {
201 will_return(cbfs_file_hash, &hash);
202 expect_memory(vb2_hash_verify, buf,
203 &file_valid_hash.attrs_and_data[HASH_ATTR_SIZE], HASH_ATTR_SIZE);
204 expect_value(vb2_hash_verify, size, TEST_DATA_1_SIZE);
205 mapping = cbfs_map(TEST_DATA_1_FILENAME, &size);
206 assert_non_null(mapping);
207 assert_int_equal(TEST_DATA_1_SIZE, size);
208 assert_memory_equal(mapping, &file_valid_hash.attrs_and_data[HASH_ATTR_SIZE],
209 size);
210 } else {
211 mapping = cbfs_map(TEST_DATA_1_FILENAME, &size);
212 assert_non_null(mapping);
213 assert_int_equal(TEST_DATA_1_SIZE, size);
214 assert_memory_equal(test_data_1, mapping, size);
215 cbfs_unmap(mapping);
216 }
217}
218
Yu-Ping Wuc1d7d892022-06-15 15:03:04 +0800219static void test_cbfs_map_valid_hash(void **state)
220{
221 test_cbfs_map_valid_hash_impl(state, false);
222}
223
224static void test_cbfs_map_valid_hash_with_lz4(void **state)
225{
226 test_cbfs_map_valid_hash_impl(state, true);
227}
228
Jakub Czapiga63e54272021-11-15 08:36:07 +0000229static void test_cbfs_map_invalid_hash(void **state)
230{
231 void *mapping = NULL;
232 size_t size = 0;
233 struct vb2_hash hash = {
234 .algo = VB2_HASH_SHA256,
235 };
236 memcpy(&hash.sha256, bad_hash, VB2_SHA256_DIGEST_SIZE);
237
238 set_cbfs((uint64_t)&file_broken_hash, sizeof(file_broken_hash));
239
240 expect_cbfs_lookup(TEST_DATA_1_FILENAME, CB_SUCCESS,
241 (const union cbfs_mdata *)&file_broken_hash,
242 be32toh(file_broken_hash.header.offset));
243 will_return(cbfs_find_attr, NULL);
244
245 if (CONFIG(LP_CBFS_VERIFICATION)) {
246 will_return(cbfs_file_hash, &hash);
247 expect_memory(vb2_hash_verify, buf,
248 &file_broken_hash.attrs_and_data[HASH_ATTR_SIZE], HASH_ATTR_SIZE);
249 expect_value(vb2_hash_verify, size, TEST_DATA_1_SIZE);
250 mapping = cbfs_map(TEST_DATA_1_FILENAME, NULL);
251 assert_null(mapping);
252 } else {
253 mapping = cbfs_map(TEST_DATA_1_FILENAME, &size);
254 assert_non_null(mapping);
255 assert_int_equal(TEST_DATA_1_SIZE, size);
256 assert_memory_equal(test_data_1, mapping, size);
257 cbfs_unmap(mapping);
258 }
259}
260
261int main(void)
262{
263 const struct CMUnitTest tests[] = {
264 cmocka_unit_test_setup(test_cbfs_map_no_hash, setup_test_cbfs),
265 cmocka_unit_test_setup(test_cbfs_map_valid_hash, setup_test_cbfs),
Yu-Ping Wuc1d7d892022-06-15 15:03:04 +0800266 cmocka_unit_test_setup(test_cbfs_map_valid_hash_with_lz4, setup_test_cbfs),
Jakub Czapiga63e54272021-11-15 08:36:07 +0000267 cmocka_unit_test_setup(test_cbfs_map_invalid_hash, setup_test_cbfs),
268 };
269
270 return lp_run_group_tests(tests, NULL, NULL);
271}