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_api_kernel, part 3 - software sync
6  */
7 
8 #include <stdint.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 
12 #include "gbb_header.h"
13 #include "host_common.h"
14 #include "load_kernel_fw.h"
15 #include "rollback_index.h"
16 #include "test_common.h"
17 #include "vboot_audio.h"
18 #include "vboot_common.h"
19 #include "vboot_kernel.h"
20 #include "vboot_nvstorage.h"
21 #include "vboot_struct.h"
22 
23 /* Mock data */
24 static VbCommonParams cparams;
25 static uint8_t shared_data[VB_SHARED_DATA_MIN_SIZE];
26 static VbSharedDataHeader *shared = (VbSharedDataHeader *)shared_data;
27 static GoogleBinaryBlockHeader gbb;
28 
29 static int trust_ec;
30 static int mock_in_rw;
31 static VbError_t in_rw_retval;
32 static int protect_retval;
33 static int ec_protected;
34 static int run_retval;
35 static int ec_run_image;
36 static int update_retval;
37 static int ec_updated;
38 static int get_expected_retval;
39 static int shutdown_request_calls_left;
40 
41 static uint8_t mock_ec_hash[32];
42 static int mock_ec_hash_size;
43 static uint8_t want_ec_hash[32];
44 static int want_ec_hash_size;
45 static uint8_t mock_sha[32];
46 
47 static uint32_t screens_displayed[8];
48 static uint32_t screens_count = 0;
49 
50 /* Reset mock data (for use before each test) */
ResetMocks(void)51 static void ResetMocks(void)
52 {
53 	Memset(&cparams, 0, sizeof(cparams));
54 	cparams.shared_data_size = sizeof(shared_data);
55 	cparams.shared_data_blob = shared_data;
56 	cparams.gbb_data = &gbb;
57 
58 	Memset(&gbb, 0, sizeof(gbb));
59 	gbb.major_version = GBB_MAJOR_VER;
60 	gbb.minor_version = GBB_MINOR_VER;
61 	gbb.flags = 0;
62 
63 	/*
64 	 * Only the outermost vboot_api_kernel call sets vboot_api_kernel's
65 	 * vnc.  So clear it here too.
66 	 */
67 	Memset(VbApiKernelGetVnc(), 0, sizeof(VbNvContext));
68 	VbNvSetup(VbApiKernelGetVnc());
69 	VbNvTeardown(VbApiKernelGetVnc()); /* So CRC gets generated */
70 
71 	Memset(&shared_data, 0, sizeof(shared_data));
72 	VbSharedDataInit(shared, sizeof(shared_data));
73 
74 	trust_ec = 0;
75 	mock_in_rw = 0;
76 	ec_protected = 0;
77 	ec_run_image = 0;   /* 0 = RO, 1 = RW */
78 	ec_updated = 0;
79 	in_rw_retval = VBERROR_SUCCESS;
80 	protect_retval = VBERROR_SUCCESS;
81 	update_retval = VBERROR_SUCCESS;
82 	run_retval = VBERROR_SUCCESS;
83 	get_expected_retval = VBERROR_SUCCESS;
84 	shutdown_request_calls_left = -1;
85 
86 	Memset(mock_ec_hash, 0, sizeof(mock_ec_hash));
87 	mock_ec_hash[0] = 42;
88 	mock_ec_hash_size = sizeof(mock_ec_hash);
89 
90 	Memset(want_ec_hash, 0, sizeof(want_ec_hash));
91 	want_ec_hash[0] = 42;
92 	want_ec_hash_size = sizeof(want_ec_hash);
93 
94 	Memset(mock_sha, 0, sizeof(want_ec_hash));
95 	mock_sha[0] = 42;
96 
97 	// TODO: ensure these are actually needed
98 
99 	Memset(screens_displayed, 0, sizeof(screens_displayed));
100 	screens_count = 0;
101 }
102 
103 /* Mock functions */
104 
VbExIsShutdownRequested(void)105 uint32_t VbExIsShutdownRequested(void)
106 {
107 	if (shutdown_request_calls_left == 0)
108 		return 1;
109 	else if (shutdown_request_calls_left > 0)
110 		shutdown_request_calls_left--;
111 
112 	return 0;
113 }
114 
VbExTrustEC(int devidx)115 int VbExTrustEC(int devidx)
116 {
117 	return trust_ec;
118 }
119 
VbExEcRunningRW(int devidx,int * in_rw)120 VbError_t VbExEcRunningRW(int devidx, int *in_rw)
121 {
122 	*in_rw = mock_in_rw;
123 	return in_rw_retval;
124 }
125 
VbExEcProtectRW(int devidx)126 VbError_t VbExEcProtectRW(int devidx)
127 {
128 	ec_protected = 1;
129 	return protect_retval;
130 }
131 
VbExEcDisableJump(int devidx)132 VbError_t VbExEcDisableJump(int devidx)
133 {
134 	return run_retval;
135 }
136 
VbExEcJumpToRW(int devidx)137 VbError_t VbExEcJumpToRW(int devidx)
138 {
139 	ec_run_image = 1;
140 	return run_retval;
141 }
142 
VbExEcHashRW(int devidx,const uint8_t ** hash,int * hash_size)143 VbError_t VbExEcHashRW(int devidx, const uint8_t **hash, int *hash_size)
144 {
145 	*hash = mock_ec_hash;
146 	*hash_size = mock_ec_hash_size;
147 	return mock_ec_hash_size ? VBERROR_SUCCESS : VBERROR_SIMULATED;
148 }
149 
VbExEcGetExpectedRW(int devidx,enum VbSelectFirmware_t select,const uint8_t ** image,int * image_size)150 VbError_t VbExEcGetExpectedRW(int devidx, enum VbSelectFirmware_t select,
151                               const uint8_t **image, int *image_size)
152 {
153 	static uint8_t fake_image[64] = {5, 6, 7, 8};
154 	*image = fake_image;
155 	*image_size = sizeof(fake_image);
156 	return get_expected_retval;
157 }
158 
VbExEcGetExpectedRWHash(int devidx,enum VbSelectFirmware_t select,const uint8_t ** hash,int * hash_size)159 VbError_t VbExEcGetExpectedRWHash(int devidx, enum VbSelectFirmware_t select,
160 				  const uint8_t **hash, int *hash_size)
161 {
162 	*hash = want_ec_hash;
163 	*hash_size = want_ec_hash_size;
164 
165 	if (want_ec_hash_size == -1)
166 		return VBERROR_EC_GET_EXPECTED_HASH_FROM_IMAGE;
167 	else
168 		return want_ec_hash_size ? VBERROR_SUCCESS : VBERROR_SIMULATED;
169 }
170 
internal_SHA256(const uint8_t * data,uint64_t len,uint8_t * digest)171 uint8_t *internal_SHA256(const uint8_t *data, uint64_t len, uint8_t *digest)
172 {
173 	Memcpy(digest, mock_sha, sizeof(mock_sha));
174 	return digest;
175 }
176 
VbExEcUpdateRW(int devidx,const uint8_t * image,int image_size)177 VbError_t VbExEcUpdateRW(int devidx, const uint8_t *image, int image_size)
178 {
179 	ec_updated = 1;
180 	return update_retval;
181 }
182 
VbDisplayScreen(VbCommonParams * cparams,uint32_t screen,int force,VbNvContext * vncptr)183 VbError_t VbDisplayScreen(VbCommonParams *cparams, uint32_t screen, int force,
184                           VbNvContext *vncptr)
185 {
186 	if (screens_count < ARRAY_SIZE(screens_displayed))
187 		screens_displayed[screens_count++] = screen;
188 
189 	return VBERROR_SUCCESS;
190 }
191 
test_ssync(VbError_t retval,int recovery_reason,const char * desc)192 static void test_ssync(VbError_t retval, int recovery_reason, const char *desc)
193 {
194 	uint32_t u;
195 
196 	TEST_EQ(VbEcSoftwareSync(0, &cparams), retval, desc);
197 	VbNvGet(VbApiKernelGetVnc(), VBNV_RECOVERY_REQUEST, &u);
198 	TEST_EQ(u, recovery_reason, "  recovery reason");
199 }
200 
201 /* Tests */
202 
VbSoftwareSyncTest(void)203 static void VbSoftwareSyncTest(void)
204 {
205 	/* Recovery cases */
206 	ResetMocks();
207 	shared->recovery_reason = 123;
208 	test_ssync(0, 0, "In recovery, EC-RO");
209 	TEST_EQ(ec_protected, 0, "  ec protected");
210 
211 	ResetMocks();
212 	shared->recovery_reason = 123;
213 	mock_in_rw = 1;
214 	test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED,
215 		   123, "Recovery needs EC-RO");
216 
217 	/* AP-RO cases */
218 	ResetMocks();
219 	in_rw_retval = VBERROR_SIMULATED;
220 	test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED,
221 		   VBNV_RECOVERY_EC_UNKNOWN_IMAGE, "Unknown EC image");
222 
223 	ResetMocks();
224 	shared->flags |= VBSD_LF_USE_RO_NORMAL;
225 	mock_in_rw = 1;
226 	test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED,
227 		   0, "AP-RO needs EC-RO");
228 
229 	ResetMocks();
230 	shared->flags |= VBSD_LF_USE_RO_NORMAL;
231 	test_ssync(0, 0, "AP-RO, EC-RO");
232 	TEST_EQ(ec_protected, 1, "  ec protected");
233 	TEST_EQ(ec_run_image, 0, "  ec run image");
234 
235 	ResetMocks();
236 	shared->flags |= VBSD_LF_USE_RO_NORMAL;
237 	run_retval = VBERROR_SIMULATED;
238 	test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED,
239 		   VBNV_RECOVERY_EC_SOFTWARE_SYNC, "Stay in RO fail");
240 
241 	ResetMocks();
242 	shared->flags |= VBSD_LF_USE_RO_NORMAL;
243 	protect_retval = VBERROR_SIMULATED;
244 	test_ssync(VBERROR_SIMULATED,
245 		   VBNV_RECOVERY_EC_PROTECT, "Protect error");
246 
247 	/* No longer check for shutdown requested */
248 	ResetMocks();
249 	shared->flags |= VBSD_LF_USE_RO_NORMAL;
250 	shutdown_request_calls_left = 0;
251 	test_ssync(0, 0, "AP-RO shutdown requested");
252 
253 	/* Calculate hashes */
254 	ResetMocks();
255 	mock_ec_hash_size = 0;
256 	test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED,
257 		   VBNV_RECOVERY_EC_HASH_FAILED, "Bad EC hash");
258 
259 	ResetMocks();
260 	mock_ec_hash_size = 16;
261 	test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED,
262 		   VBNV_RECOVERY_EC_HASH_SIZE, "Bad EC hash size");
263 
264 	ResetMocks();
265 	want_ec_hash_size = 0;
266 	test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED,
267 		   VBNV_RECOVERY_EC_EXPECTED_HASH, "Bad precalculated hash");
268 
269 	ResetMocks();
270 	want_ec_hash_size = 16;
271 	test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED,
272 		   VBNV_RECOVERY_EC_EXPECTED_HASH,
273 		   "Bad precalculated hash size");
274 
275 	ResetMocks();
276 	mock_in_rw = 1;
277 	want_ec_hash_size = -1;
278 	test_ssync(0, 0, "No precomputed hash");
279 
280 	ResetMocks();
281 	want_ec_hash_size = -1;
282 	get_expected_retval = VBERROR_SIMULATED;
283 	test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED,
284 		   VBNV_RECOVERY_EC_EXPECTED_IMAGE, "Can't fetch image");
285 
286 	/* Updates required */
287 	ResetMocks();
288 	mock_in_rw = 1;
289 	want_ec_hash[0]++;
290 	test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED,
291 		   VBNV_RECOVERY_EC_HASH_MISMATCH,
292 		   "Precalculated hash mismatch");
293 
294 	ResetMocks();
295 	mock_in_rw = 1;
296 	mock_ec_hash[0]++;
297 	test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED,
298 		   0, "Pending update needs reboot");
299 
300 	ResetMocks();
301 	mock_ec_hash[0]++;
302 	test_ssync(0, 0, "Update without reboot");
303 	TEST_EQ(ec_protected, 1, "  ec protected");
304 	TEST_EQ(ec_run_image, 1, "  ec run image");
305 	TEST_EQ(ec_updated, 1, "  ec updated");
306 
307 	ResetMocks();
308 	mock_ec_hash[0]++;
309 	update_retval = VBERROR_EC_REBOOT_TO_RO_REQUIRED;
310 	test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED,
311 		   0, "Reboot after update");
312 	TEST_EQ(ec_updated, 1, "  ec updated");
313 
314 	ResetMocks();
315 	mock_ec_hash[0]++;
316 	update_retval = VBERROR_SIMULATED;
317 	test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED,
318 		   VBNV_RECOVERY_EC_UPDATE, "Update failed");
319 
320 	ResetMocks();
321 	mock_ec_hash[0]++;
322 	shared->flags |= VBSD_EC_SLOW_UPDATE;
323 	test_ssync(0, 0, "Slow update");
324 	TEST_EQ(screens_displayed[0], VB_SCREEN_WAIT, "  wait screen");
325 
326 	/* RW cases, no update */
327 	ResetMocks();
328 	mock_in_rw = 1;
329 	test_ssync(0, 0, "AP-RW, EC-RW");
330 
331 	ResetMocks();
332 	test_ssync(0, 0, "AP-RW, EC-RO -> EC-RW");
333 	TEST_EQ(ec_protected, 1, "  ec protected");
334 	TEST_EQ(ec_run_image, 1, "  ec run image");
335 	TEST_EQ(ec_updated, 0, "  ec updated");
336 
337 	ResetMocks();
338 	run_retval = VBERROR_SIMULATED;
339 	test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED,
340 		   VBNV_RECOVERY_EC_JUMP_RW, "Jump to RW fail");
341 
342 	ResetMocks();
343 	run_retval = VBERROR_EC_REBOOT_TO_RO_REQUIRED;
344 	test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED,
345 		   0, "Jump to RW fail because locked");
346 
347 	ResetMocks();
348 	protect_retval = VBERROR_SIMULATED;
349 	test_ssync(VBERROR_SIMULATED,
350 		   VBNV_RECOVERY_EC_PROTECT, "Protect error");
351 
352 	/* No longer check for shutdown requested */
353 	ResetMocks();
354 	shutdown_request_calls_left = 0;
355 	test_ssync(0, 0,
356 		   "AP-RW, EC-RO -> EC-RW shutdown requested");
357 
358 	ResetMocks();
359 	mock_in_rw = 1;
360 	shutdown_request_calls_left = 0;
361 	test_ssync(0, 0, "AP-RW shutdown requested");
362 }
363 
main(void)364 int main(void)
365 {
366 	VbSoftwareSyncTest();
367 
368 	if (vboot_api_stub_check_memory())
369 		return 255;
370 
371 	return gTestSuccess ? 0 : 255;
372 }
373