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 * Functions for loading a kernel from disk. | 5 * Functions for loading a kernel from disk. |
6 * (Firmware portion) | 6 * (Firmware portion) |
7 */ | 7 */ |
8 | 8 |
9 #include "vboot_kernel.h" | 9 #include "vboot_kernel.h" |
10 | 10 |
11 #include "boot_device.h" | 11 #include "boot_device.h" |
12 #include "cgptlib.h" | 12 #include "cgptlib.h" |
13 #include "cgptlib_internal.h" | 13 #include "cgptlib_internal.h" |
14 #include "load_kernel_fw.h" | 14 #include "load_kernel_fw.h" |
15 #include "rollback_index.h" | 15 #include "rollback_index.h" |
16 #include "utility.h" | 16 #include "utility.h" |
17 #include "vboot_common.h" | 17 #include "vboot_common.h" |
18 | 18 |
19 #define KBUF_SIZE 65536 /* Bytes to read at start of kernel partition */ | 19 #define KBUF_SIZE 65536 /* Bytes to read at start of kernel partition */ |
20 | 20 |
| 21 typedef enum BootMode { |
| 22 kBootNormal, /* Normal firmware */ |
| 23 kBootDev, /* Dev firmware AND dev switch is on */ |
| 24 kBootRecovery /* Recovery firmware, regardless of dev switch position */ |
| 25 } BootMode; |
| 26 |
21 | 27 |
22 /* Allocates and reads GPT data from the drive. The sector_bytes and | 28 /* Allocates and reads GPT data from the drive. The sector_bytes and |
23 * drive_sectors fields should be filled on input. The primary and | 29 * drive_sectors fields should be filled on input. The primary and |
24 * secondary header and entries are filled on output. | 30 * secondary header and entries are filled on output. |
25 * | 31 * |
26 * Returns 0 if successful, 1 if error. */ | 32 * Returns 0 if successful, 1 if error. */ |
27 int AllocAndReadGptData(GptData* gptdata) { | 33 int AllocAndReadGptData(GptData* gptdata) { |
28 | 34 |
29 uint64_t entries_sectors = TOTAL_ENTRIES_SIZE / gptdata->sector_bytes; | 35 uint64_t entries_sectors = TOTAL_ENTRIES_SIZE / gptdata->sector_bytes; |
30 | 36 |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
105 } | 111 } |
106 | 112 |
107 /* Success */ | 113 /* Success */ |
108 return 0; | 114 return 0; |
109 } | 115 } |
110 | 116 |
111 /* disable MSVC warning on const logical expression (as in } while(0);) */ | 117 /* disable MSVC warning on const logical expression (as in } while(0);) */ |
112 __pragma(warning(disable: 4127)) | 118 __pragma(warning(disable: 4127)) |
113 | 119 |
114 int LoadKernel(LoadKernelParams* params) { | 120 int LoadKernel(LoadKernelParams* params) { |
| 121 VbNvContext* vnc = params->nv_context; |
115 VbPublicKey* kernel_subkey; | 122 VbPublicKey* kernel_subkey; |
116 GptData gpt; | 123 GptData gpt; |
117 uint64_t part_start, part_size; | 124 uint64_t part_start, part_size; |
118 uint64_t blba; | 125 uint64_t blba; |
119 uint64_t kbuf_sectors; | 126 uint64_t kbuf_sectors; |
120 uint8_t* kbuf = NULL; | 127 uint8_t* kbuf = NULL; |
121 int found_partitions = 0; | 128 int found_partitions = 0; |
122 int good_partition = -1; | 129 int good_partition = -1; |
| 130 int good_partition_key_block_valid = 0; |
123 uint32_t tpm_version = 0; | 131 uint32_t tpm_version = 0; |
124 uint64_t lowest_version = 0xFFFFFFFF; | 132 uint64_t lowest_version = 0xFFFFFFFF; |
125 int is_dev; | 133 int rec_switch, dev_switch; |
126 int is_rec; | 134 BootMode boot_mode; |
127 int is_normal; | |
128 uint32_t status; | 135 uint32_t status; |
129 | 136 |
| 137 /* TODO: differentiate between finding an invalid kernel (found_partitions>0) |
| 138 * and not finding one at all. Right now we treat them the same, and return |
| 139 * LOAD_KERNEL_INVALID for both. */ |
| 140 int retval = LOAD_KERNEL_INVALID; |
| 141 int recovery = VBNV_RECOVERY_RO_UNSPECIFIED; |
| 142 |
| 143 /* Setup NV storage */ |
| 144 VbNvSetup(vnc); |
| 145 |
130 /* Sanity Checks */ | 146 /* Sanity Checks */ |
131 if (!params || | 147 if (!params || |
132 !params->bytes_per_lba || | 148 !params->bytes_per_lba || |
133 !params->ending_lba || | 149 !params->ending_lba || |
134 !params->kernel_buffer || | 150 !params->kernel_buffer || |
135 !params->kernel_buffer_size) { | 151 !params->kernel_buffer_size) { |
136 VBDEBUG(("LoadKernel() called with invalid params\n")); | 152 VBDEBUG(("LoadKernel() called with invalid params\n")); |
137 return LOAD_KERNEL_INVALID; | 153 goto LoadKernelExit; |
138 } | 154 } |
139 | 155 |
140 /* Initialization */ | 156 /* Initialization */ |
141 kernel_subkey = (VbPublicKey*)params->header_sign_key_blob; | 157 kernel_subkey = (VbPublicKey*)params->header_sign_key_blob; |
142 blba = params->bytes_per_lba; | 158 blba = params->bytes_per_lba; |
143 kbuf_sectors = KBUF_SIZE / blba; | 159 kbuf_sectors = KBUF_SIZE / blba; |
144 if (0 == kbuf_sectors) { | 160 if (0 == kbuf_sectors) { |
145 VBDEBUG(("LoadKernel() called with sector size > KBUF_SIZE\n")); | 161 VBDEBUG(("LoadKernel() called with sector size > KBUF_SIZE\n")); |
146 return LOAD_KERNEL_INVALID; | 162 goto LoadKernelExit; |
147 } | 163 } |
148 | 164 |
149 is_rec = (BOOT_FLAG_RECOVERY & params->boot_flags ? 1 : 0); | 165 rec_switch = (BOOT_FLAG_RECOVERY & params->boot_flags ? 1 : 0); |
150 if (is_rec || (BOOT_FLAG_DEV_FIRMWARE & params->boot_flags)) { | 166 dev_switch = (BOOT_FLAG_DEVELOPER & params->boot_flags ? 1 : 0); |
151 /* Recovery or developer firmware, so accurately represent the | 167 |
152 * state of the developer switch for the purposes of verified boot. */ | 168 if (rec_switch) |
153 is_dev = (BOOT_FLAG_DEVELOPER & params->boot_flags ? 1 : 0); | 169 boot_mode = kBootRecovery; |
154 } else { | 170 else if (BOOT_FLAG_DEV_FIRMWARE & params->boot_flags) |
155 /* Normal firmware always does a fully verified boot regardless of | 171 if (!dev_switch) { |
156 * the state of the developer switch. */ | 172 /* Dev firmware should be signed such that it never boots with the dev |
157 is_dev = 0; | 173 * switch is off; so something is terribly wrong. */ |
| 174 VBDEBUG(("LoadKernel() called with dev firmware but dev switch off\n")); |
| 175 recovery = VBNV_RECOVERY_RW_DEV_MISMATCH; |
| 176 goto LoadKernelExit; |
| 177 } |
| 178 boot_mode = kBootDev; |
| 179 else { |
| 180 /* Normal firmware */ |
| 181 boot_mode = kBootNormal; |
| 182 dev_switch = 0; /* Always do a fully verified boot */ |
158 } | 183 } |
159 is_normal = (!is_dev && !is_rec); | |
160 | 184 |
161 /* Clear output params in case we fail */ | 185 /* Clear output params in case we fail */ |
162 params->partition_number = 0; | 186 params->partition_number = 0; |
163 params->bootloader_address = 0; | 187 params->bootloader_address = 0; |
164 params->bootloader_size = 0; | 188 params->bootloader_size = 0; |
165 | 189 |
166 /* Let the TPM know if we're in recovery mode */ | 190 /* Let the TPM know if we're in recovery mode */ |
167 if (is_rec) { | 191 if (kBootRecovery == boot_mode) { |
168 if (0 != RollbackKernelRecovery(is_dev)) { | 192 if (0 != RollbackKernelRecovery(dev_switch)) { |
169 VBDEBUG(("Error setting up TPM for recovery kernel\n")); | 193 VBDEBUG(("Error setting up TPM for recovery kernel\n")); |
170 /* Ignore return code, since we need to boot recovery mode to | 194 /* Ignore return code, since we need to boot recovery mode to |
171 * fix the TPM. */ | 195 * fix the TPM. */ |
172 } | 196 } |
173 } | 197 } else { |
174 | |
175 if (is_normal) { | |
176 /* Read current kernel key index from TPM. Assumes TPM is already | 198 /* Read current kernel key index from TPM. Assumes TPM is already |
177 * initialized. */ | 199 * initialized. */ |
178 status = RollbackKernelRead(&tpm_version); | 200 status = RollbackKernelRead(&tpm_version); |
179 if (0 != status) { | 201 if (0 != status) { |
180 VBDEBUG(("Unable to get kernel versions from TPM\n")); | 202 VBDEBUG(("Unable to get kernel versions from TPM\n")); |
181 return (status == TPM_E_MUST_REBOOT ? | 203 if (status == TPM_E_MUST_REBOOT) |
182 LOAD_KERNEL_REBOOT : LOAD_KERNEL_RECOVERY); | 204 retval = LOAD_KERNEL_REBOOT; |
| 205 else |
| 206 recovery = VBNV_RECOVERY_RW_TPM_ERROR; |
| 207 goto LoadKernelExit; |
183 } | 208 } |
184 } | 209 } |
185 | 210 |
186 do { | 211 do { |
187 /* Read GPT data */ | 212 /* Read GPT data */ |
188 gpt.sector_bytes = (uint32_t)blba; | 213 gpt.sector_bytes = (uint32_t)blba; |
189 gpt.drive_sectors = params->ending_lba + 1; | 214 gpt.drive_sectors = params->ending_lba + 1; |
190 if (0 != AllocAndReadGptData(&gpt)) { | 215 if (0 != AllocAndReadGptData(&gpt)) { |
191 VBDEBUG(("Unable to read GPT data\n")); | 216 VBDEBUG(("Unable to read GPT data\n")); |
192 break; | 217 break; |
(...skipping 13 matching lines...) Expand all Loading... |
206 /* Loop over candidate kernel partitions */ | 231 /* Loop over candidate kernel partitions */ |
207 while (GPT_SUCCESS == GptNextKernelEntry(&gpt, &part_start, &part_size)) { | 232 while (GPT_SUCCESS == GptNextKernelEntry(&gpt, &part_start, &part_size)) { |
208 VbKeyBlockHeader* key_block; | 233 VbKeyBlockHeader* key_block; |
209 VbKernelPreambleHeader* preamble; | 234 VbKernelPreambleHeader* preamble; |
210 RSAPublicKey* data_key = NULL; | 235 RSAPublicKey* data_key = NULL; |
211 uint64_t key_version; | 236 uint64_t key_version; |
212 uint64_t combined_version; | 237 uint64_t combined_version; |
213 uint64_t body_offset; | 238 uint64_t body_offset; |
214 uint64_t body_offset_sectors; | 239 uint64_t body_offset_sectors; |
215 uint64_t body_sectors; | 240 uint64_t body_sectors; |
| 241 int key_block_valid = 1; |
216 | 242 |
217 VBDEBUG(("Found kernel entry at %" PRIu64 " size %" PRIu64 "\n", | 243 VBDEBUG(("Found kernel entry at %" PRIu64 " size %" PRIu64 "\n", |
218 part_start, part_size)); | 244 part_start, part_size)); |
219 | 245 |
220 /* Found at least one kernel partition. */ | 246 /* Found at least one kernel partition. */ |
221 found_partitions++; | 247 found_partitions++; |
222 | 248 |
223 /* Read the first part of the kernel partition */ | 249 /* Read the first part of the kernel partition. */ |
224 if (part_size < kbuf_sectors) { | 250 if (part_size < kbuf_sectors) { |
225 VBDEBUG(("Partition too small to hold kernel.\n")); | 251 VBDEBUG(("Partition too small to hold kernel.\n")); |
226 goto bad_kernel; | 252 goto bad_kernel; |
227 } | 253 } |
228 | 254 |
229 if (0 != BootDeviceReadLBA(part_start, kbuf_sectors, kbuf)) { | 255 if (0 != BootDeviceReadLBA(part_start, kbuf_sectors, kbuf)) { |
230 VBDEBUG(("Unable to read start of partition.\n")); | 256 VBDEBUG(("Unable to read start of partition.\n")); |
231 goto bad_kernel; | 257 goto bad_kernel; |
232 } | 258 } |
233 | 259 |
234 /* Verify the key block. In developer mode, we ignore the key | 260 /* Verify the key block. */ |
235 * and use only the SHA-512 hash to verify the key block. */ | |
236 key_block = (VbKeyBlockHeader*)kbuf; | 261 key_block = (VbKeyBlockHeader*)kbuf; |
237 if ((0 != KeyBlockVerify(key_block, KBUF_SIZE, kernel_subkey, | 262 if (0 != KeyBlockVerify(key_block, KBUF_SIZE, kernel_subkey, 0)) { |
238 is_dev && !is_rec))) { | 263 VBDEBUG(("Verifying key block signature failed.\n")); |
239 VBDEBUG(("Verifying key block failed.\n")); | 264 key_block_valid = 0; |
240 goto bad_kernel; | |
241 } | |
242 | 265 |
243 /* Check the key block flags against the current boot mode in normal | 266 /* If we're not in developer mode, this kernel is bad. */ |
244 * and recovery modes (not in developer mode booting from SSD). */ | 267 if (kBootDev != boot_mode) |
245 if (is_rec || is_normal) { | |
246 if (!(key_block->key_block_flags & | |
247 (is_dev ? KEY_BLOCK_FLAG_DEVELOPER_1 : | |
248 KEY_BLOCK_FLAG_DEVELOPER_0))) { | |
249 VBDEBUG(("Developer flag mismatch.\n")); | |
250 goto bad_kernel; | 268 goto bad_kernel; |
251 } | 269 |
252 if (!(key_block->key_block_flags & | 270 /* In developer mode, we can continue if the SHA-512 hash of the key |
253 (is_rec ? KEY_BLOCK_FLAG_RECOVERY_1 : | 271 * block is valid. */ |
254 KEY_BLOCK_FLAG_RECOVERY_0))) { | 272 if (0 != KeyBlockVerify(key_block, KBUF_SIZE, kernel_subkey, 1)) { |
255 VBDEBUG(("Recovery flag mismatch.\n")); | 273 VBDEBUG(("Verifying key block hash failed.\n")); |
256 goto bad_kernel; | 274 goto bad_kernel; |
257 } | 275 } |
258 } | 276 } |
259 | 277 |
260 /* Check for rollback of key version. Note this is implicitly | 278 /* Check the key block flags against the current boot mode. */ |
261 * skipped in recovery and developer modes because those set | 279 if (!(key_block->key_block_flags & |
262 * key_version=0 above. */ | 280 (dev_switch ? KEY_BLOCK_FLAG_DEVELOPER_1 : |
| 281 KEY_BLOCK_FLAG_DEVELOPER_0))) { |
| 282 VBDEBUG(("Key block developer flag mismatch.\n")); |
| 283 key_block_valid = 0; |
| 284 } |
| 285 if (!(key_block->key_block_flags & |
| 286 (rec_switch ? KEY_BLOCK_FLAG_RECOVERY_1 : |
| 287 KEY_BLOCK_FLAG_RECOVERY_0))) { |
| 288 VBDEBUG(("Key block recovery flag mismatch.\n")); |
| 289 key_block_valid = 0; |
| 290 } |
| 291 |
| 292 /* Check for rollback of key version except in recovery mode. */ |
263 key_version = key_block->data_key.key_version; | 293 key_version = key_block->data_key.key_version; |
264 if (key_version < (tpm_version >> 16)) { | 294 if (kBootRecovery != boot_mode) { |
265 VBDEBUG(("Key version too old.\n")); | 295 if (key_version < (tpm_version >> 16)) { |
| 296 VBDEBUG(("Key version too old.\n")); |
| 297 key_block_valid = 0; |
| 298 } |
| 299 } |
| 300 |
| 301 /* If we're not in developer mode, require the key block to be valid. */ |
| 302 if (kBootDev != boot_mode && !key_block_valid) { |
| 303 VBDEBUG(("Key block is invalid.\n")); |
266 goto bad_kernel; | 304 goto bad_kernel; |
267 } | 305 } |
268 | 306 |
269 /* Get the key for preamble/data verification from the key block */ | 307 /* Get the key for preamble/data verification from the key block. */ |
270 data_key = PublicKeyToRSA(&key_block->data_key); | 308 data_key = PublicKeyToRSA(&key_block->data_key); |
271 if (!data_key) { | 309 if (!data_key) { |
272 VBDEBUG(("Data key bad.\n")); | 310 VBDEBUG(("Data key bad.\n")); |
273 goto bad_kernel; | 311 goto bad_kernel; |
274 } | 312 } |
275 | 313 |
276 /* Verify the preamble, which follows the key block */ | 314 /* Verify the preamble, which follows the key block */ |
277 preamble = (VbKernelPreambleHeader*)(kbuf + key_block->key_block_size); | 315 preamble = (VbKernelPreambleHeader*)(kbuf + key_block->key_block_size); |
278 if ((0 != VerifyKernelPreamble(preamble, | 316 if ((0 != VerifyKernelPreamble(preamble, |
279 KBUF_SIZE - key_block->key_block_size, | 317 KBUF_SIZE - key_block->key_block_size, |
280 data_key))) { | 318 data_key))) { |
281 VBDEBUG(("Preamble verification failed.\n")); | 319 VBDEBUG(("Preamble verification failed.\n")); |
282 goto bad_kernel; | 320 goto bad_kernel; |
283 } | 321 } |
284 | 322 |
285 /* Check for rollback of kernel version. Note this is implicitly | 323 /* If the key block is valid and we're not in recovery mode, check for |
286 * skipped in recovery and developer modes because rollback_index | 324 * rollback of the kernel version. */ |
287 * sets those to 0 in those modes. */ | |
288 combined_version = ((key_version << 16) | | 325 combined_version = ((key_version << 16) | |
289 (preamble->kernel_version & 0xFFFF)); | 326 (preamble->kernel_version & 0xFFFF)); |
290 if (combined_version < tpm_version) { | 327 if (key_block_valid && kBootRecovery != boot_mode) { |
291 VBDEBUG(("Kernel version too low.\n")); | 328 if (combined_version < tpm_version) { |
292 goto bad_kernel; | 329 VBDEBUG(("Kernel version too low.\n")); |
| 330 /* If we're not in developer mode, kernel version must be valid. */ |
| 331 if (kBootDev != boot_mode) |
| 332 goto bad_kernel; |
| 333 } |
293 } | 334 } |
294 | 335 |
295 VBDEBUG(("Kernel preamble is good.\n")); | 336 VBDEBUG(("Kernel preamble is good.\n")); |
296 | 337 |
297 /* Check for lowest version from a valid header. */ | 338 /* Check for lowest version from a valid header. */ |
298 if (lowest_version > combined_version) | 339 if (key_block_valid && lowest_version > combined_version) |
299 lowest_version = combined_version; | 340 lowest_version = combined_version; |
300 | 341 |
301 /* If we already have a good kernel, no need to read another | 342 /* If we already have a good kernel, no need to read another |
302 * one; we only needed to look at the versions to check for | 343 * one; we only needed to look at the versions to check for |
303 * rollback. So skip to the next kernel preamble. */ | 344 * rollback. So skip to the next kernel preamble. */ |
304 if (-1 != good_partition) | 345 if (-1 != good_partition) |
305 continue; | 346 continue; |
306 | 347 |
307 /* Verify body load address matches what we expect */ | 348 /* Verify body load address matches what we expect */ |
308 if ((preamble->body_load_address != (size_t)params->kernel_buffer) && | 349 if ((preamble->body_load_address != (size_t)params->kernel_buffer) && |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
350 VBDEBUG(("Kernel data verification failed.\n")); | 391 VBDEBUG(("Kernel data verification failed.\n")); |
351 goto bad_kernel; | 392 goto bad_kernel; |
352 } | 393 } |
353 | 394 |
354 /* Done with the kernel signing key, so can free it now */ | 395 /* Done with the kernel signing key, so can free it now */ |
355 RSAPublicKeyFree(data_key); | 396 RSAPublicKeyFree(data_key); |
356 data_key = NULL; | 397 data_key = NULL; |
357 | 398 |
358 /* If we're still here, the kernel is valid. */ | 399 /* If we're still here, the kernel is valid. */ |
359 /* Save the first good partition we find; that's the one we'll boot */ | 400 /* Save the first good partition we find; that's the one we'll boot */ |
360 VBDEBUG(("Partiton is good.\n")); | 401 VBDEBUG(("Partition is good.\n")); |
| 402 good_partition_key_block_valid = key_block_valid; |
361 /* TODO: GPT partitions start at 1, but cgptlib starts them at 0. | 403 /* TODO: GPT partitions start at 1, but cgptlib starts them at 0. |
362 * Adjust here, until cgptlib is fixed. */ | 404 * Adjust here, until cgptlib is fixed. */ |
363 good_partition = gpt.current_kernel + 1; | 405 good_partition = gpt.current_kernel + 1; |
364 params->partition_number = gpt.current_kernel + 1; | 406 params->partition_number = gpt.current_kernel + 1; |
365 GetCurrentKernelUniqueGuid(&gpt, ¶ms->partition_guid); | 407 GetCurrentKernelUniqueGuid(&gpt, ¶ms->partition_guid); |
366 /* TODO: GetCurrentKernelUniqueGuid() should take a destination size, or | 408 /* TODO: GetCurrentKernelUniqueGuid() should take a destination size, or |
367 * the dest should be a struct, so we know it's big enough. */ | 409 * the dest should be a struct, so we know it's big enough. */ |
368 params->bootloader_address = preamble->bootloader_address; | 410 params->bootloader_address = preamble->bootloader_address; |
369 params->bootloader_size = preamble->bootloader_size; | 411 params->bootloader_size = preamble->bootloader_size; |
370 | 412 |
371 /* Update GPT to note this is the kernel we're trying */ | 413 /* Update GPT to note this is the kernel we're trying */ |
372 GptUpdateKernelEntry(&gpt, GPT_UPDATE_ENTRY_TRY); | 414 GptUpdateKernelEntry(&gpt, GPT_UPDATE_ENTRY_TRY); |
373 | 415 |
374 /* If we're in developer or recovery mode, there's no rollback | 416 /* If we're in recovery mode or we're about to boot a dev-signed kernel, |
375 * protection, so we can stop at the first valid kernel. */ | 417 * there's no rollback protection, so we can stop at the first valid |
376 if (!is_normal) { | 418 * kernel. */ |
377 VBDEBUG(("Boot_flags = !is_normal\n")); | 419 if (kBootRecovery == boot_mode || !key_block_valid) { |
| 420 VBDEBUG(("In recovery mode or dev-signed kernel\n")); |
378 break; | 421 break; |
379 } | 422 } |
380 | 423 |
381 /* Otherwise, we're in normal boot mode, so we do care about the | 424 /* Otherwise, we do care about the key index in the TPM. If the good |
382 * key index in the TPM. If the good partition's key version is | 425 * partition's key version is the same as the tpm, then the TPM doesn't |
383 * the same as the tpm, then the TPM doesn't need updating; we | 426 * need updating; we can stop now. Otherwise, we'll check all the other |
384 * can stop now. Otherwise, we'll check all the other headers | 427 * headers to see if they contain a newer key. */ |
385 * to see if they contain a newer key. */ | |
386 if (combined_version == tpm_version) { | 428 if (combined_version == tpm_version) { |
387 VBDEBUG(("Same kernel version\n")); | 429 VBDEBUG(("Same kernel version\n")); |
388 break; | 430 break; |
389 } | 431 } |
390 | 432 |
391 /* Continue, so that we skip the error handling code below */ | 433 /* Continue, so that we skip the error handling code below */ |
392 continue; | 434 continue; |
393 | 435 |
394 bad_kernel: | 436 bad_kernel: |
395 /* Handle errors parsing this kernel */ | 437 /* Handle errors parsing this kernel */ |
(...skipping 12 matching lines...) Expand all Loading... |
408 Free(kbuf); | 450 Free(kbuf); |
409 | 451 |
410 /* Write and free GPT data */ | 452 /* Write and free GPT data */ |
411 WriteAndFreeGptData(&gpt); | 453 WriteAndFreeGptData(&gpt); |
412 | 454 |
413 /* Handle finding a good partition */ | 455 /* Handle finding a good partition */ |
414 if (good_partition >= 0) { | 456 if (good_partition >= 0) { |
415 VBDEBUG(("Good_partition >= 0\n")); | 457 VBDEBUG(("Good_partition >= 0\n")); |
416 | 458 |
417 /* See if we need to update the TPM */ | 459 /* See if we need to update the TPM */ |
418 if (is_normal) { | 460 if (kBootRecovery != boot_mode) { |
419 /* We only update the TPM in normal boot mode. In developer | 461 /* We only update the TPM in normal and developer boot modes. In |
420 * mode, the kernel is self-signed by the developer, so we can't | 462 * developer mode, we only advanced lowest_version for kernels with valid |
421 * trust the key version and wouldn't want to roll the TPM | 463 * key blocks, and didn't count self-signed key blocks. In recovery |
422 * forward. In recovery mode, the TPM stays PP-unlocked, so | 464 * mode, the TPM stays PP-unlocked, so anything we write gets blown away |
423 * anything we write gets blown away by the firmware when we go | 465 * by the firmware when we go back to normal mode. */ |
424 * back to normal mode. */ | 466 VBDEBUG(("Boot_flags = not recovery\n")); |
425 VBDEBUG(("Boot_flags = is_normal\n")); | |
426 if (lowest_version > tpm_version) { | 467 if (lowest_version > tpm_version) { |
427 status = RollbackKernelWrite((uint32_t)lowest_version); | 468 status = RollbackKernelWrite((uint32_t)lowest_version); |
428 if (0 != status) { | 469 if (0 != status) { |
429 VBDEBUG(("Error writing kernel versions to TPM.\n")); | 470 VBDEBUG(("Error writing kernel versions to TPM.\n")); |
430 return (status == TPM_E_MUST_REBOOT ? | 471 if (status == TPM_E_MUST_REBOOT) |
431 LOAD_KERNEL_REBOOT : LOAD_KERNEL_RECOVERY); | 472 retval = LOAD_KERNEL_REBOOT; |
| 473 else |
| 474 recovery = VBNV_RECOVERY_RW_TPM_ERROR; |
| 475 goto LoadKernelExit; |
432 } | 476 } |
433 } | 477 } |
434 } | 478 } |
435 | 479 |
436 /* Lock the kernel versions */ | 480 /* Lock the kernel versions */ |
437 status = RollbackKernelLock(); | 481 status = RollbackKernelLock(); |
438 if (0 != status) { | 482 if (0 != status) { |
439 VBDEBUG(("Error locking kernel versions.\n")); | 483 VBDEBUG(("Error locking kernel versions.\n")); |
440 /* Don't reboot to recovery mode if we're already there */ | 484 /* Don't reboot to recovery mode if we're already there */ |
441 if (!is_rec) | 485 if (kBootRecovery != boot_mode) { |
442 return (status == TPM_E_MUST_REBOOT ? | 486 if (status == TPM_E_MUST_REBOOT) |
443 LOAD_KERNEL_REBOOT : LOAD_KERNEL_RECOVERY); | 487 retval = LOAD_KERNEL_REBOOT; |
| 488 else |
| 489 recovery = VBNV_RECOVERY_RW_TPM_ERROR; |
| 490 goto LoadKernelExit; |
| 491 } |
444 } | 492 } |
445 | 493 |
446 /* Success! */ | 494 /* Success! */ |
447 return LOAD_KERNEL_SUCCESS; | 495 retval = LOAD_KERNEL_SUCCESS; |
448 } | 496 } |
449 | 497 |
450 /* The BIOS may attempt to display different screens depending on whether | 498 LoadKernelExit: |
451 * we find an invalid kernel partition (return LOAD_KERNEL_INVALID) or not. | 499 |
452 * But the flow is changing, so for now treating both cases as invalid gives | 500 /* Save whether the good partition's key block was fully verified */ |
453 * slightly less confusing user feedback. Sigh. | 501 VbNvSet(vnc, VBNV_FW_VERIFIED_KERNEL_KEY, good_partition_key_block_valid); |
454 */ | 502 |
455 return LOAD_KERNEL_INVALID; | 503 /* Store recovery request, if any, then tear down non-volatile storage */ |
| 504 VbNvSet(vnc, VBNV_RECOVERY_REQUEST, LOAD_KERNEL_RECOVERY == retval ? |
| 505 recovery : VBNV_RECOVERY_NOT_REQUESTED); |
| 506 VbNvTeardown(vnc); |
| 507 |
| 508 return retval; |
456 } | 509 } |
OLD | NEW |