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 */
24static VbCommonParams cparams;
25static uint8_t shared_data[VB_SHARED_DATA_MIN_SIZE];
26static VbSharedDataHeader *shared = (VbSharedDataHeader *)shared_data;
27static GoogleBinaryBlockHeader gbb;
28
29static int trust_ec;
30static int mock_in_rw;
31static VbError_t in_rw_retval;
32static int protect_retval;
33static int ec_protected;
34static int run_retval;
35static int ec_run_image;
36static int update_retval;
37static int ec_updated;
38static int get_expected_retval;
39static int shutdown_request_calls_left;
40
41static uint8_t mock_ec_hash[32];
42static int mock_ec_hash_size;
43static uint8_t want_ec_hash[32];
44static int want_ec_hash_size;
45static uint8_t mock_sha[32];
46
47static uint32_t screens_displayed[8];
48static uint32_t screens_count = 0;
49
50/* Reset mock data (for use before each test) */
51static 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
105uint32_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
115int VbExTrustEC(int devidx)
116{
117	return trust_ec;
118}
119
120VbError_t VbExEcRunningRW(int devidx, int *in_rw)
121{
122	*in_rw = mock_in_rw;
123	return in_rw_retval;
124}
125
126VbError_t VbExEcProtectRW(int devidx)
127{
128	ec_protected = 1;
129	return protect_retval;
130}
131
132VbError_t VbExEcDisableJump(int devidx)
133{
134	return run_retval;
135}
136
137VbError_t VbExEcJumpToRW(int devidx)
138{
139	ec_run_image = 1;
140	return run_retval;
141}
142
143VbError_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
150VbError_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
159VbError_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
171uint8_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
177VbError_t VbExEcUpdateRW(int devidx, const uint8_t *image, int image_size)
178{
179	ec_updated = 1;
180	return update_retval;
181}
182
183VbError_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
192static 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
203static 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
364int main(void)
365{
366	VbSoftwareSyncTest();
367
368	if (vboot_api_stub_check_memory())
369		return 255;
370
371	return gTestSuccess ? 0 : 255;
372}
373