1 /* Copyright 2013 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 vboot_kernel.c
6 */
7
8 #include "2api.h"
9 #include "cgptlib.h"
10 #include "cgptlib_internal.h"
11 #include "common/tests.h"
12 #include "gpt.h"
13
14 #define LOGCALL(fmt, args...) sprintf(call_log + strlen(call_log), fmt, ##args)
15 #define TEST_CALLS(expect_log) TEST_STR_EQ(call_log, expect_log, " calls")
16
17 /* Assumes 512-byte disk sectors */
18 #define MOCK_SECTOR_SIZE 512
19 #define MOCK_SECTOR_COUNT 1024
20
21 /* Mock kernel partition */
22 struct mock_part {
23 uint32_t start;
24 uint32_t size;
25 };
26
27 /* Mock data */
28 static char call_log[4096];
29 static int disk_read_to_fail;
30 static int disk_write_to_fail;
31
32 static vb2ex_disk_handle_t handle;
33 static uint8_t mock_disk[MOCK_SECTOR_SIZE * MOCK_SECTOR_COUNT];
34 static GptHeader *mock_gpt_primary =
35 (GptHeader*)&mock_disk[MOCK_SECTOR_SIZE * 1];
36 static GptHeader *mock_gpt_secondary =
37 (GptHeader*)&mock_disk[MOCK_SECTOR_SIZE * (MOCK_SECTOR_COUNT - 1)];
38
39 /**
40 * Prepare a valid GPT header that will pass CheckHeader() tests
41 */
SetupGptHeader(GptHeader * h,int is_secondary)42 static void SetupGptHeader(GptHeader *h, int is_secondary)
43 {
44 memset(h, '\0', MOCK_SECTOR_SIZE);
45
46 /* "EFI PART" */
47 memcpy(h->signature, GPT_HEADER_SIGNATURE, GPT_HEADER_SIGNATURE_SIZE);
48 h->revision = GPT_HEADER_REVISION;
49 h->size = MIN_SIZE_OF_HEADER;
50
51 /* 16KB: 128 entries of 128 bytes */
52 h->size_of_entry = sizeof(GptEntry);
53 h->number_of_entries = MAX_NUMBER_OF_ENTRIES;
54
55 /* Set LBA pointers for primary or secondary header */
56 if (is_secondary) {
57 h->my_lba = MOCK_SECTOR_COUNT - GPT_HEADER_SECTORS;
58 h->entries_lba = h->my_lba - CalculateEntriesSectors(h,
59 MOCK_SECTOR_SIZE);
60 } else {
61 h->my_lba = GPT_PMBR_SECTORS;
62 h->entries_lba = h->my_lba + 1;
63 }
64
65 h->first_usable_lba = 2 + CalculateEntriesSectors(h, MOCK_SECTOR_SIZE);
66 h->last_usable_lba = MOCK_SECTOR_COUNT - 2 - CalculateEntriesSectors(h,
67 MOCK_SECTOR_SIZE);
68
69 h->header_crc32 = HeaderCrc(h);
70 }
71
ResetCallLog(void)72 static void ResetCallLog(void)
73 {
74 *call_log = 0;
75 }
76
77 /**
78 * Reset mock data (for use before each test)
79 */
ResetMocks(void)80 static void ResetMocks(void)
81 {
82 ResetCallLog();
83
84 memset(&mock_disk, 0, sizeof(mock_disk));
85 SetupGptHeader(mock_gpt_primary, 0);
86 SetupGptHeader(mock_gpt_secondary, 1);
87
88 disk_read_to_fail = -1;
89 disk_write_to_fail = -1;
90 }
91
92 /* Mocks */
93
VbExDiskRead(vb2ex_disk_handle_t h,uint64_t lba_start,uint64_t lba_count,void * buffer)94 vb2_error_t VbExDiskRead(vb2ex_disk_handle_t h, uint64_t lba_start,
95 uint64_t lba_count, void *buffer)
96 {
97 LOGCALL("VbExDiskRead(h, %d, %d)\n", (int)lba_start, (int)lba_count);
98
99 if ((int)lba_start == disk_read_to_fail)
100 return VB2_ERROR_MOCK;
101
102 memcpy(buffer, &mock_disk[lba_start * MOCK_SECTOR_SIZE],
103 lba_count * MOCK_SECTOR_SIZE);
104
105 return VB2_SUCCESS;
106 }
107
VbExDiskWrite(vb2ex_disk_handle_t h,uint64_t lba_start,uint64_t lba_count,const void * buffer)108 vb2_error_t VbExDiskWrite(vb2ex_disk_handle_t h, uint64_t lba_start,
109 uint64_t lba_count, const void *buffer)
110 {
111 LOGCALL("VbExDiskWrite(h, %d, %d)\n", (int)lba_start, (int)lba_count);
112
113 if ((int)lba_start == disk_write_to_fail)
114 return VB2_ERROR_MOCK;
115
116 memcpy(&mock_disk[lba_start * MOCK_SECTOR_SIZE], buffer,
117 lba_count * MOCK_SECTOR_SIZE);
118
119 return VB2_SUCCESS;
120 }
121
122 /**
123 * Test reading/writing GPT
124 */
ReadWriteGptTest(void)125 static void ReadWriteGptTest(void)
126 {
127 GptData g;
128 GptHeader *h;
129
130 g.sector_bytes = MOCK_SECTOR_SIZE;
131 g.streaming_drive_sectors = g.gpt_drive_sectors = MOCK_SECTOR_COUNT;
132 g.valid_headers = g.valid_entries = MASK_BOTH;
133
134 ResetMocks();
135 TEST_EQ(AllocAndReadGptData(handle, &g), 0, "AllocAndRead");
136 TEST_CALLS("VbExDiskRead(h, 1, 1)\n"
137 "VbExDiskRead(h, 2, 32)\n"
138 "VbExDiskRead(h, 1023, 1)\n"
139 "VbExDiskRead(h, 991, 32)\n");
140 ResetCallLog();
141 /*
142 * Valgrind complains about access to uninitialized memory here, so
143 * zero the primary header before each test.
144 */
145 memset(g.primary_header, '\0', g.sector_bytes);
146 TEST_EQ(WriteAndFreeGptData(handle, &g), 0, "WriteAndFree");
147 TEST_CALLS("");
148
149 /*
150 * Invalidate primary GPT header,
151 * check that AllocAndReadGptData still succeeds
152 */
153 ResetMocks();
154 memset(mock_gpt_primary, '\0', sizeof(*mock_gpt_primary));
155 TEST_EQ(AllocAndReadGptData(handle, &g), 0,
156 "AllocAndRead primary invalid");
157 TEST_EQ(CheckHeader(mock_gpt_primary, 0, g.streaming_drive_sectors,
158 g.gpt_drive_sectors, 0, g.sector_bytes),
159 1, "Primary header is invalid");
160 TEST_EQ(CheckHeader(mock_gpt_secondary, 1, g.streaming_drive_sectors,
161 g.gpt_drive_sectors, 0, g.sector_bytes),
162 0, "Secondary header is valid");
163 TEST_CALLS("VbExDiskRead(h, 1, 1)\n"
164 "VbExDiskRead(h, 1023, 1)\n"
165 "VbExDiskRead(h, 991, 32)\n");
166 WriteAndFreeGptData(handle, &g);
167
168 /*
169 * Invalidate secondary GPT header,
170 * check that AllocAndReadGptData still succeeds
171 */
172 ResetMocks();
173 memset(mock_gpt_secondary, '\0', sizeof(*mock_gpt_secondary));
174 TEST_EQ(AllocAndReadGptData(handle, &g), 0,
175 "AllocAndRead secondary invalid");
176 TEST_EQ(CheckHeader(mock_gpt_primary, 0, g.streaming_drive_sectors,
177 g.gpt_drive_sectors, 0, g.sector_bytes),
178 0, "Primary header is valid");
179 TEST_EQ(CheckHeader(mock_gpt_secondary, 1, g.streaming_drive_sectors,
180 g.gpt_drive_sectors, 0, g.sector_bytes),
181 1, "Secondary header is invalid");
182 TEST_CALLS("VbExDiskRead(h, 1, 1)\n"
183 "VbExDiskRead(h, 2, 32)\n"
184 "VbExDiskRead(h, 1023, 1)\n");
185 WriteAndFreeGptData(handle, &g);
186
187 /*
188 * Invalidate primary AND secondary GPT header,
189 * check that AllocAndReadGptData fails.
190 */
191 ResetMocks();
192 memset(mock_gpt_primary, '\0', sizeof(*mock_gpt_primary));
193 memset(mock_gpt_secondary, '\0', sizeof(*mock_gpt_secondary));
194 TEST_EQ(AllocAndReadGptData(handle, &g), 1,
195 "AllocAndRead primary and secondary invalid");
196 TEST_EQ(CheckHeader(mock_gpt_primary, 0, g.streaming_drive_sectors,
197 g.gpt_drive_sectors, 0, g.sector_bytes),
198 1, "Primary header is invalid");
199 TEST_EQ(CheckHeader(mock_gpt_secondary, 1, g.streaming_drive_sectors,
200 g.gpt_drive_sectors, 0, g.sector_bytes),
201 1, "Secondary header is invalid");
202 TEST_CALLS("VbExDiskRead(h, 1, 1)\n"
203 "VbExDiskRead(h, 1023, 1)\n");
204 WriteAndFreeGptData(handle, &g);
205
206 /*
207 * Invalidate primary GPT header and check that it is
208 * repaired by GptRepair().
209 *
210 * This would normally be called by vb2api_load_kernel()->GptInit()
211 * but this callback is mocked in these tests.
212 */
213 ResetMocks();
214 memset(mock_gpt_primary, '\0', sizeof(*mock_gpt_primary));
215 TEST_EQ(AllocAndReadGptData(handle, &g), 0,
216 "Fix Primary GPT: AllocAndRead");
217 /* Call GptRepair() with input indicating secondary GPT is valid */
218 g.valid_headers = g.valid_entries = MASK_SECONDARY;
219 GptRepair(&g);
220 TEST_EQ(WriteAndFreeGptData(handle, &g), 0,
221 "Fix Primary GPT: WriteAndFreeGptData");
222 TEST_CALLS("VbExDiskRead(h, 1, 1)\n"
223 "VbExDiskRead(h, 1023, 1)\n"
224 "VbExDiskRead(h, 991, 32)\n"
225 "VbExDiskWrite(h, 1, 1)\n"
226 "VbExDiskWrite(h, 2, 32)\n");
227 TEST_EQ(CheckHeader(mock_gpt_primary, 0, g.streaming_drive_sectors,
228 g.gpt_drive_sectors, 0, g.sector_bytes),
229 0, "Fix Primary GPT: Primary header is valid");
230
231 /*
232 * Invalidate secondary GPT header and check that it can be
233 * repaired by GptRepair().
234 *
235 * This would normally be called by vb2api_load_kernel()->GptInit()
236 * but this callback is mocked in these tests.
237 */
238 ResetMocks();
239 memset(mock_gpt_secondary, '\0', sizeof(*mock_gpt_secondary));
240 TEST_EQ(AllocAndReadGptData(handle, &g), 0,
241 "Fix Secondary GPT: AllocAndRead");
242 /* Call GptRepair() with input indicating primary GPT is valid */
243 g.valid_headers = g.valid_entries = MASK_PRIMARY;
244 GptRepair(&g);
245 TEST_EQ(WriteAndFreeGptData(handle, &g), 0,
246 "Fix Secondary GPT: WriteAndFreeGptData");
247 TEST_CALLS("VbExDiskRead(h, 1, 1)\n"
248 "VbExDiskRead(h, 2, 32)\n"
249 "VbExDiskRead(h, 1023, 1)\n"
250 "VbExDiskWrite(h, 1023, 1)\n"
251 "VbExDiskWrite(h, 991, 32)\n");
252 TEST_EQ(CheckHeader(mock_gpt_secondary, 1, g.streaming_drive_sectors,
253 g.gpt_drive_sectors, 0, g.sector_bytes),
254 0, "Fix Secondary GPT: Secondary header is valid");
255
256 /* Data which is changed is written */
257 ResetMocks();
258 AllocAndReadGptData(handle, &g);
259 g.modified |= GPT_MODIFIED_HEADER1 | GPT_MODIFIED_ENTRIES1;
260 ResetCallLog();
261 memset(g.primary_header, '\0', g.sector_bytes);
262 h = (GptHeader*)g.primary_header;
263 h->entries_lba = 2;
264 h->number_of_entries = MAX_NUMBER_OF_ENTRIES;
265 h->size_of_entry = sizeof(GptEntry);
266 TEST_EQ(WriteAndFreeGptData(handle, &g), 0, "WriteAndFree mod 1");
267 TEST_CALLS("VbExDiskWrite(h, 1, 1)\n"
268 "VbExDiskWrite(h, 2, 32)\n");
269
270 /* Data which is changed is written */
271 ResetMocks();
272 AllocAndReadGptData(handle, &g);
273 g.modified = -1;
274 ResetCallLog();
275 memset(g.primary_header, '\0', g.sector_bytes);
276 h = (GptHeader*)g.primary_header;
277 h->entries_lba = 2;
278 h->number_of_entries = MAX_NUMBER_OF_ENTRIES;
279 h->size_of_entry = sizeof(GptEntry);
280 h = (GptHeader*)g.secondary_header;
281 h->entries_lba = 991;
282 TEST_EQ(WriteAndFreeGptData(handle, &g), 0, "WriteAndFree mod all");
283 TEST_CALLS("VbExDiskWrite(h, 1, 1)\n"
284 "VbExDiskWrite(h, 2, 32)\n"
285 "VbExDiskWrite(h, 1023, 1)\n"
286 "VbExDiskWrite(h, 991, 32)\n");
287
288 /* If legacy signature, don't modify GPT header/entries 1 */
289 ResetMocks();
290 AllocAndReadGptData(handle, &g);
291 h = (GptHeader *)g.primary_header;
292 memcpy(h->signature, GPT_HEADER_SIGNATURE2, GPT_HEADER_SIGNATURE_SIZE);
293 g.modified = -1;
294 ResetCallLog();
295 TEST_EQ(WriteAndFreeGptData(handle, &g), 0, "WriteAndFree mod all");
296 TEST_CALLS("VbExDiskWrite(h, 1023, 1)\n"
297 "VbExDiskWrite(h, 991, 32)\n");
298
299 /* Error reading */
300 ResetMocks();
301 disk_read_to_fail = 1;
302 TEST_EQ(AllocAndReadGptData(handle, &g), 0, "AllocAndRead disk fail");
303 g.valid_headers = g.valid_entries = MASK_SECONDARY;
304 GptRepair(&g);
305 ResetCallLog();
306 TEST_EQ(WriteAndFreeGptData(handle, &g), 0, "WriteAndFree mod 1");
307 TEST_CALLS("VbExDiskWrite(h, 1, 1)\n"
308 "VbExDiskWrite(h, 2, 32)\n");
309
310 ResetMocks();
311 disk_read_to_fail = 2;
312 TEST_EQ(AllocAndReadGptData(handle, &g), 0, "AllocAndRead disk fail");
313 g.valid_headers = MASK_BOTH;
314 g.valid_entries = MASK_SECONDARY;
315 GptRepair(&g);
316 ResetCallLog();
317 TEST_EQ(WriteAndFreeGptData(handle, &g), 0, "WriteAndFree mod 1");
318 TEST_CALLS("VbExDiskWrite(h, 2, 32)\n");
319
320 ResetMocks();
321 disk_read_to_fail = 991;
322 TEST_EQ(AllocAndReadGptData(handle, &g), 0, "AllocAndRead disk fail");
323 g.valid_headers = MASK_BOTH;
324 g.valid_entries = MASK_PRIMARY;
325 GptRepair(&g);
326 ResetCallLog();
327 TEST_EQ(WriteAndFreeGptData(handle, &g), 0, "WriteAndFree mod 2");
328 TEST_CALLS("VbExDiskWrite(h, 991, 32)\n");
329
330 ResetMocks();
331 disk_read_to_fail = 1023;
332 TEST_EQ(AllocAndReadGptData(handle, &g), 0, "AllocAndRead disk fail");
333 g.valid_headers = g.valid_entries = MASK_PRIMARY;
334 GptRepair(&g);
335 ResetCallLog();
336 TEST_EQ(WriteAndFreeGptData(handle, &g), 0, "WriteAndFree mod 2");
337 TEST_CALLS("VbExDiskWrite(h, 1023, 1)\n"
338 "VbExDiskWrite(h, 991, 32)\n");
339
340 /* Error writing */
341 ResetMocks();
342 disk_write_to_fail = 1;
343 AllocAndReadGptData(handle, &g);
344 g.modified = -1;
345 memset(g.primary_header, '\0', g.sector_bytes);
346 TEST_NEQ(WriteAndFreeGptData(handle, &g), 0, "WriteAndFree disk fail");
347
348 ResetMocks();
349 disk_write_to_fail = 2;
350 AllocAndReadGptData(handle, &g);
351 g.modified = -1;
352 memset(g.primary_header, '\0', g.sector_bytes);
353 h = (GptHeader*)g.primary_header;
354 h->entries_lba = 2;
355 TEST_NEQ(WriteAndFreeGptData(handle, &g), 0, "WriteAndFree disk fail");
356
357 ResetMocks();
358 disk_write_to_fail = 991;
359 AllocAndReadGptData(handle, &g);
360 g.modified = -1;
361 memset(g.primary_header, '\0', g.sector_bytes);
362 TEST_NEQ(WriteAndFreeGptData(handle, &g), 0, "WriteAndFree disk fail");
363
364 ResetMocks();
365 disk_write_to_fail = 1023;
366 AllocAndReadGptData(handle, &g);
367 g.modified = -1;
368 memset(g.primary_header, '\0', g.sector_bytes);
369 TEST_NEQ(WriteAndFreeGptData(handle, &g), 0, "WriteAndFree disk fail");
370
371 }
372
main(void)373 int main(void)
374 {
375 ReadWriteGptTest();
376
377 return gTestSuccess ? 0 : 255;
378 }
379