xref: /aosp_15_r20/external/vboot_reference/tests/vb2_load_kernel2_tests.c (revision 8617a60d3594060b7ecbd21bc622a7c14f3cf2bc)
1 /* Copyright 2021 The ChromiumOS Authors
2  * Use of this source code is governed by a BSD-style license that can be
3  * found in the LICENSE file.
4  *
5  * Tests for miniOS kernel selection, loading, verification, and booting.
6  */
7 
8 #include "2api.h"
9 #include "2common.h"
10 #include "2misc.h"
11 #include "2nvstorage.h"
12 #include "2secdata.h"
13 #include "common/boot_mode.h"
14 #include "common/tests.h"
15 #include "vboot_api.h"
16 
17 #define MAX_MOCK_KERNELS 10
18 #define KBUF_SIZE 65536
19 
20 /* Internal struct to simulate a stream for sector-based disks */
21 struct disk_stream {
22 	/* Disk handle */
23 	vb2ex_disk_handle_t handle;
24 
25 	/* Next sector to read */
26 	uint64_t sector;
27 
28 	/* Number of sectors left */
29 	uint64_t sectors_left;
30 };
31 
32 /* Represent a "kernel" located on the disk */
33 struct mock_kernel {
34 	/* Sector where the kernel begins */
35 	uint64_t sector;
36 
37 	/* Return value from vb2_load_partition */
38 	vb2_error_t rv;
39 
40 	/* Number of times the sector was read */
41 	int read_count;
42 };
43 
44 /* Mock data */
45 static struct vb2_context *ctx;
46 static struct vb2_shared_data *sd;
47 static struct vb2_workbuf wb;
48 static uint8_t workbuf[VB2_KERNEL_WORKBUF_RECOMMENDED_SIZE]
49 	__attribute__((aligned(VB2_WORKBUF_ALIGN)));
50 
51 static struct vb2_kernel_params lkp;
52 static struct vb2_disk_info disk_info;
53 static struct vb2_keyblock kbh;
54 static struct vb2_kernel_preamble kph;
55 static uint8_t kernel_buffer[80000];
56 
57 static struct mock_kernel kernels[MAX_MOCK_KERNELS];
58 static int kernel_count;
59 static struct mock_kernel *cur_kernel;
60 
add_mock_kernel(uint64_t sector,vb2_error_t rv)61 static void add_mock_kernel(uint64_t sector, vb2_error_t rv)
62 {
63 	if (kernel_count >= ARRAY_SIZE(kernels)) {
64 		TEST_TRUE(0, "  kernel_count ran out of entries!");
65 		return;
66 	}
67 
68 	kernels[kernel_count].sector = sector;
69 	kernels[kernel_count].rv = rv;
70 	kernel_count++;
71 }
72 
reset_common_data(void)73 static void reset_common_data(void)
74 {
75 	TEST_SUCC(vb2api_init(workbuf, sizeof(workbuf), &ctx),
76 		  "vb2api_init failed");
77 	vb2_workbuf_from_ctx(ctx, &wb);
78 	vb2_nv_init(ctx);
79 	vb2api_secdata_kernel_create(ctx);
80 	vb2_secdata_kernel_init(ctx);
81 	ctx->flags = VB2_CONTEXT_RECOVERY_MODE;
82 
83 	SET_BOOT_MODE(ctx, VB2_BOOT_MODE_MANUAL_RECOVERY,
84 		      VB2_RECOVERY_RO_MANUAL);
85 
86 	sd = vb2_get_sd(ctx);
87 	sd->kernel_version_secdata = 0xabcdef | (1 << 24);
88 
89 	memset(&lkp, 0, sizeof(lkp));
90 	lkp.kernel_buffer = kernel_buffer;
91 	lkp.kernel_buffer_size = sizeof(kernel_buffer);
92 
93 	memset(&disk_info, 0, sizeof(disk_info));
94 	disk_info.bytes_per_lba = 512;
95 	disk_info.lba_count = 1024;
96 	disk_info.handle = (vb2ex_disk_handle_t)1;
97 
98 	memset(&kbh, 0, sizeof(kbh));
99 	kbh.data_key.key_version = 2;
100 	kbh.keyblock_flags = VB2_KEYBLOCK_FLAG_DEVELOPER_0
101 		| VB2_KEYBLOCK_FLAG_DEVELOPER_1
102 		| VB2_KEYBLOCK_FLAG_RECOVERY_1
103 		| VB2_KEYBLOCK_FLAG_MINIOS_1;
104 	kbh.keyblock_size = sizeof(kbh);
105 
106 	memset(&kph, 0, sizeof(kph));
107 	kph.kernel_version = 1;
108 	kph.preamble_size = 4096 - kbh.keyblock_size;
109 	kph.body_signature.data_size = 0;
110 	kph.bootloader_address = 0xbeadd008;
111 	kph.bootloader_size = 0x1234;
112 
113 
114 	memset(&kernels, 0, sizeof(kernels));
115 	kernel_count = 0;
116 	cur_kernel = NULL;
117 }
118 
119 /* Mocks */
120 
VbExStreamOpen(vb2ex_disk_handle_t handle,uint64_t lba_start,uint64_t lba_count,VbExStream_t * stream)121 vb2_error_t VbExStreamOpen(vb2ex_disk_handle_t handle, uint64_t lba_start,
122 			   uint64_t lba_count, VbExStream_t *stream)
123 {
124 	struct disk_stream *s;
125 	uint64_t i;
126 
127 	if (!handle) {
128 		*stream = NULL;
129 		return VB2_ERROR_UNKNOWN;
130 	}
131 
132 	if (lba_start + lba_count > disk_info.lba_count)
133 		return VB2_ERROR_UNKNOWN;
134 
135 	s = malloc(sizeof(*s));
136 	s->handle = handle;
137 	s->sector = lba_start;
138 	s->sectors_left = lba_count;
139 
140 	*stream = (void *)s;
141 
142 	for (i = 0; i < kernel_count; i++) {
143 		if (kernels[i].sector == lba_start)
144 			cur_kernel = &kernels[i];
145 	}
146 
147 	return VB2_SUCCESS;
148 }
149 
VbExStreamRead(VbExStream_t stream,uint32_t bytes,void * buffer)150 vb2_error_t VbExStreamRead(VbExStream_t stream, uint32_t bytes, void *buffer)
151 {
152 	struct disk_stream *s = (struct disk_stream *)stream;
153 	uint64_t sectors;
154 	uint64_t i;
155 
156 	if (!s)
157 		return VB2_ERROR_UNKNOWN;
158 
159 	/* For now, require reads to be a multiple of the LBA size */
160 	if (bytes % disk_info.bytes_per_lba)
161 		return VB2_ERROR_UNKNOWN;
162 
163 	/* Fail on overflow */
164 	sectors = bytes / disk_info.bytes_per_lba;
165 	if (sectors > s->sectors_left)
166 		return VB2_ERROR_UNKNOWN;
167 
168 	memset(buffer, 0, bytes);
169 	for (i = 0; i < kernel_count; i++) {
170 		if (kernels[i].sector >= s->sector &&
171 		    kernels[i].sector < s->sector + sectors) {
172 			VB2_DEBUG("Simulating kernel %" PRIu64 " match\n", i);
173 			uint64_t buf_offset = (kernels[i].sector - s->sector)
174 				* disk_info.bytes_per_lba;
175 			memcpy(buffer + buf_offset, VB2_KEYBLOCK_MAGIC,
176 			       VB2_KEYBLOCK_MAGIC_SIZE);
177 			kernels[i].read_count++;
178 			TEST_TRUE(kernels[i].read_count <= 2,
179 				  "  Max read count exceeded");
180 		}
181 	}
182 
183 	s->sector += sectors;
184 	s->sectors_left -= sectors;
185 
186 	return VB2_SUCCESS;
187 }
188 
VbExStreamClose(VbExStream_t stream)189 void VbExStreamClose(VbExStream_t stream)
190 {
191 	free(stream);
192 }
193 
vb2_unpack_key_buffer(struct vb2_public_key * key,const uint8_t * buf,uint32_t size)194 vb2_error_t vb2_unpack_key_buffer(struct vb2_public_key *key,
195 				  const uint8_t *buf, uint32_t size)
196 {
197 	return cur_kernel->rv;
198 }
199 
vb2_verify_keyblock(struct vb2_keyblock * block,uint32_t size,const struct vb2_public_key * key,const struct vb2_workbuf * w)200 vb2_error_t vb2_verify_keyblock(struct vb2_keyblock *block, uint32_t size,
201 				const struct vb2_public_key *key,
202 				const struct vb2_workbuf *w)
203 {
204 	/* Use this as an opportunity to override the keyblock */
205 	memcpy((void *)block, &kbh, sizeof(kbh));
206 
207 	return cur_kernel->rv;
208 }
209 
vb2_verify_keyblock_hash(const struct vb2_keyblock * block,uint32_t size,const struct vb2_workbuf * w)210 vb2_error_t vb2_verify_keyblock_hash(const struct vb2_keyblock *block,
211 				     uint32_t size,
212 				     const struct vb2_workbuf *w)
213 {
214 	/* Use this as an opportunity to override the keyblock */
215 	memcpy((void *)block, &kbh, sizeof(kbh));
216 
217 	return cur_kernel->rv;
218 }
219 
vb2_verify_kernel_preamble(struct vb2_kernel_preamble * preamble,uint32_t size,const struct vb2_public_key * key,const struct vb2_workbuf * w)220 vb2_error_t vb2_verify_kernel_preamble(struct vb2_kernel_preamble *preamble,
221 			       uint32_t size, const struct vb2_public_key *key,
222 			       const struct vb2_workbuf *w)
223 {
224 	/* Use this as an opportunity to override the preamble */
225 	memcpy((void *)preamble, &kph, sizeof(kph));
226 
227 	return cur_kernel->rv;
228 }
229 
vb2_verify_data(const uint8_t * data,uint32_t size,struct vb2_signature * sig,const struct vb2_public_key * key,const struct vb2_workbuf * w)230 vb2_error_t vb2_verify_data(const uint8_t *data, uint32_t size,
231 			    struct vb2_signature *sig,
232 			    const struct vb2_public_key *key,
233 			    const struct vb2_workbuf *w)
234 {
235 	return cur_kernel->rv;
236 }
237 
vb2_digest_finalize(struct vb2_digest_context * dc,uint8_t * digest,uint32_t digest_size)238 vb2_error_t vb2_digest_finalize(struct vb2_digest_context *dc, uint8_t *digest,
239 				uint32_t digest_size)
240 {
241 	return cur_kernel->rv;
242 }
243 
244 /* Make sure nothing tested here ever calls this directly. */
vb2api_fail(struct vb2_context * c,uint8_t reason,uint8_t subcode)245 void vb2api_fail(struct vb2_context *c, uint8_t reason, uint8_t subcode)
246 {
247 	TEST_TRUE(0, "  called vb2api_fail()");
248 }
249 
250 /* Tests */
251 
load_minios_kernel_tests(void)252 static void load_minios_kernel_tests(void)
253 {
254 	reset_common_data();
255 	disk_info.bytes_per_lba = KBUF_SIZE;
256 	disk_info.lba_count = 1;
257 	add_mock_kernel(0, VB2_SUCCESS);
258 	TEST_SUCC(vb2api_load_minios_kernel(ctx, &lkp, &disk_info, 0),
259 		  "{valid kernel}");
260 	TEST_PTR_EQ(lkp.disk_handle, disk_info.handle,
261 		    "  fill disk_handle when success");
262 
263 	reset_common_data();
264 	disk_info.bytes_per_lba = KBUF_SIZE;
265 	disk_info.lba_count = 1;
266 	TEST_EQ(vb2api_load_minios_kernel(ctx, &lkp, &disk_info, 0),
267 		VB2_ERROR_LK_NO_KERNEL_FOUND, "{no kernel}");
268 
269 	reset_common_data();
270 	disk_info.bytes_per_lba = KBUF_SIZE;
271 	disk_info.lba_count = 2;
272 	add_mock_kernel(1, VB2_SUCCESS);
273 	TEST_SUCC(vb2api_load_minios_kernel(ctx, &lkp, &disk_info, 0),
274 		  "{no kernel, valid kernel}");
275 	TEST_EQ(cur_kernel->sector, 1, "  select kernel");
276 	TEST_PTR_EQ(lkp.disk_handle, disk_info.handle,
277 		    "  fill disk_handle when success");
278 
279 	reset_common_data();
280 	disk_info.bytes_per_lba = KBUF_SIZE;
281 	disk_info.lba_count = 2;
282 	add_mock_kernel(0, VB2_ERROR_MOCK);
283 	add_mock_kernel(1, VB2_SUCCESS);
284 	TEST_SUCC(vb2api_load_minios_kernel(ctx, &lkp, &disk_info, 0),
285 		  "{invalid kernel, valid kernel}");
286 	TEST_EQ(cur_kernel->sector, 1, "  select second kernel");
287 	TEST_PTR_EQ(lkp.disk_handle, disk_info.handle,
288 		    "  fill disk_handle when success");
289 
290 	reset_common_data();
291 	disk_info.bytes_per_lba = KBUF_SIZE;
292 	disk_info.lba_count = 2;
293 	add_mock_kernel(0, VB2_ERROR_MOCK);
294 	add_mock_kernel(1, VB2_ERROR_MOCK);
295 	TEST_EQ(vb2api_load_minios_kernel(ctx, &lkp, &disk_info, 0),
296 		VB2_ERROR_LK_NO_KERNEL_FOUND,
297 		"{invalid kernel, invalid kernel}");
298 
299 	reset_common_data();
300 	disk_info.bytes_per_lba = KBUF_SIZE;
301 	disk_info.lba_count = 2;
302 	add_mock_kernel(0, VB2_SUCCESS);
303 	add_mock_kernel(1, VB2_SUCCESS);
304 	TEST_SUCC(vb2api_load_minios_kernel(ctx, &lkp, &disk_info, 0),
305 		  "{valid kernel, valid kernel} minios_priority=0");
306 	TEST_EQ(cur_kernel->sector, 0, "  select first kernel");
307 	TEST_PTR_EQ(lkp.disk_handle, disk_info.handle,
308 		    "  fill disk_handle when success");
309 
310 	reset_common_data();
311 	disk_info.bytes_per_lba = KBUF_SIZE;
312 	disk_info.lba_count = 2;
313 	add_mock_kernel(0, VB2_SUCCESS);
314 	add_mock_kernel(1, VB2_SUCCESS);
315 	vb2_nv_set(ctx, VB2_NV_MINIOS_PRIORITY, 1);
316 	TEST_SUCC(vb2api_load_minios_kernel(ctx, &lkp, &disk_info, 0),
317 		  "{valid kernel, valid kernel} minios_priority=1");
318 	TEST_EQ(cur_kernel->sector, 1, "  select second kernel");
319 	TEST_PTR_EQ(lkp.disk_handle, disk_info.handle,
320 		    "  fill disk_handle when success");
321 
322 	reset_common_data();
323 	disk_info.bytes_per_lba = KBUF_SIZE;
324 	disk_info.lba_count = 2;
325 	add_mock_kernel(0, VB2_SUCCESS);
326 	add_mock_kernel(1, VB2_SUCCESS);
327 	TEST_SUCC(vb2api_load_minios_kernel(ctx, &lkp, &disk_info,
328 					    VB2_MINIOS_FLAG_NON_ACTIVE),
329 		  "{valid kernel, valid kernel} minios_priority=0 non-active");
330 	TEST_EQ(cur_kernel->sector, 1, "  select second kernel");
331 	TEST_PTR_EQ(lkp.disk_handle, disk_info.handle,
332 		    "  fill disk_handle when success");
333 
334 	reset_common_data();
335 	disk_info.bytes_per_lba = KBUF_SIZE;
336 	disk_info.lba_count = 2;
337 	add_mock_kernel(0, VB2_ERROR_MOCK);
338 	add_mock_kernel(1, VB2_SUCCESS);
339 	vb2_nv_set(ctx, VB2_NV_MINIOS_PRIORITY, 1);
340 	TEST_EQ(vb2api_load_minios_kernel(ctx, &lkp, &disk_info,
341 					  VB2_MINIOS_FLAG_NON_ACTIVE),
342 		VB2_ERROR_LK_NO_KERNEL_FOUND,
343 		"{invalid kernel, valid kernel} minios_priority=1 non-active");
344 
345 	reset_common_data();
346 	disk_info.bytes_per_lba = VB2_KEYBLOCK_MAGIC_SIZE;
347 	disk_info.lba_count = 4;
348 	add_mock_kernel(1, VB2_SUCCESS);
349 	TEST_EQ(vb2api_load_minios_kernel(ctx, &lkp, &disk_info, 0),
350 		VB2_ERROR_LK_NO_KERNEL_FOUND,
351 		"valid kernel header near start of disk (disk too small)");
352 
353 	reset_common_data();
354 	disk_info.bytes_per_lba = VB2_KEYBLOCK_MAGIC_SIZE;
355 	disk_info.lba_count = 1000;
356 	add_mock_kernel(999, VB2_SUCCESS);
357 	TEST_EQ(vb2api_load_minios_kernel(ctx, &lkp, &disk_info, 0),
358 		VB2_ERROR_LK_NO_KERNEL_FOUND,
359 		"valid kernel header near end of disk");
360 
361 	reset_common_data();
362 	disk_info.bytes_per_lba = 1024;
363 	disk_info.lba_count = 128;
364 	add_mock_kernel(63, VB2_SUCCESS);
365 	TEST_SUCC(vb2api_load_minios_kernel(ctx, &lkp, &disk_info, 0),
366 		  "start/end overlap assuming >128 MB search range (start)");
367 	TEST_PTR_EQ(lkp.disk_handle, disk_info.handle,
368 		    "  fill disk_handle when success");
369 
370 	reset_common_data();
371 	disk_info.bytes_per_lba = 1024;
372 	disk_info.lba_count = 128;
373 	add_mock_kernel(64, VB2_SUCCESS);
374 	TEST_SUCC(vb2api_load_minios_kernel(ctx, &lkp, &disk_info, 0),
375 		  "start/end overlap assuming >128 MB search range (end)");
376 	TEST_PTR_EQ(lkp.disk_handle, disk_info.handle,
377 		    "  fill disk_handle when success");
378 
379 	reset_common_data();
380 	disk_info.bytes_per_lba = 128;
381 	disk_info.lba_count = 1024;
382 	add_mock_kernel(3, VB2_SUCCESS);
383 	TEST_SUCC(vb2api_load_minios_kernel(ctx, &lkp, &disk_info, 0),
384 		  "kernel at last sector in batch assuming 512 KB batches");
385 	TEST_PTR_EQ(lkp.disk_handle, disk_info.handle,
386 		    "  fill disk_handle when success");
387 
388 	reset_common_data();
389 	disk_info.bytes_per_lba = 256;
390 	disk_info.lba_count = 1024;
391 	add_mock_kernel(3, VB2_SUCCESS);
392 	TEST_SUCC(vb2api_load_minios_kernel(ctx, &lkp, &disk_info, 0),
393 		  "kernel at last sector in batch assuming 1 MB batches");
394 	TEST_PTR_EQ(lkp.disk_handle, disk_info.handle,
395 		    "  fill disk_handle when success");
396 
397 	reset_common_data();
398 	disk_info.bytes_per_lba = 512;
399 	disk_info.lba_count = 1024;
400 	add_mock_kernel(3, VB2_SUCCESS);
401 	TEST_SUCC(vb2api_load_minios_kernel(ctx, &lkp, &disk_info, 0),
402 		  "kernel at last sector in batch assuming 2 MB batches");
403 	TEST_PTR_EQ(lkp.disk_handle, disk_info.handle,
404 		    "  fill disk_handle when success");
405 
406 	reset_common_data();
407 	kbh.keyblock_flags = VB2_KEYBLOCK_FLAG_DEVELOPER_0
408 		| VB2_KEYBLOCK_FLAG_RECOVERY_1
409 		| VB2_KEYBLOCK_FLAG_MINIOS_1;
410 	disk_info.bytes_per_lba = KBUF_SIZE;
411 	disk_info.lba_count = 2;
412 	add_mock_kernel(0, VB2_SUCCESS);
413 	TEST_SUCC(vb2api_load_minios_kernel(ctx, &lkp, &disk_info, 0),
414 		  "kernel with minios keyblock flag");
415 	TEST_PTR_EQ(lkp.disk_handle, disk_info.handle,
416 		    "  fill disk_handle when success");
417 
418 	reset_common_data();
419 	kbh.keyblock_flags = VB2_KEYBLOCK_FLAG_DEVELOPER_0
420 		| VB2_KEYBLOCK_FLAG_RECOVERY_1
421 		| VB2_KEYBLOCK_FLAG_MINIOS_0;
422 	disk_info.bytes_per_lba = KBUF_SIZE;
423 	disk_info.lba_count = 2;
424 	add_mock_kernel(0, VB2_SUCCESS);
425 	TEST_EQ(vb2api_load_minios_kernel(ctx, &lkp, &disk_info, 0),
426 		VB2_ERROR_LK_NO_KERNEL_FOUND,
427 		"kernel with !minios keyblock flag");
428 
429 	reset_common_data();
430 	disk_info.bytes_per_lba = KBUF_SIZE;
431 	disk_info.lba_count = 2;
432 	add_mock_kernel(0, VB2_SUCCESS);
433 	sd->kernel_version_secdata = 5 << 24;
434 	kph.kernel_version = 4;
435 	TEST_EQ(vb2api_load_minios_kernel(ctx, &lkp, &disk_info, 0),
436 		VB2_ERROR_LK_NO_KERNEL_FOUND,
437 		"kernel version too old");
438 
439 	reset_common_data();
440 	disk_info.bytes_per_lba = KBUF_SIZE;
441 	disk_info.lba_count = 2;
442 	add_mock_kernel(0, VB2_SUCCESS);
443 	sd->kernel_version_secdata = 5 << 24;
444 	kph.kernel_version = 0x100;
445 	TEST_EQ(vb2api_load_minios_kernel(ctx, &lkp, &disk_info, 0),
446 		VB2_ERROR_LK_NO_KERNEL_FOUND,
447 		"kernel version greater than 0xff");
448 
449 	reset_common_data();
450 	disk_info.bytes_per_lba = KBUF_SIZE;
451 	disk_info.lba_count = 2;
452 	add_mock_kernel(0, VB2_SUCCESS);
453 	sd->kernel_version_secdata = 5 << 24;
454 	kbh.data_key.key_version = 5;
455 	kph.kernel_version = 6;
456 	TEST_SUCC(vb2api_load_minios_kernel(ctx, &lkp, &disk_info, 0),
457 		  "newer kernel version");
458 	TEST_EQ(sd->kernel_version, 0x50006, "  SD kernel version");
459 	TEST_PTR_EQ(lkp.disk_handle, disk_info.handle,
460 		    "  fill disk_handle when success");
461 }
462 
main(void)463 int main(void)
464 {
465 	load_minios_kernel_tests();
466 
467 	return gTestSuccess ? 0 : 255;
468 }
469