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 VbTryLoadKernel()
6  */
7 
8 #include <stddef.h>
9 #include <stdint.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 
13 #include "gbb_header.h"
14 #include "load_kernel_fw.h"
15 #include "rollback_index.h"
16 #include "test_common.h"
17 #include "utility.h"
18 #include "vboot_api.h"
19 #include "vboot_kernel.h"
20 
21 #define MAX_TEST_DISKS 10
22 #define DEFAULT_COUNT -1
23 
24 typedef struct {
25 	uint64_t bytes_per_lba;
26 	uint64_t lba_count;
27 	uint32_t flags;
28 	const char *diskname;
29 } disk_desc_t;
30 
31 typedef struct {
32 	char *name;
33 
34 	/* inputs for test case */
35 	uint32_t want_flags;
36 	VbError_t diskgetinfo_return_val;
37 	disk_desc_t disks_to_provide[MAX_TEST_DISKS];
38 	int disk_count_to_return;
39 	VbError_t loadkernel_return_val[MAX_TEST_DISKS];
40 	uint8_t external_expected[MAX_TEST_DISKS];
41 
42 	/* outputs from test */
43 	uint32_t expected_recovery_request_val;
44 	const char *expected_to_find_disk;
45 	const char *expected_to_load_disk;
46 	uint32_t expected_return_val;
47 
48 } test_case_t;
49 
50 /****************************************************************************/
51 /* Test cases */
52 
53 static const char pickme[] = "correct choice";
54 #define DONT_CARE ((const char *)42)
55 
56 test_case_t test[] = {
57 	{
58 		.name = "first removable drive",
59 		.want_flags = VB_DISK_FLAG_REMOVABLE,
60 		.disks_to_provide = {
61 			/* too small */
62 			{512,   10,  VB_DISK_FLAG_REMOVABLE, 0},
63 			/* wrong LBA */
64 			{2048, 100,  VB_DISK_FLAG_REMOVABLE, 0},
65 			/* wrong type */
66 			{512,  100,  VB_DISK_FLAG_FIXED, 0},
67 			/* wrong flags */
68 			{512,  100,  0, 0},
69 			/* still wrong flags */
70 			{512,  100,  -1, 0},
71 			{512,  100,
72 			 VB_DISK_FLAG_REMOVABLE | VB_DISK_FLAG_EXTERNAL_GPT,
73 			 pickme},
74 			/* already got one */
75 			{512,  100,  VB_DISK_FLAG_REMOVABLE, "holygrail"},
76 		},
77 		.disk_count_to_return = DEFAULT_COUNT,
78 		.diskgetinfo_return_val = VBERROR_SUCCESS,
79 		.loadkernel_return_val = {0, 1, 1, 1, 1, 1, 1, 1, 1, 1,},
80 		.external_expected = {1, 0, 0, 0, 0, 0, 0, 0, 0, 0,},
81 
82 		.expected_recovery_request_val = VBNV_RECOVERY_NOT_REQUESTED,
83 		.expected_to_find_disk = pickme,
84 		.expected_to_load_disk = pickme,
85 		.expected_return_val = VBERROR_SUCCESS
86 	},
87 	{
88 		.name = "second removable drive",
89 		.want_flags = VB_DISK_FLAG_REMOVABLE,
90 		.disks_to_provide = {
91 			/* wrong flags */
92 			{512,  100,  0, 0},
93 			{512,  100,  VB_DISK_FLAG_REMOVABLE, "not yet"},
94 			{512,  100,  VB_DISK_FLAG_REMOVABLE, pickme},
95 		},
96 		.disk_count_to_return = DEFAULT_COUNT,
97 		.diskgetinfo_return_val = VBERROR_SUCCESS,
98 		.loadkernel_return_val = {1, 0, 1, 1, 1, 1, 1, 1, 1, 1,},
99 
100 		.expected_recovery_request_val = VBNV_RECOVERY_NOT_REQUESTED,
101 		.expected_to_find_disk = pickme,
102 		.expected_to_load_disk = pickme,
103 		.expected_return_val = VBERROR_SUCCESS
104 	},
105 	{
106 		.name = "first fixed drive",
107 		.want_flags = VB_DISK_FLAG_FIXED,
108 		.disks_to_provide = {
109 			/* too small */
110 			{512,   10,  VB_DISK_FLAG_FIXED, 0},
111 			/* wrong LBA */
112 			{2048, 100,  VB_DISK_FLAG_FIXED, 0},
113 			/* wrong type */
114 			{512,  100,  VB_DISK_FLAG_REMOVABLE, 0},
115 			/* wrong flags */
116 			{512,  100,  0, 0},
117 			/* still wrong flags */
118 			{512,  100,  -1, 0},
119 			/* flags */
120 			{512,  100,  VB_DISK_FLAG_REMOVABLE|VB_DISK_FLAG_FIXED,
121 			 0},
122 			{512,  100,  VB_DISK_FLAG_FIXED, pickme},
123 			/* already got one */
124 			{512,  100,  VB_DISK_FLAG_FIXED, "holygrail"},
125 		},
126 		.disk_count_to_return = DEFAULT_COUNT,
127 		.diskgetinfo_return_val = VBERROR_SUCCESS,
128 		.loadkernel_return_val = {0, 1, 1, 1, 1, 1, 1, 1, 1, 1,},
129 
130 		.expected_recovery_request_val = VBNV_RECOVERY_NOT_REQUESTED,
131 		.expected_to_find_disk = pickme,
132 		.expected_to_load_disk = pickme,
133 		.expected_return_val = VBERROR_SUCCESS
134 	},
135 	{
136 		.name = "no drives at all",
137 		.want_flags = VB_DISK_FLAG_FIXED,
138 		.disks_to_provide = {},
139 		.disk_count_to_return = DEFAULT_COUNT,
140 		.diskgetinfo_return_val = VBERROR_SUCCESS,
141 		.loadkernel_return_val = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1,},
142 
143 		.expected_recovery_request_val = VBNV_RECOVERY_RW_NO_DISK,
144 		.expected_to_find_disk = 0,
145 		.expected_to_load_disk = 0,
146 		.expected_return_val = VBERROR_NO_DISK_FOUND
147 	},
148 	{
149 		.name = "no valid drives",
150 		.want_flags = VB_DISK_FLAG_FIXED,
151 		.disks_to_provide = {
152 			/* too small */
153 			{512,   10,  VB_DISK_FLAG_FIXED, 0},
154 			/* wrong LBA */
155 			{2048, 100,  VB_DISK_FLAG_FIXED, 0},
156 			/* wrong type */
157 			{512,  100,  VB_DISK_FLAG_REMOVABLE, 0},
158 			/* wrong flags */
159 			{512,  100,  0, 0},
160 			/* still wrong flags */
161 			{512,  100,  -1, 0},
162 			/* doesn't load */
163 			{512,  100,  VB_DISK_FLAG_FIXED, "bad1"},
164 			/* doesn't load */
165 			{512,  100,  VB_DISK_FLAG_FIXED, "bad2"},
166 		},
167 		.disk_count_to_return = DEFAULT_COUNT,
168 		.diskgetinfo_return_val = VBERROR_SUCCESS,
169 		.loadkernel_return_val = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1,},
170 
171 		.expected_recovery_request_val = VBNV_RECOVERY_RW_NO_KERNEL,
172 		.expected_to_find_disk = DONT_CARE,
173 		.expected_to_load_disk = 0,
174 		.expected_return_val = 1
175 	},
176 };
177 
178 /****************************************************************************/
179 
180 /* Mock data */
181 static LoadKernelParams lkparams;
182 static VbDiskInfo mock_disks[MAX_TEST_DISKS];
183 static test_case_t *t;
184 static int load_kernel_calls;
185 static uint32_t got_recovery_request_val;
186 static const char *got_find_disk;
187 static const char *got_load_disk;
188 static uint32_t got_return_val;
189 static uint32_t got_external_mismatch;
190 
191 /**
192  * Reset mock data (for use before each test)
193  */
ResetMocks(int i)194 static void ResetMocks(int i)
195 {
196 	Memset(&lkparams, 0, sizeof(lkparams));
197 	Memset(&mock_disks, 0, sizeof(mock_disks));
198 	load_kernel_calls = 0;
199 
200 	got_recovery_request_val = VBNV_RECOVERY_NOT_REQUESTED;
201 	got_find_disk = 0;
202 	got_load_disk = 0;
203 	got_return_val = 0xdeadbeef;
204 
205 	t = test + i;
206 }
207 
is_nonzero(const void * vptr,size_t count)208 int is_nonzero(const void *vptr, size_t count)
209 {
210 	const char *p = (const char *)vptr;
211 	while (count--)
212 		if (*p++)
213 			return 1;
214 
215 	return 0;
216 }
217 
218 /****************************************************************************/
219 /* Mocked verification functions */
220 
VbExDiskGetInfo(VbDiskInfo ** infos_ptr,uint32_t * count,uint32_t disk_flags)221 VbError_t VbExDiskGetInfo(VbDiskInfo **infos_ptr, uint32_t *count,
222                           uint32_t disk_flags)
223 {
224 	int i;
225 	int num_disks = 0;
226 
227 	VBDEBUG(("My %s\n", __FUNCTION__));
228 
229 	*infos_ptr = mock_disks;
230 
231 	for(i = 0; i < MAX_TEST_DISKS; i++) {
232 		if (is_nonzero(&t->disks_to_provide[i],
233 			       sizeof(t->disks_to_provide[i]))) {
234 			mock_disks[num_disks].bytes_per_lba =
235 				t->disks_to_provide[i].bytes_per_lba;
236 			mock_disks[num_disks].lba_count =
237 				mock_disks[num_disks].streaming_lba_count =
238 				t->disks_to_provide[i].lba_count;
239 			mock_disks[num_disks].flags =
240 				t->disks_to_provide[i].flags;
241 			mock_disks[num_disks].handle = (VbExDiskHandle_t)
242 				t->disks_to_provide[i].diskname;
243 			VBDEBUG(("  mock_disk[%d] %" PRIu64 " %" PRIu64
244 				 " 0x%x %s\n", i,
245 				 mock_disks[num_disks].bytes_per_lba,
246 				 mock_disks[num_disks].lba_count,
247 				 mock_disks[num_disks].flags,
248 				 (mock_disks[num_disks].handle
249 				  ? (char *)mock_disks[num_disks].handle
250 				  : "0")));
251 			num_disks++;
252 		} else {
253 			mock_disks[num_disks].handle =
254 				(VbExDiskHandle_t)"INVALID";
255 		}
256 	}
257 
258 	if (t->disk_count_to_return >= 0)
259 		*count = t->disk_count_to_return;
260 	else
261 		*count = num_disks;
262 
263 	VBDEBUG(("  *count=%" PRIu32 "\n", *count));
264 	VBDEBUG(("  return 0x%x\n", t->diskgetinfo_return_val));
265 
266 	return t->diskgetinfo_return_val;
267 }
268 
VbExDiskFreeInfo(VbDiskInfo * infos,VbExDiskHandle_t preserve_handle)269 VbError_t VbExDiskFreeInfo(VbDiskInfo *infos,
270                            VbExDiskHandle_t preserve_handle)
271 {
272 	got_load_disk = (const char *)preserve_handle;
273 	VBDEBUG(("%s(): got_load_disk = %s\n", __FUNCTION__,
274 		 got_load_disk ? got_load_disk : "0"));
275 	return VBERROR_SUCCESS;
276 }
277 
LoadKernel(LoadKernelParams * params,VbCommonParams * cparams)278 VbError_t LoadKernel(LoadKernelParams *params, VbCommonParams *cparams)
279 {
280 	got_find_disk = (const char *)params->disk_handle;
281 	VBDEBUG(("%s(%d): got_find_disk = %s\n", __FUNCTION__,
282 		 load_kernel_calls,
283 		 got_find_disk ? got_find_disk : "0"));
284 	if (t->external_expected[load_kernel_calls] !=
285 			!!(params->boot_flags & BOOT_FLAG_EXTERNAL_GPT))
286 		got_external_mismatch++;
287 	return t->loadkernel_return_val[load_kernel_calls++];
288 }
289 
VbNvSet(VbNvContext * context,VbNvParam param,uint32_t value)290 int VbNvSet(VbNvContext *context, VbNvParam param, uint32_t value)
291 {
292 	VBDEBUG(("%s(): got_recovery_request_val = %d (0x%x)\n", __FUNCTION__,
293 		 value, value));
294 	got_recovery_request_val = value;
295 	return 0;
296 }
297 
298 /****************************************************************************/
299 
VbTryLoadKernelTest(void)300 static void VbTryLoadKernelTest(void)
301 {
302 	int i;
303 	int num_tests =  sizeof(test) / sizeof(test[0]);
304 
305 	for (i = 0; i < num_tests; i++) {
306 		printf("Test case: %s ...\n", test[i].name);
307 		ResetMocks(i);
308 		TEST_EQ(VbTryLoadKernel(0, &lkparams, test[i].want_flags),
309 			t->expected_return_val, "  return value");
310 		TEST_EQ(got_recovery_request_val,
311 			t->expected_recovery_request_val, "  recovery_request");
312 		if (t->expected_to_find_disk != DONT_CARE) {
313 			TEST_PTR_EQ(got_find_disk, t->expected_to_find_disk,
314 				    "  find disk");
315 			TEST_PTR_EQ(got_load_disk, t->expected_to_load_disk,
316 				    "  load disk");
317 		}
318 		TEST_EQ(got_external_mismatch, 0, "  external GPT errors");
319 	}
320 }
321 
main(void)322 int main(void)
323 {
324 	VbTryLoadKernelTest();
325 
326 	if (vboot_api_stub_check_memory())
327 		return 255;
328 
329 	return gTestSuccess ? 0 : 255;
330 }
331