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