vboot_kernel_tests.c revision 2500185a83b453580f187087fffc6376f19f8ff0
1/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
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 vboot_kernel.c
6 */
7
8#include <stdint.h>
9#include <stdio.h>
10#include <stdlib.h>
11#include <string.h>
12
13#include "cgptlib.h"
14#include "gbb_header.h"
15#include "gpt.h"
16#include "host_common.h"
17#include "load_kernel_fw.h"
18#include "test_common.h"
19#include "vboot_api.h"
20#include "vboot_common.h"
21#include "vboot_kernel.h"
22#include "vboot_nvstorage.h"
23
24#define LOGCALL(fmt, args...) sprintf(call_log + strlen(call_log), fmt, ##args)
25#define TEST_CALLS(expect_log) TEST_STR_EQ(call_log, expect_log, "  calls")
26
27/* Mock kernel partition */
28struct mock_part {
29	uint32_t start;
30	uint32_t size;
31};
32
33/* Partition list; ends with a 0-size partition. */
34#define MOCK_PART_COUNT 8
35static struct mock_part mock_parts[MOCK_PART_COUNT];
36static int mock_part_next;
37
38/* Mock data */
39static char call_log[4096];
40static uint8_t kernel_buffer[80000];
41static int disk_read_to_fail;
42static int disk_write_to_fail;
43static int gpt_init_fail;
44static int key_block_verify_fail;  /* 0=ok, 1=sig, 2=hash */
45static int preamble_verify_fail;
46static int verify_data_fail;
47static RSAPublicKey *mock_data_key;
48static int mock_data_key_allocated;
49
50static uint8_t gbb_data[sizeof(GoogleBinaryBlockHeader) + 2048];
51static GoogleBinaryBlockHeader *gbb = (GoogleBinaryBlockHeader*)gbb_data;
52static VbExDiskHandle_t handle;
53static VbNvContext vnc;
54static uint8_t shared_data[VB_SHARED_DATA_MIN_SIZE];
55static VbSharedDataHeader *shared = (VbSharedDataHeader *)shared_data;
56static LoadKernelParams lkp;
57static VbKeyBlockHeader kbh;
58static VbKernelPreambleHeader kph;
59static VbCommonParams cparams;
60
61static void ResetCallLog(void)
62{
63	*call_log = 0;
64}
65
66/**
67 * Reset mock data (for use before each test)
68 */
69static void ResetMocks(void)
70{
71	ResetCallLog();
72
73	disk_read_to_fail = -1;
74	disk_write_to_fail = -1;
75
76	gpt_init_fail = 0;
77	key_block_verify_fail = 0;
78	preamble_verify_fail = 0;
79	verify_data_fail = 0;
80
81	mock_data_key = (RSAPublicKey *)"TestDataKey";
82	mock_data_key_allocated = 0;
83
84	memset(gbb, 0, sizeof(*gbb));
85	gbb->major_version = GBB_MAJOR_VER;
86	gbb->minor_version = GBB_MINOR_VER;
87	gbb->flags = 0;
88
89	memset(&cparams, '\0', sizeof(cparams));
90	cparams.gbb = gbb;
91	cparams.gbb_data = gbb;
92	cparams.gbb_size = sizeof(gbb_data);
93
94	memset(&vnc, 0, sizeof(vnc));
95	VbNvSetup(&vnc);
96	VbNvTeardown(&vnc);                   /* So CRC gets generated */
97
98	memset(&shared_data, 0, sizeof(shared_data));
99	VbSharedDataInit(shared, sizeof(shared_data));
100	shared->kernel_version_tpm = 0x20001;
101
102	memset(&lkp, 0, sizeof(lkp));
103	lkp.nv_context = &vnc;
104	lkp.shared_data_blob = shared;
105	lkp.gbb_data = gbb;
106	lkp.gbb_size = sizeof(gbb_data);
107	lkp.bytes_per_lba = 512;
108	lkp.ending_lba = 1023;
109	lkp.kernel_buffer = kernel_buffer;
110	lkp.kernel_buffer_size = sizeof(kernel_buffer);
111
112	memset(&kbh, 0, sizeof(kbh));
113	kbh.data_key.key_version = 2;
114	kbh.key_block_flags = -1;
115	kbh.key_block_size = sizeof(kbh);
116
117	memset(&kph, 0, sizeof(kph));
118	kph.kernel_version = 1;
119	kph.preamble_size = 4096 - kbh.key_block_size;
120	kph.body_signature.data_size = 70000;
121	kph.bootloader_address = 0xbeadd008;
122	kph.bootloader_size = 0x1234;
123
124	memset(mock_parts, 0, sizeof(mock_parts));
125	mock_parts[0].start = 100;
126	mock_parts[0].size = 150;  /* 75 KB */
127	mock_part_next = 0;
128}
129
130/* Mocks */
131
132VbError_t VbExDiskRead(VbExDiskHandle_t handle, uint64_t lba_start,
133                       uint64_t lba_count, void *buffer)
134{
135	LOGCALL("VbExDiskRead(h, %d, %d)\n", (int)lba_start, (int)lba_count);
136
137	if ((int)lba_start == disk_read_to_fail)
138		return VBERROR_SIMULATED;
139
140	/* Keep valgrind happy */
141	Memset(buffer, '\0', lba_count);
142	return VBERROR_SUCCESS;
143}
144
145VbError_t VbExDiskWrite(VbExDiskHandle_t handle, uint64_t lba_start,
146			uint64_t lba_count, const void *buffer)
147{
148	LOGCALL("VbExDiskWrite(h, %d, %d)\n", (int)lba_start, (int)lba_count);
149
150	if ((int)lba_start == disk_write_to_fail)
151		return VBERROR_SIMULATED;
152
153	return VBERROR_SUCCESS;
154}
155
156int GptInit(GptData *gpt)
157{
158	return gpt_init_fail;
159}
160
161int GptNextKernelEntry(GptData *gpt, uint64_t *start_sector, uint64_t *size)
162{
163	struct mock_part *p = mock_parts + mock_part_next;
164
165	if (!p->size)
166		return GPT_ERROR_NO_VALID_KERNEL;
167
168	gpt->current_kernel = mock_part_next;
169	*start_sector = p->start;
170	*size = p->size;
171	mock_part_next++;
172	return GPT_SUCCESS;
173}
174
175void GetCurrentKernelUniqueGuid(GptData *gpt, void *dest)
176{
177	static char fake_guid[] = "FakeGuid";
178
179	memcpy(dest, fake_guid, sizeof(fake_guid));
180}
181
182int KeyBlockVerify(const VbKeyBlockHeader *block, uint64_t size,
183		   const VbPublicKey *key, int hash_only) {
184
185	if (hash_only && key_block_verify_fail >= 2)
186		return VBERROR_SIMULATED;
187	else if (!hash_only && key_block_verify_fail >= 1)
188		return VBERROR_SIMULATED;
189
190	/* Use this as an opportunity to override the key block */
191	memcpy((void *)block, &kbh, sizeof(kbh));
192	return VBERROR_SUCCESS;
193}
194
195RSAPublicKey *PublicKeyToRSA(const VbPublicKey *key)
196{
197	TEST_EQ(mock_data_key_allocated, 0, "  mock data key not allocated");
198
199	if (mock_data_key)
200		mock_data_key_allocated++;
201
202	return mock_data_key;
203}
204
205void RSAPublicKeyFree(RSAPublicKey* key)
206{
207	TEST_EQ(mock_data_key_allocated, 1, "  mock data key allocated");
208	TEST_PTR_EQ(key, mock_data_key, "  data key ptr");
209	mock_data_key_allocated--;
210}
211
212int VerifyKernelPreamble(const VbKernelPreambleHeader *preamble,
213			 uint64_t size, const RSAPublicKey *key)
214{
215	if (preamble_verify_fail)
216		return VBERROR_SIMULATED;
217
218	/* Use this as an opportunity to override the preamble */
219	memcpy((void *)preamble, &kph, sizeof(kph));
220	return VBERROR_SUCCESS;
221}
222
223int VerifyData(const uint8_t *data, uint64_t size, const VbSignature *sig,
224	       const RSAPublicKey *key)
225{
226	if (verify_data_fail)
227		return VBERROR_SIMULATED;
228
229	return VBERROR_SUCCESS;
230}
231
232
233/**
234 * Test reading/writing GPT
235 */
236static void ReadWriteGptTest(void)
237{
238	GptData g;
239	GptHeader *h;
240
241	g.sector_bytes = 512;
242	g.drive_sectors = 1024;
243
244	ResetMocks();
245	TEST_EQ(AllocAndReadGptData(handle, &g), 0, "AllocAndRead");
246	TEST_CALLS("VbExDiskRead(h, 1, 1)\n"
247		   "VbExDiskRead(h, 2, 32)\n"
248		   "VbExDiskRead(h, 991, 32)\n"
249		   "VbExDiskRead(h, 1023, 1)\n");
250	ResetCallLog();
251	/*
252	 * Valgrind complains about access to uninitialized memory here, so
253	 * zero the primary header before each test.
254	 */
255	Memset(g.primary_header, '\0', g.sector_bytes);
256	TEST_EQ(WriteAndFreeGptData(handle, &g), 0, "WriteAndFree");
257	TEST_CALLS("");
258
259	/* Data which is changed is written */
260	ResetMocks();
261	AllocAndReadGptData(handle, &g);
262	g.modified |= GPT_MODIFIED_HEADER1 | GPT_MODIFIED_ENTRIES1;
263	ResetCallLog();
264	Memset(g.primary_header, '\0', g.sector_bytes);
265	TEST_EQ(WriteAndFreeGptData(handle, &g), 0, "WriteAndFree mod 1");
266	TEST_CALLS("VbExDiskWrite(h, 1, 1)\n"
267		   "VbExDiskWrite(h, 2, 32)\n");
268
269	/* Data which is changed is written */
270	ResetMocks();
271	AllocAndReadGptData(handle, &g);
272	g.modified = -1;
273	ResetCallLog();
274	Memset(g.primary_header, '\0', g.sector_bytes);
275	TEST_EQ(WriteAndFreeGptData(handle, &g), 0, "WriteAndFree mod all");
276	TEST_CALLS("VbExDiskWrite(h, 1, 1)\n"
277		   "VbExDiskWrite(h, 2, 32)\n"
278		   "VbExDiskWrite(h, 991, 32)\n"
279		   "VbExDiskWrite(h, 1023, 1)\n");
280
281	/* If legacy signature, don't modify GPT header/entries 1 */
282	ResetMocks();
283	AllocAndReadGptData(handle, &g);
284	h = (GptHeader *)g.primary_header;
285	memcpy(h->signature, GPT_HEADER_SIGNATURE2, GPT_HEADER_SIGNATURE_SIZE);
286	g.modified = -1;
287	ResetCallLog();
288	TEST_EQ(WriteAndFreeGptData(handle, &g), 0, "WriteAndFree mod all");
289	TEST_CALLS("VbExDiskWrite(h, 991, 32)\n"
290		   "VbExDiskWrite(h, 1023, 1)\n");
291
292	/* Error reading */
293	ResetMocks();
294	disk_read_to_fail = 1;
295	TEST_NEQ(AllocAndReadGptData(handle, &g), 0, "AllocAndRead disk fail");
296	Memset(g.primary_header, '\0', g.sector_bytes);
297	WriteAndFreeGptData(handle, &g);
298
299	ResetMocks();
300	disk_read_to_fail = 2;
301	TEST_NEQ(AllocAndReadGptData(handle, &g), 0, "AllocAndRead disk fail");
302	Memset(g.primary_header, '\0', g.sector_bytes);
303	WriteAndFreeGptData(handle, &g);
304
305	ResetMocks();
306	disk_read_to_fail = 991;
307	TEST_NEQ(AllocAndReadGptData(handle, &g), 0, "AllocAndRead disk fail");
308	Memset(g.primary_header, '\0', g.sector_bytes);
309	WriteAndFreeGptData(handle, &g);
310
311	ResetMocks();
312	disk_read_to_fail = 1023;
313	TEST_NEQ(AllocAndReadGptData(handle, &g), 0, "AllocAndRead disk fail");
314	Memset(g.primary_header, '\0', g.sector_bytes);
315	WriteAndFreeGptData(handle, &g);
316
317	/* Error writing */
318	ResetMocks();
319	disk_write_to_fail = 1;
320	AllocAndReadGptData(handle, &g);
321	g.modified = -1;
322	Memset(g.primary_header, '\0', g.sector_bytes);
323	TEST_NEQ(WriteAndFreeGptData(handle, &g), 0, "WriteAndFree disk fail");
324
325	ResetMocks();
326	disk_write_to_fail = 2;
327	AllocAndReadGptData(handle, &g);
328	g.modified = -1;
329	Memset(g.primary_header, '\0', g.sector_bytes);
330	TEST_NEQ(WriteAndFreeGptData(handle, &g), 0, "WriteAndFree disk fail");
331
332	ResetMocks();
333	disk_write_to_fail = 991;
334	AllocAndReadGptData(handle, &g);
335	g.modified = -1;
336	Memset(g.primary_header, '\0', g.sector_bytes);
337	TEST_NEQ(WriteAndFreeGptData(handle, &g), 0, "WriteAndFree disk fail");
338
339	ResetMocks();
340	disk_write_to_fail = 1023;
341	AllocAndReadGptData(handle, &g);
342	g.modified = -1;
343	Memset(g.primary_header, '\0', g.sector_bytes);
344	TEST_NEQ(WriteAndFreeGptData(handle, &g), 0, "WriteAndFree disk fail");
345
346}
347
348/**
349 * Trivial invalid calls to LoadKernel()
350 */
351static void InvalidParamsTest(void)
352{
353	ResetMocks();
354	lkp.bytes_per_lba = 0;
355	TEST_EQ(LoadKernel(&lkp, &cparams), VBERROR_INVALID_PARAMETER,
356		"Bad lba size");
357
358	ResetMocks();
359	lkp.ending_lba = 0;
360	TEST_EQ(LoadKernel(&lkp, &cparams), VBERROR_INVALID_PARAMETER,
361		"Bad lba count");
362
363	ResetMocks();
364	lkp.bytes_per_lba = 128*1024;
365	TEST_EQ(LoadKernel(&lkp, &cparams), VBERROR_INVALID_PARAMETER,
366		"Huge lba size");
367
368	ResetMocks();
369	disk_read_to_fail = 1;
370	TEST_EQ(LoadKernel(&lkp, &cparams), VBERROR_NO_KERNEL_FOUND,
371		"Can't read disk");
372
373	ResetMocks();
374	gpt_init_fail = 1;
375	TEST_EQ(LoadKernel(&lkp, &cparams), VBERROR_NO_KERNEL_FOUND,
376		"Bad GPT");
377}
378
379static void LoadKernelTest(void)
380{
381	uint32_t u;
382
383	ResetMocks();
384	TEST_EQ(LoadKernel(&lkp, &cparams), 0, "First kernel good");
385	TEST_EQ(lkp.partition_number, 1, "  part num");
386	TEST_EQ(lkp.bootloader_address, 0xbeadd008, "  bootloader addr");
387	TEST_EQ(lkp.bootloader_size, 0x1234, "  bootloader size");
388	TEST_STR_EQ((char *)lkp.partition_guid, "FakeGuid", "  guid");
389	VbNvGet(&vnc, VBNV_RECOVERY_REQUEST, &u);
390	TEST_EQ(u, 0, "  recovery request");
391
392	ResetMocks();
393	mock_parts[1].start = 300;
394	mock_parts[1].size = 150;
395	TEST_EQ(LoadKernel(&lkp, &cparams), 0, "Two good kernels");
396	TEST_EQ(lkp.partition_number, 1, "  part num");
397	TEST_EQ(mock_part_next, 1, "  didn't read second one");
398
399	/* Fail if no kernels found */
400	ResetMocks();
401	mock_parts[0].size = 0;
402	TEST_EQ(LoadKernel(&lkp, &cparams), VBERROR_NO_KERNEL_FOUND, "No kernels");
403	VbNvGet(&vnc, VBNV_RECOVERY_REQUEST, &u);
404	TEST_EQ(u, VBNV_RECOVERY_RW_NO_OS, "  recovery request");
405
406	/* Skip kernels which are too small */
407	ResetMocks();
408	mock_parts[0].size = 10;
409	TEST_EQ(LoadKernel(&lkp, &cparams), VBERROR_INVALID_KERNEL_FOUND, "Too small");
410	VbNvGet(&vnc, VBNV_RECOVERY_REQUEST, &u);
411	TEST_EQ(u, VBNV_RECOVERY_RW_INVALID_OS, "  recovery request");
412
413	ResetMocks();
414	disk_read_to_fail = 100;
415	TEST_EQ(LoadKernel(&lkp, &cparams), VBERROR_INVALID_KERNEL_FOUND,
416		"Fail reading kernel start");
417
418	ResetMocks();
419	key_block_verify_fail = 1;
420	TEST_EQ(LoadKernel(&lkp, &cparams), VBERROR_INVALID_KERNEL_FOUND,
421		"Fail key block sig");
422
423	/* In dev mode, fail if hash is bad too */
424	ResetMocks();
425	lkp.boot_flags |= BOOT_FLAG_DEVELOPER;
426	key_block_verify_fail = 2;
427	TEST_EQ(LoadKernel(&lkp, &cparams), VBERROR_INVALID_KERNEL_FOUND,
428		"Fail key block dev hash");
429
430	/* But just bad sig is ok */
431	ResetMocks();
432	lkp.boot_flags |= BOOT_FLAG_DEVELOPER;
433	key_block_verify_fail = 1;
434	TEST_EQ(LoadKernel(&lkp, &cparams), 0, "Succeed key block dev sig");
435
436	/* In dev mode and requiring signed kernel, fail if sig is bad */
437	ResetMocks();
438	lkp.boot_flags |= BOOT_FLAG_DEVELOPER;
439	VbNvSet(&vnc, VBNV_DEV_BOOT_SIGNED_ONLY, 1);
440	VbNvTeardown(&vnc);
441	key_block_verify_fail = 1;
442	TEST_EQ(LoadKernel(&lkp, &cparams), VBERROR_INVALID_KERNEL_FOUND,
443		"Fail key block dev sig");
444
445	/* Check key block flag mismatches */
446	ResetMocks();
447	kbh.key_block_flags =
448		KEY_BLOCK_FLAG_RECOVERY_0 | KEY_BLOCK_FLAG_DEVELOPER_1;
449	TEST_EQ(LoadKernel(&lkp, &cparams), VBERROR_INVALID_KERNEL_FOUND,
450		"Key block dev flag mismatch");
451
452	ResetMocks();
453	kbh.key_block_flags =
454		KEY_BLOCK_FLAG_RECOVERY_1 | KEY_BLOCK_FLAG_DEVELOPER_0;
455	TEST_EQ(LoadKernel(&lkp, &cparams), VBERROR_INVALID_KERNEL_FOUND,
456		"Key block rec flag mismatch");
457
458	ResetMocks();
459	lkp.boot_flags |= BOOT_FLAG_RECOVERY;
460	kbh.key_block_flags =
461		KEY_BLOCK_FLAG_RECOVERY_1 | KEY_BLOCK_FLAG_DEVELOPER_1;
462	TEST_EQ(LoadKernel(&lkp, &cparams), VBERROR_INVALID_KERNEL_FOUND,
463		"Key block recdev flag mismatch");
464
465	ResetMocks();
466	lkp.boot_flags |= BOOT_FLAG_RECOVERY | BOOT_FLAG_DEVELOPER;
467	kbh.key_block_flags =
468		KEY_BLOCK_FLAG_RECOVERY_1 | KEY_BLOCK_FLAG_DEVELOPER_0;
469	TEST_EQ(LoadKernel(&lkp, &cparams), VBERROR_INVALID_KERNEL_FOUND,
470		"Key block rec!dev flag mismatch");
471
472	ResetMocks();
473	kbh.data_key.key_version = 1;
474	TEST_EQ(LoadKernel(&lkp, &cparams), VBERROR_INVALID_KERNEL_FOUND,
475		"Key block kernel key rollback");
476
477	ResetMocks();
478	kbh.data_key.key_version = 0x10000;
479	TEST_EQ(LoadKernel(&lkp, &cparams), VBERROR_INVALID_KERNEL_FOUND,
480		"Key block kernel key version too big");
481
482	ResetMocks();
483	kbh.data_key.key_version = 3;
484	TEST_EQ(LoadKernel(&lkp, &cparams), 0, "Key block version roll forward");
485	TEST_EQ(shared->kernel_version_tpm, 0x30001, "  shared version");
486
487	ResetMocks();
488	kbh.data_key.key_version = 3;
489	mock_parts[1].start = 300;
490	mock_parts[1].size = 150;
491	TEST_EQ(LoadKernel(&lkp, &cparams), 0, "Two kernels roll forward");
492	TEST_EQ(mock_part_next, 2, "  read both");
493	TEST_EQ(shared->kernel_version_tpm, 0x30001, "  shared version");
494
495	ResetMocks();
496	kbh.data_key.key_version = 1;
497	lkp.boot_flags |= BOOT_FLAG_DEVELOPER;
498	TEST_EQ(LoadKernel(&lkp, &cparams), 0, "Key version ignored in dev mode");
499
500	ResetMocks();
501	kbh.data_key.key_version = 1;
502	lkp.boot_flags |= BOOT_FLAG_RECOVERY;
503	TEST_EQ(LoadKernel(&lkp, &cparams), 0, "Key version ignored in rec mode");
504
505	ResetMocks();
506	mock_data_key = NULL;
507	TEST_EQ(LoadKernel(&lkp, &cparams), VBERROR_INVALID_KERNEL_FOUND,
508		"Bad data key");
509
510	ResetMocks();
511	preamble_verify_fail = 1;
512	TEST_EQ(LoadKernel(&lkp, &cparams), VBERROR_INVALID_KERNEL_FOUND,
513		"Bad preamble");
514
515	ResetMocks();
516	kph.kernel_version = 0;
517	TEST_EQ(LoadKernel(&lkp, &cparams), VBERROR_INVALID_KERNEL_FOUND,
518		"Kernel version rollback");
519
520	ResetMocks();
521	kph.kernel_version = 0;
522	lkp.boot_flags |= BOOT_FLAG_DEVELOPER;
523	TEST_EQ(LoadKernel(&lkp, &cparams), 0, "Kernel version ignored in dev mode");
524
525	ResetMocks();
526	kph.kernel_version = 0;
527	lkp.boot_flags |= BOOT_FLAG_RECOVERY;
528	TEST_EQ(LoadKernel(&lkp, &cparams), 0, "Kernel version ignored in rec mode");
529
530	ResetMocks();
531	kph.preamble_size |= 0x07;
532	TEST_EQ(LoadKernel(&lkp, &cparams), VBERROR_INVALID_KERNEL_FOUND,
533		"Kernel body offset");
534
535	/* Check getting kernel load address from header */
536	ResetMocks();
537	kph.body_load_address = (size_t)kernel_buffer;
538	lkp.kernel_buffer = NULL;
539	TEST_EQ(LoadKernel(&lkp, &cparams), 0, "Get load address from preamble");
540	TEST_PTR_EQ(lkp.kernel_buffer, kernel_buffer, "  address");
541	/* Size is rounded up to nearest sector */
542	TEST_EQ(lkp.kernel_buffer_size, 70144, "  size");
543
544	ResetMocks();
545	lkp.kernel_buffer_size = 8192;
546	TEST_EQ(LoadKernel(&lkp, &cparams), VBERROR_INVALID_KERNEL_FOUND,
547		"Kernel too big for buffer");
548
549	ResetMocks();
550	mock_parts[0].size = 130;
551	TEST_EQ(LoadKernel(&lkp, &cparams), VBERROR_INVALID_KERNEL_FOUND,
552		"Kernel too big for partition");
553
554	ResetMocks();
555	disk_read_to_fail = 108;
556	TEST_EQ(LoadKernel(&lkp, &cparams), VBERROR_INVALID_KERNEL_FOUND,
557		"Fail reading kernel data");
558
559	ResetMocks();
560	verify_data_fail = 1;
561	TEST_EQ(LoadKernel(&lkp, &cparams), VBERROR_INVALID_KERNEL_FOUND,	"Bad data");
562}
563
564int main(void)
565{
566	ReadWriteGptTest();
567	InvalidParamsTest();
568	LoadKernelTest();
569
570	if (vboot_api_stub_check_memory())
571		return 255;
572
573	return gTestSuccess ? 0 : 255;
574}
575