OLD | NEW |
1 /* Copyright (c) 2010 The Chromium OS Authors. All rights reserved. | 1 /* Copyright (c) 2010 The Chromium OS Authors. All rights reserved. |
2 * Use of this source code is governed by a BSD-style license that can be | 2 * Use of this source code is governed by a BSD-style license that can be |
3 * found in the LICENSE file. | 3 * found in the LICENSE file. |
4 * | 4 * |
5 * High-level firmware API for loading and verifying rewritable firmware. | 5 * High-level firmware API for loading and verifying rewritable firmware. |
6 * (Firmware portion) | 6 * (Firmware portion) |
7 */ | 7 */ |
8 | 8 |
9 #include "load_firmware_fw.h" | 9 #include "load_firmware_fw.h" |
10 #include "rollback_index.h" | 10 #include "rollback_index.h" |
11 #include "utility.h" | 11 #include "utility.h" |
12 #include "vboot_common.h" | 12 #include "vboot_common.h" |
| 13 #include "vboot_nvstorage.h" |
13 | 14 |
14 /* Static variables for UpdateFirmwareBodyHash(). It's less than | 15 /* Static variables for UpdateFirmwareBodyHash(). It's less than |
15 * optimal to have static variables in a library, but in UEFI the | 16 * optimal to have static variables in a library, but in UEFI the |
16 * caller is deep inside a different firmware stack and doesn't have a | 17 * caller is deep inside a different firmware stack and doesn't have a |
17 * good way to pass the params struct back to us. */ | 18 * good way to pass the params struct back to us. */ |
18 typedef struct VbLoadFirmwareInternal { | 19 typedef struct VbLoadFirmwareInternal { |
19 DigestContext body_digest_context; | 20 DigestContext body_digest_context; |
20 uint64_t body_size_accum; | 21 uint64_t body_size_accum; |
21 } VbLoadFirmwareInternal; | 22 } VbLoadFirmwareInternal; |
22 | 23 |
23 | 24 |
24 void UpdateFirmwareBodyHash(LoadFirmwareParams* params, | 25 void UpdateFirmwareBodyHash(LoadFirmwareParams* params, |
25 uint8_t* data, uint64_t size) { | 26 uint8_t* data, uint64_t size) { |
26 VbLoadFirmwareInternal* lfi = | 27 VbLoadFirmwareInternal* lfi = |
27 (VbLoadFirmwareInternal*)params->load_firmware_internal; | 28 (VbLoadFirmwareInternal*)params->load_firmware_internal; |
28 | 29 |
29 DigestUpdate(&lfi->body_digest_context, data, size); | 30 DigestUpdate(&lfi->body_digest_context, data, size); |
30 lfi->body_size_accum += size; | 31 lfi->body_size_accum += size; |
31 } | 32 } |
32 | 33 |
33 | 34 |
| 35 int LoadFirmwareSetup(void) { |
| 36 /* TODO: start initializing the TPM */ |
| 37 return LOAD_FIRMWARE_SUCCESS; |
| 38 } |
| 39 |
| 40 |
34 int LoadFirmware(LoadFirmwareParams* params) { | 41 int LoadFirmware(LoadFirmwareParams* params) { |
35 | 42 |
36 VbPublicKey* root_key = (VbPublicKey*)params->firmware_root_key_blob; | 43 VbPublicKey* root_key = (VbPublicKey*)params->firmware_root_key_blob; |
37 VbLoadFirmwareInternal* lfi; | 44 VbLoadFirmwareInternal* lfi; |
| 45 VbNvContext* vnc = params->nv_context; |
38 | 46 |
| 47 uint32_t try_b_count; |
39 uint32_t tpm_version = 0; | 48 uint32_t tpm_version = 0; |
40 uint64_t lowest_version = 0xFFFFFFFF; | 49 uint64_t lowest_version = 0xFFFFFFFF; |
41 uint32_t status; | 50 uint32_t status; |
42 int good_index = -1; | 51 int good_index = -1; |
43 int is_dev; | 52 int is_dev; |
44 int index; | 53 int index; |
| 54 int i; |
| 55 |
| 56 int retval = LOAD_FIRMWARE_RECOVERY; |
| 57 int recovery = VBNV_RECOVERY_RO_UNSPECIFIED; |
45 | 58 |
46 /* Clear output params in case we fail */ | 59 /* Clear output params in case we fail */ |
47 params->firmware_index = 0; | 60 params->firmware_index = 0; |
48 | 61 |
49 VBDEBUG(("LoadFirmware started...\n")); | 62 VBDEBUG(("LoadFirmware started...\n")); |
50 | 63 |
| 64 /* Setup NV storage */ |
| 65 VbNvSetup(vnc); |
| 66 |
51 if (params->kernel_sign_key_size < sizeof(VbPublicKey)) { | 67 if (params->kernel_sign_key_size < sizeof(VbPublicKey)) { |
52 VBDEBUG(("Kernel sign key buffer too small\n")); | 68 VBDEBUG(("Kernel sign key buffer too small\n")); |
53 return LOAD_FIRMWARE_RECOVERY; | 69 goto LoadFirmwareExit; |
54 } | 70 } |
55 | 71 |
56 /* Must have a root key */ | 72 /* Must have a root key */ |
57 if (!root_key) { | 73 if (!root_key) { |
58 VBDEBUG(("No root key\n")); | 74 VBDEBUG(("No root key\n")); |
59 return LOAD_FIRMWARE_RECOVERY; | 75 goto LoadFirmwareExit; |
60 } | 76 } |
61 | 77 |
62 /* Parse flags */ | 78 /* Parse flags */ |
63 is_dev = (params->boot_flags & BOOT_FLAG_DEVELOPER ? 1 : 0); | 79 is_dev = (params->boot_flags & BOOT_FLAG_DEVELOPER ? 1 : 0); |
64 | 80 |
65 /* Initialize the TPM and read rollback indices. */ | 81 /* Initialize the TPM and read rollback indices. */ |
66 VBPERFSTART("VB_TPMI"); | 82 VBPERFSTART("VB_TPMI"); |
67 status = RollbackFirmwareSetup(is_dev, &tpm_version); | 83 status = RollbackFirmwareSetup(is_dev, &tpm_version); |
68 if (0 != status) { | 84 if (0 != status) { |
69 VBDEBUG(("Unable to setup TPM and read stored versions.\n")); | 85 VBDEBUG(("Unable to setup TPM and read stored versions.\n")); |
70 VBPERFEND("VB_TPMI"); | 86 VBPERFEND("VB_TPMI"); |
71 return (status == TPM_E_MUST_REBOOT ? | 87 if (status == TPM_E_MUST_REBOOT) |
72 LOAD_FIRMWARE_REBOOT : LOAD_FIRMWARE_RECOVERY_TPM); | 88 retval = LOAD_FIRMWARE_REBOOT; |
| 89 else |
| 90 recovery = VBNV_RECOVERY_RO_TPM_ERROR; |
| 91 goto LoadFirmwareExit; |
73 } | 92 } |
74 VBPERFEND("VB_TPMI"); | 93 VBPERFEND("VB_TPMI"); |
75 | 94 |
| 95 /* Read try-b count and decrement if necessary */ |
| 96 VbNvGet(vnc, VBNV_TRY_B_COUNT, &try_b_count); |
| 97 if (0 != try_b_count) |
| 98 VbNvSet(vnc, VBNV_TRY_B_COUNT, try_b_count - 1); |
| 99 VbNvSet(vnc, VBNV_TRIED_FIRMWARE_B, try_b_count ? 1 : 0); |
| 100 |
76 /* Allocate our internal data */ | 101 /* Allocate our internal data */ |
77 lfi = (VbLoadFirmwareInternal*)Malloc(sizeof(VbLoadFirmwareInternal)); | 102 lfi = (VbLoadFirmwareInternal*)Malloc(sizeof(VbLoadFirmwareInternal)); |
78 if (!lfi) | 103 if (!lfi) |
79 return LOAD_FIRMWARE_RECOVERY; | 104 return LOAD_FIRMWARE_RECOVERY; |
80 | 105 |
81 params->load_firmware_internal = (uint8_t*)lfi; | 106 params->load_firmware_internal = (uint8_t*)lfi; |
82 | 107 |
83 /* Loop over indices */ | 108 /* Loop over indices */ |
84 for (index = 0; index < 2; index++) { | 109 for (i = 0; i < 2; i++) { |
85 VbKeyBlockHeader* key_block; | 110 VbKeyBlockHeader* key_block; |
86 uint64_t vblock_size; | 111 uint64_t vblock_size; |
87 VbFirmwarePreambleHeader* preamble; | 112 VbFirmwarePreambleHeader* preamble; |
88 RSAPublicKey* data_key; | 113 RSAPublicKey* data_key; |
89 uint64_t key_version; | 114 uint64_t key_version; |
90 uint64_t combined_version; | 115 uint64_t combined_version; |
91 uint8_t* body_digest; | 116 uint8_t* body_digest; |
92 | 117 |
| 118 /* If try B count is non-zero try firmware B first */ |
| 119 index = (try_b_count ? i : 1 - i); |
| 120 |
93 /* Verify the key block */ | 121 /* Verify the key block */ |
94 VBPERFSTART("VB_VKB"); | 122 VBPERFSTART("VB_VKB"); |
95 if (0 == index) { | 123 if (0 == index) { |
96 key_block = (VbKeyBlockHeader*)params->verification_block_0; | 124 key_block = (VbKeyBlockHeader*)params->verification_block_0; |
97 vblock_size = params->verification_size_0; | 125 vblock_size = params->verification_size_0; |
98 } else { | 126 } else { |
99 key_block = (VbKeyBlockHeader*)params->verification_block_1; | 127 key_block = (VbKeyBlockHeader*)params->verification_block_1; |
100 vblock_size = params->verification_size_1; | 128 vblock_size = params->verification_size_1; |
101 } | 129 } |
102 if ((0 != KeyBlockVerify(key_block, vblock_size, root_key, 0))) { | 130 if ((0 != KeyBlockVerify(key_block, vblock_size, root_key, 0))) { |
(...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
241 /* Handle finding good firmware */ | 269 /* Handle finding good firmware */ |
242 if (good_index >= 0) { | 270 if (good_index >= 0) { |
243 | 271 |
244 /* Update TPM if necessary */ | 272 /* Update TPM if necessary */ |
245 if (lowest_version > tpm_version) { | 273 if (lowest_version > tpm_version) { |
246 VBPERFSTART("VB_TPMU"); | 274 VBPERFSTART("VB_TPMU"); |
247 status = RollbackFirmwareWrite((uint32_t)lowest_version); | 275 status = RollbackFirmwareWrite((uint32_t)lowest_version); |
248 VBPERFEND("VB_TPMU"); | 276 VBPERFEND("VB_TPMU"); |
249 if (0 != status) { | 277 if (0 != status) { |
250 VBDEBUG(("Unable to write stored versions.\n")); | 278 VBDEBUG(("Unable to write stored versions.\n")); |
251 return (status == TPM_E_MUST_REBOOT ? | 279 if (status == TPM_E_MUST_REBOOT) |
252 LOAD_FIRMWARE_REBOOT : LOAD_FIRMWARE_RECOVERY_TPM); | 280 retval = LOAD_FIRMWARE_REBOOT; |
| 281 else |
| 282 recovery = VBNV_RECOVERY_RO_TPM_ERROR; |
| 283 goto LoadFirmwareExit; |
253 } | 284 } |
254 } | 285 } |
255 | 286 |
256 /* Lock firmware versions in TPM */ | 287 /* Lock firmware versions in TPM */ |
257 VBPERFSTART("VB_TPML"); | 288 VBPERFSTART("VB_TPML"); |
258 status = RollbackFirmwareLock(); | 289 status = RollbackFirmwareLock(); |
259 VBPERFEND("VB_TPML"); | 290 VBPERFEND("VB_TPML"); |
260 if (0 != status) { | 291 if (0 != status) { |
261 VBDEBUG(("Unable to lock firmware versions.\n")); | 292 VBDEBUG(("Unable to lock firmware versions.\n")); |
262 return (status == TPM_E_MUST_REBOOT ? | 293 if (status == TPM_E_MUST_REBOOT) |
263 LOAD_FIRMWARE_REBOOT : LOAD_FIRMWARE_RECOVERY_TPM); | 294 retval = LOAD_FIRMWARE_REBOOT; |
| 295 else |
| 296 recovery = VBNV_RECOVERY_RO_TPM_ERROR; |
| 297 goto LoadFirmwareExit; |
264 } | 298 } |
265 | 299 |
266 /* Success */ | 300 /* Success */ |
267 VBDEBUG(("Will boot firmware index %d\n", (int)params->firmware_index)); | 301 VBDEBUG(("Will boot firmware index %d\n", (int)params->firmware_index)); |
268 return LOAD_FIRMWARE_SUCCESS; | 302 retval = LOAD_FIRMWARE_SUCCESS; |
| 303 } else { |
| 304 /* No good firmware, so go to recovery mode. */ |
| 305 VBDEBUG(("Alas, no good firmware.\n")); |
| 306 recovery = VBNV_RECOVERY_RO_INVALID_RW; |
269 } | 307 } |
270 | 308 |
271 /* If we're still here, no good firmware, so go to recovery mode. */ | 309 LoadFirmwareExit: |
272 VBDEBUG(("Alas, no good firmware.\n")); | 310 /* Store recovery request, if any, then tear down non-volatile storage */ |
273 return LOAD_FIRMWARE_RECOVERY; | 311 VbNvSet(vnc, VBNV_RECOVERY_REQUEST, LOAD_FIRMWARE_RECOVERY == retval ? |
| 312 recovery : VBNV_RECOVERY_NOT_REQUESTED); |
| 313 VbNvTeardown(vnc); |
| 314 |
| 315 return retval; |
274 } | 316 } |
275 | 317 |
276 | 318 |
277 int S3Resume(void) { | 319 int S3Resume(void) { |
278 /* Resume the TPM */ | 320 /* Resume the TPM */ |
279 uint32_t status = RollbackS3Resume(); | 321 uint32_t status = RollbackS3Resume(); |
280 | 322 |
| 323 /* If we can't resume, just do a full reboot. No need to go to recovery |
| 324 * mode here, since if the TPM is really broken we'll catch it on the |
| 325 * next boot. */ |
281 if (status == TPM_SUCCESS) | 326 if (status == TPM_SUCCESS) |
282 return LOAD_FIRMWARE_SUCCESS; | 327 return LOAD_FIRMWARE_SUCCESS; |
283 else if (status == TPM_E_MUST_REBOOT) | 328 else |
284 return LOAD_FIRMWARE_REBOOT; | 329 return LOAD_FIRMWARE_REBOOT; |
285 else | |
286 return LOAD_FIRMWARE_RECOVERY_TPM; | |
287 } | 330 } |
OLD | NEW |