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