32a35eca5462a092a668af887aac47f8efb11272
[vboot.git] / tests / vboot_api_kernel3_tests.c
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) */
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
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
115 int VbExTrustEC(int devidx)
116 {
117         return trust_ec;
118 }
119
120 VbError_t VbExEcRunningRW(int devidx, int *in_rw)
121 {
122         *in_rw = mock_in_rw;
123         return in_rw_retval;
124 }
125
126 VbError_t VbExEcProtectRW(int devidx)
127 {
128         ec_protected = 1;
129         return protect_retval;
130 }
131
132 VbError_t VbExEcDisableJump(int devidx)
133 {
134         return run_retval;
135 }
136
137 VbError_t VbExEcJumpToRW(int devidx)
138 {
139         ec_run_image = 1;
140         return run_retval;
141 }
142
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
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
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
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
177 VbError_t VbExEcUpdateRW(int devidx, const uint8_t *image, int image_size)
178 {
179         ec_updated = 1;
180         return update_retval;
181 }
182
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
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
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
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 }