Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(173)

Side by Side Diff: firmware/lib/vboot_kernel.c

Issue 6594092: Support NvStorage and kernkey_vfy in LoadKernel() (Closed) Base URL: ssh://git@gitrw.chromium.org:9222/vboot_reference.git@master
Patch Set: Fix comment Created 9 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « firmware/include/vboot_nvstorage.h ('k') | utility/load_kernel_test.c » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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, &params->partition_guid); 407 GetCurrentKernelUniqueGuid(&gpt, &params->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
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 }
OLDNEW
« no previous file with comments | « firmware/include/vboot_nvstorage.h ('k') | utility/load_kernel_test.c » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698