Home | History | Annotate | Download | only in tests
      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 }
    373