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