blob: 7e7beca69784b714d22e7baaf96f1c55685c7693 [file] [log] [blame]
Randall Spangler49cb0d32013-01-29 14:28:16 -08001/* 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 <stdio.h>
9#include <stdlib.h>
10#include <string.h>
11
12#include "cgptlib.h"
13#include "gbb_header.h"
14#include "gpt.h"
15#include "host_common.h"
16#include "load_kernel_fw.h"
17#include "test_common.h"
18#include "vboot_api.h"
19#include "vboot_common.h"
20#include "vboot_kernel.h"
21#include "vboot_nvstorage.h"
22
23#define LOGCALL(fmt, args...) sprintf(call_log + strlen(call_log), fmt, ##args)
24#define TEST_CALLS(expect_log) TEST_STR_EQ(call_log, expect_log, " calls")
25
Randall Spangler5d0a2e72013-01-30 13:19:19 -080026/* Mock kernel partition */
27struct mock_part {
28 uint32_t start;
29 uint32_t size;
30};
31
32/* Partition list; ends with a 0-size partition. */
33#define MOCK_PART_COUNT 8
34static struct mock_part mock_parts[MOCK_PART_COUNT];
35static int mock_part_next;
36
Randall Spangler49cb0d32013-01-29 14:28:16 -080037/* Mock data */
38static char call_log[4096];
Randall Spangler5d0a2e72013-01-30 13:19:19 -080039static uint8_t kernel_buffer[80000];
40static int disk_read_to_fail;
41static int disk_write_to_fail;
Randall Spangler49cb0d32013-01-29 14:28:16 -080042static int gpt_init_fail;
Randall Spangler5d0a2e72013-01-30 13:19:19 -080043static int key_block_verify_fail; /* 0=ok, 1=sig, 2=hash */
44static int preamble_verify_fail;
45static RSAPublicKey *mock_data_key;
46static int mock_data_key_allocated;
Randall Spangler49cb0d32013-01-29 14:28:16 -080047
48static GoogleBinaryBlockHeader gbb;
49static VbExDiskHandle_t handle;
50static VbNvContext vnc;
51static uint8_t shared_data[VB_SHARED_DATA_MIN_SIZE];
52static VbSharedDataHeader *shared = (VbSharedDataHeader *)shared_data;
53static LoadKernelParams lkp;
Randall Spangler5d0a2e72013-01-30 13:19:19 -080054static VbKeyBlockHeader kbh;
55static VbKernelPreambleHeader kph;
Randall Spangler49cb0d32013-01-29 14:28:16 -080056
57static void ResetCallLog(void)
58{
59 *call_log = 0;
60}
61
62/**
63 * Reset mock data (for use before each test)
64 */
65static void ResetMocks(void)
66{
67 ResetCallLog();
68
Randall Spangler5d0a2e72013-01-30 13:19:19 -080069 disk_read_to_fail = -1;
70 disk_write_to_fail = -1;
Randall Spangler49cb0d32013-01-29 14:28:16 -080071
72 gpt_init_fail = 0;
Randall Spangler5d0a2e72013-01-30 13:19:19 -080073 key_block_verify_fail = 0;
74 preamble_verify_fail = 0;
75
76 mock_data_key = (RSAPublicKey *)"TestDataKey";
77 mock_data_key_allocated = 0;
Randall Spangler49cb0d32013-01-29 14:28:16 -080078
79 memset(&gbb, 0, sizeof(gbb));
80 gbb.major_version = GBB_MAJOR_VER;
81 gbb.minor_version = GBB_MINOR_VER;
82 gbb.flags = 0;
83
84 memset(&vnc, 0, sizeof(vnc));
85 VbNvSetup(&vnc);
86 VbNvTeardown(&vnc); /* So CRC gets generated */
87
88 memset(&shared_data, 0, sizeof(shared_data));
89 VbSharedDataInit(shared, sizeof(shared_data));
Randall Spangler5d0a2e72013-01-30 13:19:19 -080090 shared->kernel_version_tpm = 0x20001;
Randall Spangler49cb0d32013-01-29 14:28:16 -080091
92 memset(&lkp, 0, sizeof(lkp));
93 lkp.nv_context = &vnc;
94 lkp.shared_data_blob = shared;
95 lkp.gbb_data = &gbb;
96 lkp.bytes_per_lba = 512;
97 lkp.ending_lba = 1023;
Randall Spangler5d0a2e72013-01-30 13:19:19 -080098 lkp.kernel_buffer = kernel_buffer;
99 lkp.kernel_buffer_size = sizeof(kernel_buffer);
100
101 memset(&kbh, 0, sizeof(kbh));
102 kbh.data_key.key_version = 2;
103 kbh.key_block_flags = -1;
104 kbh.key_block_size = sizeof(kbh);
105
106 memset(&kph, 0, sizeof(kph));
107 kph.kernel_version = 1;
108 kph.preamble_size = 4096 - kbh.key_block_size;
109 kph.body_signature.data_size = 70000;
110
111 memset(mock_parts, 0, sizeof(mock_parts));
112 mock_parts[0].start = 100;
113 mock_parts[0].size = 150; /* 75 KB */
114 mock_part_next = 0;
Randall Spangler49cb0d32013-01-29 14:28:16 -0800115}
116
117/* Mocks */
118
119VbError_t VbExDiskRead(VbExDiskHandle_t handle, uint64_t lba_start,
120 uint64_t lba_count, void *buffer)
121{
122 LOGCALL("VbExDiskRead(h, %d, %d)\n", (int)lba_start, (int)lba_count);
123
Randall Spangler5d0a2e72013-01-30 13:19:19 -0800124 if ((int)lba_start == disk_read_to_fail)
Randall Spangler49cb0d32013-01-29 14:28:16 -0800125 return VBERROR_SIMULATED;
126
127 return VBERROR_SUCCESS;
128}
129
130VbError_t VbExDiskWrite(VbExDiskHandle_t handle, uint64_t lba_start,
131 uint64_t lba_count, const void *buffer)
132{
133 LOGCALL("VbExDiskWrite(h, %d, %d)\n", (int)lba_start, (int)lba_count);
134
Randall Spangler5d0a2e72013-01-30 13:19:19 -0800135 if ((int)lba_start == disk_write_to_fail)
Randall Spangler49cb0d32013-01-29 14:28:16 -0800136 return VBERROR_SIMULATED;
137
138 return VBERROR_SUCCESS;
139}
140
141int GptInit(GptData *gpt)
142{
143 return gpt_init_fail;
144}
145
Randall Spangler5d0a2e72013-01-30 13:19:19 -0800146int GptNextKernelEntry(GptData *gpt, uint64_t *start_sector, uint64_t *size)
147{
148 struct mock_part *p = mock_parts + mock_part_next;
149
150 if (!p->size)
151 return GPT_ERROR_NO_VALID_KERNEL;
152
153 gpt->current_kernel = mock_part_next;
154 *start_sector = p->start;
155 *size = p->size;
156 mock_part_next++;
157 return GPT_SUCCESS;
158}
159
160int KeyBlockVerify(const VbKeyBlockHeader *block, uint64_t size,
161 const VbPublicKey *key, int hash_only) {
162
163 if (hash_only && key_block_verify_fail >= 2)
164 return VBERROR_SIMULATED;
165 else if (!hash_only && key_block_verify_fail >= 1)
166 return VBERROR_SIMULATED;
167
168 /* Use this as an opportunity to override the key block */
169 memcpy((void *)block, &kbh, sizeof(kbh));
170 return VBERROR_SUCCESS;
171}
172
173RSAPublicKey *PublicKeyToRSA(const VbPublicKey *key)
174{
175 TEST_EQ(mock_data_key_allocated, 0, " mock data key not allocated");
176
177 if (mock_data_key)
178 mock_data_key_allocated++;
179
180 return mock_data_key;
181}
182
183void RSAPublicKeyFree(RSAPublicKey* key)
184{
185 TEST_EQ(mock_data_key_allocated, 1, " mock data key allocated");
186 TEST_PTR_EQ(key, mock_data_key, " data key ptr");
187 mock_data_key_allocated--;
188}
189
190int VerifyKernelPreamble(const VbKernelPreambleHeader *preamble,
191 uint64_t size, const RSAPublicKey *key)
192{
193 if (preamble_verify_fail)
194 return VBERROR_SIMULATED;
195
196 /* Use this as an opportunity to override the preamble */
197 memcpy((void *)preamble, &kph, sizeof(kph));
198 return VBERROR_SUCCESS;
199}
200
Randall Spangler49cb0d32013-01-29 14:28:16 -0800201/**
202 * Test reading/writing GPT
203 */
204static void ReadWriteGptTest(void)
205{
206 GptData g;
207 GptHeader *h;
208
209 g.sector_bytes = 512;
210 g.drive_sectors = 1024;
211
212 ResetMocks();
213 TEST_EQ(AllocAndReadGptData(handle, &g), 0, "AllocAndRead");
214 TEST_CALLS("VbExDiskRead(h, 1, 1)\n"
215 "VbExDiskRead(h, 2, 32)\n"
216 "VbExDiskRead(h, 991, 32)\n"
217 "VbExDiskRead(h, 1023, 1)\n");
218 ResetCallLog();
219 TEST_EQ(WriteAndFreeGptData(handle, &g), 0, "WriteAndFree");
220 TEST_CALLS("");
221
222 /* Data which is changed is written */
223 ResetMocks();
224 AllocAndReadGptData(handle, &g);
225 g.modified |= GPT_MODIFIED_HEADER1 | GPT_MODIFIED_ENTRIES1;
226 ResetCallLog();
227 TEST_EQ(WriteAndFreeGptData(handle, &g), 0, "WriteAndFree mod 1");
228 TEST_CALLS("VbExDiskWrite(h, 1, 1)\n"
229 "VbExDiskWrite(h, 2, 32)\n");
230
231 /* Data which is changed is written */
232 ResetMocks();
233 AllocAndReadGptData(handle, &g);
234 g.modified = -1;
235 ResetCallLog();
236 TEST_EQ(WriteAndFreeGptData(handle, &g), 0, "WriteAndFree mod all");
237 TEST_CALLS("VbExDiskWrite(h, 1, 1)\n"
238 "VbExDiskWrite(h, 2, 32)\n"
239 "VbExDiskWrite(h, 991, 32)\n"
240 "VbExDiskWrite(h, 1023, 1)\n");
241
242 /* If legacy signature, don't modify GPT header/entries 1 */
243 ResetMocks();
244 AllocAndReadGptData(handle, &g);
245 h = (GptHeader *)g.primary_header;
246 memcpy(h->signature, GPT_HEADER_SIGNATURE2, GPT_HEADER_SIGNATURE_SIZE);
247 g.modified = -1;
248 ResetCallLog();
249 TEST_EQ(WriteAndFreeGptData(handle, &g), 0, "WriteAndFree mod all");
250 TEST_CALLS("VbExDiskWrite(h, 991, 32)\n"
251 "VbExDiskWrite(h, 1023, 1)\n");
252
253 /* Error reading */
254 ResetMocks();
Randall Spangler5d0a2e72013-01-30 13:19:19 -0800255 disk_read_to_fail = 1;
Randall Spangler49cb0d32013-01-29 14:28:16 -0800256 TEST_NEQ(AllocAndReadGptData(handle, &g), 0, "AllocAndRead disk fail");
257 WriteAndFreeGptData(handle, &g);
258
259 /* Error writing */
260 ResetMocks();
Randall Spangler5d0a2e72013-01-30 13:19:19 -0800261 disk_write_to_fail = 1;
Randall Spangler49cb0d32013-01-29 14:28:16 -0800262 AllocAndReadGptData(handle, &g);
263 g.modified = -1;
264 TEST_NEQ(WriteAndFreeGptData(handle, &g), 0, "WriteAndFree disk fail");
265}
266
267/**
268 * Trivial invalid calls to LoadKernel()
269 */
270static void InvalidParamsTest(void)
271{
272 ResetMocks();
273 lkp.bytes_per_lba = 0;
274 TEST_EQ(LoadKernel(&lkp), VBERROR_INVALID_PARAMETER, "Bad lba size");
275
276 ResetMocks();
277 lkp.ending_lba = 0;
278 TEST_EQ(LoadKernel(&lkp), VBERROR_INVALID_PARAMETER, "Bad lba count");
279
280 ResetMocks();
281 lkp.bytes_per_lba = 128*1024;
282 TEST_EQ(LoadKernel(&lkp), VBERROR_INVALID_PARAMETER, "Huge lba size");
283
284 ResetMocks();
Randall Spangler5d0a2e72013-01-30 13:19:19 -0800285 disk_read_to_fail = 1;
Randall Spangler49cb0d32013-01-29 14:28:16 -0800286 TEST_EQ(LoadKernel(&lkp), VBERROR_NO_KERNEL_FOUND, "Can't read disk");
287
288 ResetMocks();
289 gpt_init_fail = 1;
290 TEST_EQ(LoadKernel(&lkp), VBERROR_NO_KERNEL_FOUND, "Bad GPT");
291}
292
Randall Spangler5d0a2e72013-01-30 13:19:19 -0800293static void KernelLoopTest(void)
294{
295 /* Fail if no kernels found */
296 ResetMocks();
297 mock_parts[0].size = 0;
298 TEST_EQ(LoadKernel(&lkp), VBERROR_NO_KERNEL_FOUND, "No kernels");
299
300 /* Skip kernels which are too small */
301 ResetMocks();
302 mock_parts[0].size = 10;
303 TEST_EQ(LoadKernel(&lkp), VBERROR_INVALID_KERNEL_FOUND, "Too small");
304
305 ResetMocks();
306 disk_read_to_fail = 100;
307 TEST_EQ(LoadKernel(&lkp), VBERROR_INVALID_KERNEL_FOUND,
308 "Fail reading kernel start");
309
310 ResetMocks();
311 key_block_verify_fail = 1;
312 TEST_EQ(LoadKernel(&lkp), VBERROR_INVALID_KERNEL_FOUND,
313 "Fail key block sig");
314
315 /* In dev mode, fail if hash is bad too */
316 ResetMocks();
317 lkp.boot_flags |= BOOT_FLAG_DEVELOPER;
318 key_block_verify_fail = 2;
319 TEST_EQ(LoadKernel(&lkp), VBERROR_INVALID_KERNEL_FOUND,
320 "Fail key block dev hash");
321
322 /* In dev mode and requiring signed kernel, fail if sig is bad */
323 ResetMocks();
324 lkp.boot_flags |= BOOT_FLAG_DEVELOPER;
325 VbNvSet(&vnc, VBNV_DEV_BOOT_SIGNED_ONLY, 1);
326 VbNvTeardown(&vnc);
327 key_block_verify_fail = 1;
328 TEST_EQ(LoadKernel(&lkp), VBERROR_INVALID_KERNEL_FOUND,
329 "Fail key block dev sig");
330
331 /* Check key block flag mismatches */
332 ResetMocks();
333 kbh.key_block_flags =
334 KEY_BLOCK_FLAG_RECOVERY_0 | KEY_BLOCK_FLAG_DEVELOPER_1;
335 TEST_EQ(LoadKernel(&lkp), VBERROR_INVALID_KERNEL_FOUND,
336 "Key block dev flag mismatch");
337
338 ResetMocks();
339 kbh.key_block_flags =
340 KEY_BLOCK_FLAG_RECOVERY_1 | KEY_BLOCK_FLAG_DEVELOPER_0;
341 TEST_EQ(LoadKernel(&lkp), VBERROR_INVALID_KERNEL_FOUND,
342 "Key block rec flag mismatch");
343
344 ResetMocks();
345 lkp.boot_flags |= BOOT_FLAG_RECOVERY;
346 kbh.key_block_flags =
347 KEY_BLOCK_FLAG_RECOVERY_1 | KEY_BLOCK_FLAG_DEVELOPER_1;
348 TEST_EQ(LoadKernel(&lkp), VBERROR_INVALID_KERNEL_FOUND,
349 "Key block recdev flag mismatch");
350
351 ResetMocks();
352 lkp.boot_flags |= BOOT_FLAG_RECOVERY | BOOT_FLAG_DEVELOPER;
353 kbh.key_block_flags =
354 KEY_BLOCK_FLAG_RECOVERY_1 | KEY_BLOCK_FLAG_DEVELOPER_0;
355 TEST_EQ(LoadKernel(&lkp), VBERROR_INVALID_KERNEL_FOUND,
356 "Key block rec!dev flag mismatch");
357
358 ResetMocks();
359 kbh.data_key.key_version = 1;
360 TEST_EQ(LoadKernel(&lkp), VBERROR_INVALID_KERNEL_FOUND,
361 "Key block kernel key rollback");
362
363 ResetMocks();
364 kbh.data_key.key_version = 0x10000;
365 TEST_EQ(LoadKernel(&lkp), VBERROR_INVALID_KERNEL_FOUND,
366 "Key block kernel key version too big");
367
368 /* TODO: key version ignored in recovery mode */
369 /* TODO: key block validity ignored in dev mode */
370
371 ResetMocks();
372 mock_data_key = NULL;
373 TEST_EQ(LoadKernel(&lkp), VBERROR_INVALID_KERNEL_FOUND, "Bad data key");
374
375 ResetMocks();
376 preamble_verify_fail = 1;
377 TEST_EQ(LoadKernel(&lkp), VBERROR_INVALID_KERNEL_FOUND, "Bad preamble");
378
379 ResetMocks();
380 kph.kernel_version = 0;
381 TEST_EQ(LoadKernel(&lkp), VBERROR_INVALID_KERNEL_FOUND,
382 "Kernel version rollback");
383
384 /* TODO: kernel version ignored in recovery and dev modes */
385
386 ResetMocks();
387 kph.preamble_size |= 0x07;
388 TEST_EQ(LoadKernel(&lkp), VBERROR_INVALID_KERNEL_FOUND,
389 "Kernel body offset");
390
391 ResetMocks();
392 lkp.kernel_buffer_size = 8192;
393 TEST_EQ(LoadKernel(&lkp), VBERROR_INVALID_KERNEL_FOUND,
394 "Kernel too big for buffer");
395
396 ResetMocks();
397 mock_parts[0].size = 130;
398 TEST_EQ(LoadKernel(&lkp), VBERROR_INVALID_KERNEL_FOUND,
399 "Kernel too big for partition");
400
401}
402
Randall Spangler49cb0d32013-01-29 14:28:16 -0800403int main(void)
404{
405 ReadWriteGptTest();
406 InvalidParamsTest();
Randall Spangler5d0a2e72013-01-30 13:19:19 -0800407 KernelLoopTest();
Randall Spangler49cb0d32013-01-29 14:28:16 -0800408
409 return gTestSuccess ? 0 : 255;
410}