xref: /aosp_15_r20/external/vboot_reference/tests/gpt_misc_tests.c (revision 8617a60d3594060b7ecbd21bc622a7c14f3cf2bc)
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