| Randall Spangler | 95c4031 | 2011-03-09 15:54:16 -0800 | [diff] [blame] | 1 | /* Copyright (c) 2011 The Chromium OS Authors. All rights reserved. | 
| Randall Spangler | d183644 | 2010-06-10 09:59:04 -0700 | [diff] [blame] | 2 |  * Use of this source code is governed by a BSD-style license that can be | 
 | 3 |  * found in the LICENSE file. | 
 | 4 |  * | 
 | 5 |  * Functions for loading a kernel from disk. | 
 | 6 |  * (Firmware portion) | 
 | 7 |  */ | 
 | 8 |  | 
 | 9 | #include "vboot_kernel.h" | 
 | 10 |  | 
 | 11 | #include "boot_device.h" | 
 | 12 | #include "cgptlib.h" | 
| Bill Richardson | 5deb67f | 2010-07-23 17:22:25 -0700 | [diff] [blame] | 13 | #include "cgptlib_internal.h" | 
| Randall Spangler | 95c4031 | 2011-03-09 15:54:16 -0800 | [diff] [blame] | 14 | #include "gbb_header.h" | 
| Randall Spangler | d183644 | 2010-06-10 09:59:04 -0700 | [diff] [blame] | 15 | #include "load_kernel_fw.h" | 
 | 16 | #include "rollback_index.h" | 
 | 17 | #include "utility.h" | 
| Randall Spangler | 83c88cf | 2010-06-11 16:14:18 -0700 | [diff] [blame] | 18 | #include "vboot_common.h" | 
 | 19 |  | 
| Randall Spangler | d183644 | 2010-06-10 09:59:04 -0700 | [diff] [blame] | 20 | #define KBUF_SIZE 65536  /* Bytes to read at start of kernel partition */ | 
 | 21 |  | 
| Randall Spangler | 640fb51 | 2011-03-03 10:11:17 -0800 | [diff] [blame] | 22 | typedef enum BootMode { | 
 | 23 |   kBootNormal,   /* Normal firmware */ | 
 | 24 |   kBootDev,      /* Dev firmware AND dev switch is on */ | 
 | 25 |   kBootRecovery  /* Recovery firmware, regardless of dev switch position */ | 
 | 26 | } BootMode; | 
 | 27 |  | 
| Randall Spangler | 83c88cf | 2010-06-11 16:14:18 -0700 | [diff] [blame] | 28 |  | 
 | 29 | /* Allocates and reads GPT data from the drive.  The sector_bytes and | 
 | 30 |  * drive_sectors fields should be filled on input.  The primary and | 
 | 31 |  * secondary header and entries are filled on output. | 
 | 32 |  * | 
 | 33 |  * Returns 0 if successful, 1 if error. */ | 
 | 34 | int AllocAndReadGptData(GptData* gptdata) { | 
 | 35 |  | 
 | 36 |   uint64_t entries_sectors = TOTAL_ENTRIES_SIZE / gptdata->sector_bytes; | 
 | 37 |  | 
 | 38 |   /* No data to be written yet */ | 
 | 39 |   gptdata->modified = 0; | 
 | 40 |  | 
 | 41 |   /* Allocate all buffers */ | 
 | 42 |   gptdata->primary_header = (uint8_t*)Malloc(gptdata->sector_bytes); | 
 | 43 |   gptdata->secondary_header = (uint8_t*)Malloc(gptdata->sector_bytes); | 
 | 44 |   gptdata->primary_entries = (uint8_t*)Malloc(TOTAL_ENTRIES_SIZE); | 
 | 45 |   gptdata->secondary_entries = (uint8_t*)Malloc(TOTAL_ENTRIES_SIZE); | 
 | 46 |  | 
 | 47 |   if (gptdata->primary_header == NULL || gptdata->secondary_header == NULL || | 
 | 48 |       gptdata->primary_entries == NULL || gptdata->secondary_entries == NULL) | 
 | 49 |     return 1; | 
 | 50 |  | 
 | 51 |   /* Read data from the drive, skipping the protective MBR */ | 
 | 52 |   if (0 != BootDeviceReadLBA(1, 1, gptdata->primary_header)) | 
 | 53 |     return 1; | 
 | 54 |   if (0 != BootDeviceReadLBA(2, entries_sectors, gptdata->primary_entries)) | 
 | 55 |     return 1; | 
 | 56 |   if (0 != BootDeviceReadLBA(gptdata->drive_sectors - entries_sectors - 1, | 
 | 57 |                              entries_sectors, gptdata->secondary_entries)) | 
 | 58 |     return 1; | 
 | 59 |   if (0 != BootDeviceReadLBA(gptdata->drive_sectors - 1, | 
 | 60 |                              1, gptdata->secondary_header)) | 
 | 61 |     return 1; | 
 | 62 |  | 
 | 63 |   return 0; | 
 | 64 | } | 
 | 65 |  | 
 | 66 |  | 
 | 67 | /* Writes any changes for the GPT data back to the drive, then frees | 
 | 68 |  * the buffers. | 
 | 69 |  * | 
 | 70 |  * Returns 0 if successful, 1 if error. */ | 
 | 71 | int WriteAndFreeGptData(GptData* gptdata) { | 
 | 72 |  | 
 | 73 |   uint64_t entries_sectors = TOTAL_ENTRIES_SIZE / gptdata->sector_bytes; | 
 | 74 |  | 
 | 75 |   if (gptdata->primary_header) { | 
 | 76 |     if (gptdata->modified & GPT_MODIFIED_HEADER1) { | 
| Randall Spangler | e2ec984 | 2010-06-23 21:17:07 -0700 | [diff] [blame] | 77 |       VBDEBUG(("Updating GPT header 1\n")); | 
| Randall Spangler | 83c88cf | 2010-06-11 16:14:18 -0700 | [diff] [blame] | 78 |       if (0 != BootDeviceWriteLBA(1, 1, gptdata->primary_header)) | 
 | 79 |         return 1; | 
 | 80 |     } | 
 | 81 |     Free(gptdata->primary_header); | 
 | 82 |   } | 
 | 83 |  | 
 | 84 |   if (gptdata->primary_entries) { | 
 | 85 |     if (gptdata->modified & GPT_MODIFIED_ENTRIES1) { | 
| Randall Spangler | e2ec984 | 2010-06-23 21:17:07 -0700 | [diff] [blame] | 86 |       VBDEBUG(("Updating GPT entries 1\n")); | 
| Randall Spangler | 83c88cf | 2010-06-11 16:14:18 -0700 | [diff] [blame] | 87 |       if (0 != BootDeviceWriteLBA(2, entries_sectors, | 
 | 88 |                                   gptdata->primary_entries)) | 
 | 89 |         return 1; | 
 | 90 |     } | 
 | 91 |     Free(gptdata->primary_entries); | 
 | 92 |   } | 
 | 93 |  | 
 | 94 |   if (gptdata->secondary_entries) { | 
 | 95 |     if (gptdata->modified & GPT_MODIFIED_ENTRIES2) { | 
| Randall Spangler | e2ec984 | 2010-06-23 21:17:07 -0700 | [diff] [blame] | 96 |       VBDEBUG(("Updating GPT header 2\n")); | 
| Randall Spangler | 83c88cf | 2010-06-11 16:14:18 -0700 | [diff] [blame] | 97 |       if (0 != BootDeviceWriteLBA(gptdata->drive_sectors - entries_sectors - 1, | 
 | 98 |                                   entries_sectors, gptdata->secondary_entries)) | 
 | 99 |         return 1; | 
 | 100 |     } | 
 | 101 |     Free(gptdata->secondary_entries); | 
 | 102 |   } | 
 | 103 |  | 
 | 104 |   if (gptdata->secondary_header) { | 
 | 105 |     if (gptdata->modified & GPT_MODIFIED_HEADER2) { | 
| Randall Spangler | e2ec984 | 2010-06-23 21:17:07 -0700 | [diff] [blame] | 106 |       VBDEBUG(("Updating GPT entries 2\n")); | 
| Randall Spangler | 83c88cf | 2010-06-11 16:14:18 -0700 | [diff] [blame] | 107 |       if (0 != BootDeviceWriteLBA(gptdata->drive_sectors - 1, 1, | 
 | 108 |                                   gptdata->secondary_header)) | 
 | 109 |         return 1; | 
 | 110 |     } | 
 | 111 |     Free(gptdata->secondary_header); | 
 | 112 |   } | 
 | 113 |  | 
 | 114 |   /* Success */ | 
 | 115 |   return 0; | 
 | 116 | } | 
 | 117 |  | 
| vbendeb | 3ecaf77 | 2010-06-24 16:19:53 -0700 | [diff] [blame] | 118 | /* disable MSVC warning on const logical expression (as in } while(0);) */ | 
 | 119 | __pragma(warning(disable: 4127)) | 
| Randall Spangler | 83c88cf | 2010-06-11 16:14:18 -0700 | [diff] [blame] | 120 |  | 
| Randall Spangler | bd529f0 | 2010-06-16 12:51:26 -0700 | [diff] [blame] | 121 | int LoadKernel(LoadKernelParams* params) { | 
| Randall Spangler | 95c4031 | 2011-03-09 15:54:16 -0800 | [diff] [blame] | 122 |   VbSharedDataHeader* shared = (VbSharedDataHeader*)params->shared_data_blob; | 
| Randall Spangler | 640fb51 | 2011-03-03 10:11:17 -0800 | [diff] [blame] | 123 |   VbNvContext* vnc = params->nv_context; | 
| Randall Spangler | 95c4031 | 2011-03-09 15:54:16 -0800 | [diff] [blame] | 124 |   GoogleBinaryBlockHeader* gbb = (GoogleBinaryBlockHeader*)params->gbb_data; | 
| Bill Richardson | e272940 | 2010-07-22 12:23:47 -0700 | [diff] [blame] | 125 |   VbPublicKey* kernel_subkey; | 
| Randall Spangler | d183644 | 2010-06-10 09:59:04 -0700 | [diff] [blame] | 126 |   GptData gpt; | 
 | 127 |   uint64_t part_start, part_size; | 
| Bill Richardson | e272940 | 2010-07-22 12:23:47 -0700 | [diff] [blame] | 128 |   uint64_t blba; | 
 | 129 |   uint64_t kbuf_sectors; | 
| Randall Spangler | d183644 | 2010-06-10 09:59:04 -0700 | [diff] [blame] | 130 |   uint8_t* kbuf = NULL; | 
 | 131 |   int found_partitions = 0; | 
 | 132 |   int good_partition = -1; | 
| Randall Spangler | 640fb51 | 2011-03-03 10:11:17 -0800 | [diff] [blame] | 133 |   int good_partition_key_block_valid = 0; | 
| Randall Spangler | 6668028 | 2010-08-16 12:33:44 -0700 | [diff] [blame] | 134 |   uint32_t tpm_version = 0; | 
 | 135 |   uint64_t lowest_version = 0xFFFFFFFF; | 
| Randall Spangler | 640fb51 | 2011-03-03 10:11:17 -0800 | [diff] [blame] | 136 |   int rec_switch, dev_switch; | 
 | 137 |   BootMode boot_mode; | 
| Randall Spangler | 99ca346 | 2011-03-15 15:28:31 -0700 | [diff] [blame^] | 138 |   uint32_t test_err = 0; | 
| Randall Spangler | 7a786b7 | 2010-07-08 13:29:42 -0700 | [diff] [blame] | 139 |   uint32_t status; | 
| Randall Spangler | d183644 | 2010-06-10 09:59:04 -0700 | [diff] [blame] | 140 |  | 
| Randall Spangler | 640fb51 | 2011-03-03 10:11:17 -0800 | [diff] [blame] | 141 |   /* TODO: differentiate between finding an invalid kernel (found_partitions>0) | 
 | 142 |    * and not finding one at all.  Right now we treat them the same, and return | 
 | 143 |    * LOAD_KERNEL_INVALID for both. */ | 
 | 144 |   int retval = LOAD_KERNEL_INVALID; | 
 | 145 |   int recovery = VBNV_RECOVERY_RO_UNSPECIFIED; | 
 | 146 |  | 
 | 147 |   /* Setup NV storage */ | 
 | 148 |   VbNvSetup(vnc); | 
 | 149 |  | 
| Bill Richardson | e272940 | 2010-07-22 12:23:47 -0700 | [diff] [blame] | 150 |   /* Sanity Checks */ | 
 | 151 |   if (!params || | 
| Bill Richardson | e272940 | 2010-07-22 12:23:47 -0700 | [diff] [blame] | 152 |       !params->bytes_per_lba || | 
 | 153 |       !params->ending_lba || | 
 | 154 |       !params->kernel_buffer || | 
 | 155 |       !params->kernel_buffer_size) { | 
 | 156 |     VBDEBUG(("LoadKernel() called with invalid params\n")); | 
| Randall Spangler | 640fb51 | 2011-03-03 10:11:17 -0800 | [diff] [blame] | 157 |     goto LoadKernelExit; | 
| Bill Richardson | e272940 | 2010-07-22 12:23:47 -0700 | [diff] [blame] | 158 |   } | 
 | 159 |  | 
| Randall Spangler | 99ca346 | 2011-03-15 15:28:31 -0700 | [diff] [blame^] | 160 |   /* Handle test errors */ | 
 | 161 |   VbNvGet(vnc, VBNV_TEST_ERROR_FUNC, &test_err); | 
 | 162 |   if (VBNV_TEST_ERROR_LOAD_KERNEL == test_err) { | 
 | 163 |     /* Get error code */ | 
 | 164 |     VbNvGet(vnc, VBNV_TEST_ERROR_NUM, &test_err); | 
 | 165 |     /* Clear test params so we don't repeat the error */ | 
 | 166 |     VbNvSet(vnc, VBNV_TEST_ERROR_FUNC, 0); | 
 | 167 |     VbNvSet(vnc, VBNV_TEST_ERROR_NUM, 0); | 
 | 168 |     /* Handle error codes */ | 
 | 169 |     switch (test_err) { | 
 | 170 |       case LOAD_KERNEL_RECOVERY: | 
 | 171 |         recovery = VBNV_RECOVERY_RW_TEST_LK; | 
 | 172 |         goto LoadKernelExit; | 
 | 173 |       case LOAD_KERNEL_NOT_FOUND: | 
 | 174 |       case LOAD_KERNEL_INVALID: | 
 | 175 |       case LOAD_KERNEL_REBOOT: | 
 | 176 |         retval = test_err; | 
 | 177 |         goto LoadKernelExit; | 
 | 178 |       default: | 
 | 179 |         break; | 
 | 180 |     } | 
 | 181 |   } | 
 | 182 |  | 
| Bill Richardson | e272940 | 2010-07-22 12:23:47 -0700 | [diff] [blame] | 183 |   /* Initialization */ | 
| Bill Richardson | e272940 | 2010-07-22 12:23:47 -0700 | [diff] [blame] | 184 |   blba = params->bytes_per_lba; | 
 | 185 |   kbuf_sectors = KBUF_SIZE / blba; | 
| Randall Spangler | 4bb5e4b | 2010-08-19 09:05:22 -0700 | [diff] [blame] | 186 |   if (0 == kbuf_sectors) { | 
 | 187 |     VBDEBUG(("LoadKernel() called with sector size > KBUF_SIZE\n")); | 
| Randall Spangler | 640fb51 | 2011-03-03 10:11:17 -0800 | [diff] [blame] | 188 |     goto LoadKernelExit; | 
| Randall Spangler | 4bb5e4b | 2010-08-19 09:05:22 -0700 | [diff] [blame] | 189 |   } | 
 | 190 |  | 
| Randall Spangler | 640fb51 | 2011-03-03 10:11:17 -0800 | [diff] [blame] | 191 |   rec_switch = (BOOT_FLAG_RECOVERY & params->boot_flags ? 1 : 0); | 
 | 192 |   dev_switch = (BOOT_FLAG_DEVELOPER & params->boot_flags ? 1 : 0); | 
 | 193 |  | 
 | 194 |   if (rec_switch) | 
 | 195 |     boot_mode = kBootRecovery; | 
| Randall Spangler | 8478ece | 2011-03-03 11:00:17 -0800 | [diff] [blame] | 196 |   else if (BOOT_FLAG_DEV_FIRMWARE & params->boot_flags) { | 
| Randall Spangler | 640fb51 | 2011-03-03 10:11:17 -0800 | [diff] [blame] | 197 |     if (!dev_switch) { | 
 | 198 |       /* Dev firmware should be signed such that it never boots with the dev | 
 | 199 |        * switch is off; so something is terribly wrong. */ | 
 | 200 |       VBDEBUG(("LoadKernel() called with dev firmware but dev switch off\n")); | 
 | 201 |       recovery = VBNV_RECOVERY_RW_DEV_MISMATCH; | 
 | 202 |       goto LoadKernelExit; | 
 | 203 |     } | 
 | 204 |     boot_mode = kBootDev; | 
| Randall Spangler | 8478ece | 2011-03-03 11:00:17 -0800 | [diff] [blame] | 205 |   } else { | 
| Randall Spangler | 640fb51 | 2011-03-03 10:11:17 -0800 | [diff] [blame] | 206 |     /* Normal firmware */ | 
 | 207 |     boot_mode = kBootNormal; | 
 | 208 |     dev_switch = 0;  /* Always do a fully verified boot */ | 
| Randall Spangler | a8e0f94 | 2011-02-14 11:12:09 -0800 | [diff] [blame] | 209 |   } | 
| Bill Richardson | e272940 | 2010-07-22 12:23:47 -0700 | [diff] [blame] | 210 |  | 
| Randall Spangler | d183644 | 2010-06-10 09:59:04 -0700 | [diff] [blame] | 211 |   /* Clear output params in case we fail */ | 
 | 212 |   params->partition_number = 0; | 
 | 213 |   params->bootloader_address = 0; | 
 | 214 |   params->bootloader_size = 0; | 
 | 215 |  | 
| Randall Spangler | 640fb51 | 2011-03-03 10:11:17 -0800 | [diff] [blame] | 216 |   if (kBootRecovery == boot_mode) { | 
| Randall Spangler | 95c4031 | 2011-03-09 15:54:16 -0800 | [diff] [blame] | 217 |     /* Initialize the shared data structure, since LoadFirmware() didn't do it | 
 | 218 |      * for us. */ | 
 | 219 |     if (0 != VbSharedDataInit(shared, params->shared_data_size)) { | 
 | 220 |       /* Error initializing the shared data, but we can keep going.  We just | 
 | 221 |        * can't use the shared data. */ | 
 | 222 |       VBDEBUG(("Shared data init error\n")); | 
 | 223 |       params->shared_data_size = 0; | 
 | 224 |       shared = NULL; | 
 | 225 |     } | 
 | 226 |  | 
 | 227 |     /* Use the recovery key to verify the kernel */ | 
 | 228 |     kernel_subkey = (VbPublicKey*)((uint8_t*)gbb + gbb->recovery_key_offset); | 
 | 229 |  | 
 | 230 |     /* Let the TPM know if we're in recovery mode */ | 
| Randall Spangler | 640fb51 | 2011-03-03 10:11:17 -0800 | [diff] [blame] | 231 |     if (0 != RollbackKernelRecovery(dev_switch)) { | 
| Randall Spangler | 63dffcb | 2010-08-05 15:13:14 -0700 | [diff] [blame] | 232 |       VBDEBUG(("Error setting up TPM for recovery kernel\n")); | 
 | 233 |       /* Ignore return code, since we need to boot recovery mode to | 
 | 234 |        * fix the TPM. */ | 
| Randall Spangler | 1078838 | 2010-06-23 15:35:31 -0700 | [diff] [blame] | 235 |     } | 
| Randall Spangler | 640fb51 | 2011-03-03 10:11:17 -0800 | [diff] [blame] | 236 |   } else { | 
| Randall Spangler | 95c4031 | 2011-03-09 15:54:16 -0800 | [diff] [blame] | 237 |     /* Use the kernel subkey passed from LoadFirmware(). */ | 
 | 238 |     kernel_subkey = &shared->kernel_subkey; | 
 | 239 |  | 
| Randall Spangler | d183644 | 2010-06-10 09:59:04 -0700 | [diff] [blame] | 240 |     /* Read current kernel key index from TPM.  Assumes TPM is already | 
 | 241 |      * initialized. */ | 
| Randall Spangler | 6668028 | 2010-08-16 12:33:44 -0700 | [diff] [blame] | 242 |     status = RollbackKernelRead(&tpm_version); | 
| Randall Spangler | 7a786b7 | 2010-07-08 13:29:42 -0700 | [diff] [blame] | 243 |     if (0 != status) { | 
| Randall Spangler | e2ec984 | 2010-06-23 21:17:07 -0700 | [diff] [blame] | 244 |       VBDEBUG(("Unable to get kernel versions from TPM\n")); | 
| Randall Spangler | 640fb51 | 2011-03-03 10:11:17 -0800 | [diff] [blame] | 245 |       if (status == TPM_E_MUST_REBOOT) | 
 | 246 |         retval = LOAD_KERNEL_REBOOT; | 
 | 247 |       else | 
 | 248 |         recovery = VBNV_RECOVERY_RW_TPM_ERROR; | 
 | 249 |       goto LoadKernelExit; | 
| Randall Spangler | 695cd16 | 2010-06-15 23:38:23 -0700 | [diff] [blame] | 250 |     } | 
| Randall Spangler | d183644 | 2010-06-10 09:59:04 -0700 | [diff] [blame] | 251 |   } | 
 | 252 |  | 
 | 253 |   do { | 
 | 254 |     /* Read GPT data */ | 
| Randall Spangler | beb5bae | 2010-06-21 16:33:26 -0700 | [diff] [blame] | 255 |     gpt.sector_bytes = (uint32_t)blba; | 
| Randall Spangler | d183644 | 2010-06-10 09:59:04 -0700 | [diff] [blame] | 256 |     gpt.drive_sectors = params->ending_lba + 1; | 
| Randall Spangler | 695cd16 | 2010-06-15 23:38:23 -0700 | [diff] [blame] | 257 |     if (0 != AllocAndReadGptData(&gpt)) { | 
| Randall Spangler | e2ec984 | 2010-06-23 21:17:07 -0700 | [diff] [blame] | 258 |       VBDEBUG(("Unable to read GPT data\n")); | 
| Randall Spangler | d183644 | 2010-06-10 09:59:04 -0700 | [diff] [blame] | 259 |       break; | 
| Randall Spangler | 695cd16 | 2010-06-15 23:38:23 -0700 | [diff] [blame] | 260 |     } | 
| Randall Spangler | d183644 | 2010-06-10 09:59:04 -0700 | [diff] [blame] | 261 |  | 
 | 262 |     /* Initialize GPT library */ | 
| Randall Spangler | 695cd16 | 2010-06-15 23:38:23 -0700 | [diff] [blame] | 263 |     if (GPT_SUCCESS != GptInit(&gpt)) { | 
| Randall Spangler | e2ec984 | 2010-06-23 21:17:07 -0700 | [diff] [blame] | 264 |       VBDEBUG(("Error parsing GPT\n")); | 
| Randall Spangler | d183644 | 2010-06-10 09:59:04 -0700 | [diff] [blame] | 265 |       break; | 
| Randall Spangler | 695cd16 | 2010-06-15 23:38:23 -0700 | [diff] [blame] | 266 |     } | 
| Randall Spangler | d183644 | 2010-06-10 09:59:04 -0700 | [diff] [blame] | 267 |  | 
| Randall Spangler | d183644 | 2010-06-10 09:59:04 -0700 | [diff] [blame] | 268 |     /* Allocate kernel header buffers */ | 
 | 269 |     kbuf = (uint8_t*)Malloc(KBUF_SIZE); | 
 | 270 |     if (!kbuf) | 
 | 271 |       break; | 
 | 272 |  | 
 | 273 |     /* Loop over candidate kernel partitions */ | 
 | 274 |     while (GPT_SUCCESS == GptNextKernelEntry(&gpt, &part_start, &part_size)) { | 
 | 275 |       VbKeyBlockHeader* key_block; | 
 | 276 |       VbKernelPreambleHeader* preamble; | 
| Randall Spangler | 741d2b2 | 2010-08-20 16:37:12 -0700 | [diff] [blame] | 277 |       RSAPublicKey* data_key = NULL; | 
| Randall Spangler | d183644 | 2010-06-10 09:59:04 -0700 | [diff] [blame] | 278 |       uint64_t key_version; | 
| Randall Spangler | 6668028 | 2010-08-16 12:33:44 -0700 | [diff] [blame] | 279 |       uint64_t combined_version; | 
| Randall Spangler | d183644 | 2010-06-10 09:59:04 -0700 | [diff] [blame] | 280 |       uint64_t body_offset; | 
| Randall Spangler | 4bb5e4b | 2010-08-19 09:05:22 -0700 | [diff] [blame] | 281 |       uint64_t body_offset_sectors; | 
 | 282 |       uint64_t body_sectors; | 
| Randall Spangler | 640fb51 | 2011-03-03 10:11:17 -0800 | [diff] [blame] | 283 |       int key_block_valid = 1; | 
| Randall Spangler | d183644 | 2010-06-10 09:59:04 -0700 | [diff] [blame] | 284 |  | 
| Randall Spangler | e2ec984 | 2010-06-23 21:17:07 -0700 | [diff] [blame] | 285 |       VBDEBUG(("Found kernel entry at %" PRIu64 " size %" PRIu64 "\n", | 
 | 286 |               part_start, part_size)); | 
| Randall Spangler | 695cd16 | 2010-06-15 23:38:23 -0700 | [diff] [blame] | 287 |  | 
| Randall Spangler | d183644 | 2010-06-10 09:59:04 -0700 | [diff] [blame] | 288 |       /* Found at least one kernel partition. */ | 
 | 289 |       found_partitions++; | 
 | 290 |  | 
| Randall Spangler | 640fb51 | 2011-03-03 10:11:17 -0800 | [diff] [blame] | 291 |       /* Read the first part of the kernel partition. */ | 
| Randall Spangler | 77ae389 | 2010-09-09 17:37:51 -0700 | [diff] [blame] | 292 |       if (part_size < kbuf_sectors) { | 
 | 293 |         VBDEBUG(("Partition too small to hold kernel.\n")); | 
| Randall Spangler | 741d2b2 | 2010-08-20 16:37:12 -0700 | [diff] [blame] | 294 |         goto bad_kernel; | 
| Randall Spangler | 77ae389 | 2010-09-09 17:37:51 -0700 | [diff] [blame] | 295 |       } | 
 | 296 |  | 
 | 297 |       if (0 != BootDeviceReadLBA(part_start, kbuf_sectors, kbuf)) { | 
 | 298 |         VBDEBUG(("Unable to read start of partition.\n")); | 
| Randall Spangler | 741d2b2 | 2010-08-20 16:37:12 -0700 | [diff] [blame] | 299 |         goto bad_kernel; | 
| Randall Spangler | 77ae389 | 2010-09-09 17:37:51 -0700 | [diff] [blame] | 300 |       } | 
| Randall Spangler | d183644 | 2010-06-10 09:59:04 -0700 | [diff] [blame] | 301 |  | 
| Randall Spangler | 640fb51 | 2011-03-03 10:11:17 -0800 | [diff] [blame] | 302 |       /* Verify the key block. */ | 
| Randall Spangler | d183644 | 2010-06-10 09:59:04 -0700 | [diff] [blame] | 303 |       key_block = (VbKeyBlockHeader*)kbuf; | 
| Randall Spangler | 640fb51 | 2011-03-03 10:11:17 -0800 | [diff] [blame] | 304 |       if (0 != KeyBlockVerify(key_block, KBUF_SIZE, kernel_subkey, 0)) { | 
 | 305 |         VBDEBUG(("Verifying key block signature failed.\n")); | 
 | 306 |         key_block_valid = 0; | 
| Randall Spangler | d183644 | 2010-06-10 09:59:04 -0700 | [diff] [blame] | 307 |  | 
| Randall Spangler | 640fb51 | 2011-03-03 10:11:17 -0800 | [diff] [blame] | 308 |         /* If we're not in developer mode, this kernel is bad. */ | 
 | 309 |         if (kBootDev != boot_mode) | 
| Randall Spangler | 741d2b2 | 2010-08-20 16:37:12 -0700 | [diff] [blame] | 310 |           goto bad_kernel; | 
| Randall Spangler | 640fb51 | 2011-03-03 10:11:17 -0800 | [diff] [blame] | 311 |  | 
 | 312 |         /* In developer mode, we can continue if the SHA-512 hash of the key | 
 | 313 |          * block is valid. */ | 
 | 314 |         if (0 != KeyBlockVerify(key_block, KBUF_SIZE, kernel_subkey, 1)) { | 
 | 315 |           VBDEBUG(("Verifying key block hash failed.\n")); | 
| Randall Spangler | 741d2b2 | 2010-08-20 16:37:12 -0700 | [diff] [blame] | 316 |           goto bad_kernel; | 
| Randall Spangler | ae029d9 | 2010-07-19 18:26:35 -0700 | [diff] [blame] | 317 |         } | 
| Randall Spangler | 695cd16 | 2010-06-15 23:38:23 -0700 | [diff] [blame] | 318 |       } | 
| Randall Spangler | d183644 | 2010-06-10 09:59:04 -0700 | [diff] [blame] | 319 |  | 
| Randall Spangler | 640fb51 | 2011-03-03 10:11:17 -0800 | [diff] [blame] | 320 |       /* Check the key block flags against the current boot mode. */ | 
 | 321 |       if (!(key_block->key_block_flags & | 
 | 322 |             (dev_switch ? KEY_BLOCK_FLAG_DEVELOPER_1 : | 
 | 323 |              KEY_BLOCK_FLAG_DEVELOPER_0))) { | 
 | 324 |         VBDEBUG(("Key block developer flag mismatch.\n")); | 
 | 325 |         key_block_valid = 0; | 
 | 326 |       } | 
 | 327 |       if (!(key_block->key_block_flags & | 
 | 328 |             (rec_switch ? KEY_BLOCK_FLAG_RECOVERY_1 : | 
 | 329 |              KEY_BLOCK_FLAG_RECOVERY_0))) { | 
 | 330 |         VBDEBUG(("Key block recovery flag mismatch.\n")); | 
 | 331 |         key_block_valid = 0; | 
 | 332 |       } | 
 | 333 |  | 
 | 334 |       /* Check for rollback of key version except in recovery mode. */ | 
| Randall Spangler | d183644 | 2010-06-10 09:59:04 -0700 | [diff] [blame] | 335 |       key_version = key_block->data_key.key_version; | 
| Randall Spangler | 640fb51 | 2011-03-03 10:11:17 -0800 | [diff] [blame] | 336 |       if (kBootRecovery != boot_mode) { | 
 | 337 |         if (key_version < (tpm_version >> 16)) { | 
 | 338 |           VBDEBUG(("Key version too old.\n")); | 
 | 339 |           key_block_valid = 0; | 
 | 340 |         } | 
 | 341 |       } | 
 | 342 |  | 
 | 343 |       /* If we're not in developer mode, require the key block to be valid. */ | 
 | 344 |       if (kBootDev != boot_mode && !key_block_valid) { | 
 | 345 |         VBDEBUG(("Key block is invalid.\n")); | 
| Randall Spangler | 741d2b2 | 2010-08-20 16:37:12 -0700 | [diff] [blame] | 346 |         goto bad_kernel; | 
| Randall Spangler | 695cd16 | 2010-06-15 23:38:23 -0700 | [diff] [blame] | 347 |       } | 
| Randall Spangler | d183644 | 2010-06-10 09:59:04 -0700 | [diff] [blame] | 348 |  | 
| Randall Spangler | 640fb51 | 2011-03-03 10:11:17 -0800 | [diff] [blame] | 349 |       /* Get the key for preamble/data verification from the key block. */ | 
| Randall Spangler | d183644 | 2010-06-10 09:59:04 -0700 | [diff] [blame] | 350 |       data_key = PublicKeyToRSA(&key_block->data_key); | 
| Randall Spangler | 77ae389 | 2010-09-09 17:37:51 -0700 | [diff] [blame] | 351 |       if (!data_key) { | 
 | 352 |         VBDEBUG(("Data key bad.\n")); | 
| Randall Spangler | 741d2b2 | 2010-08-20 16:37:12 -0700 | [diff] [blame] | 353 |         goto bad_kernel; | 
| Randall Spangler | 77ae389 | 2010-09-09 17:37:51 -0700 | [diff] [blame] | 354 |       } | 
| Randall Spangler | d183644 | 2010-06-10 09:59:04 -0700 | [diff] [blame] | 355 |  | 
 | 356 |       /* Verify the preamble, which follows the key block */ | 
 | 357 |       preamble = (VbKernelPreambleHeader*)(kbuf + key_block->key_block_size); | 
| Randall Spangler | 87c13d8 | 2010-07-19 10:35:40 -0700 | [diff] [blame] | 358 |       if ((0 != VerifyKernelPreamble(preamble, | 
| Randall Spangler | d183644 | 2010-06-10 09:59:04 -0700 | [diff] [blame] | 359 |                                      KBUF_SIZE - key_block->key_block_size, | 
 | 360 |                                      data_key))) { | 
| Randall Spangler | e2ec984 | 2010-06-23 21:17:07 -0700 | [diff] [blame] | 361 |         VBDEBUG(("Preamble verification failed.\n")); | 
| Randall Spangler | 741d2b2 | 2010-08-20 16:37:12 -0700 | [diff] [blame] | 362 |         goto bad_kernel; | 
| Randall Spangler | d183644 | 2010-06-10 09:59:04 -0700 | [diff] [blame] | 363 |       } | 
 | 364 |  | 
| Randall Spangler | 640fb51 | 2011-03-03 10:11:17 -0800 | [diff] [blame] | 365 |       /* If the key block is valid and we're not in recovery mode, check for | 
 | 366 |        * rollback of the kernel version. */ | 
| Randall Spangler | 6668028 | 2010-08-16 12:33:44 -0700 | [diff] [blame] | 367 |       combined_version = ((key_version << 16) | | 
 | 368 |                           (preamble->kernel_version & 0xFFFF)); | 
| Randall Spangler | 640fb51 | 2011-03-03 10:11:17 -0800 | [diff] [blame] | 369 |       if (key_block_valid && kBootRecovery != boot_mode) { | 
 | 370 |         if (combined_version < tpm_version) { | 
 | 371 |           VBDEBUG(("Kernel version too low.\n")); | 
 | 372 |           /* If we're not in developer mode, kernel version must be valid. */ | 
 | 373 |           if (kBootDev != boot_mode) | 
 | 374 |             goto bad_kernel; | 
 | 375 |         } | 
| Randall Spangler | d183644 | 2010-06-10 09:59:04 -0700 | [diff] [blame] | 376 |       } | 
 | 377 |  | 
| Randall Spangler | e2ec984 | 2010-06-23 21:17:07 -0700 | [diff] [blame] | 378 |       VBDEBUG(("Kernel preamble is good.\n")); | 
| Randall Spangler | 695cd16 | 2010-06-15 23:38:23 -0700 | [diff] [blame] | 379 |  | 
| Randall Spangler | 6668028 | 2010-08-16 12:33:44 -0700 | [diff] [blame] | 380 |       /* Check for lowest version from a valid header. */ | 
| Randall Spangler | 640fb51 | 2011-03-03 10:11:17 -0800 | [diff] [blame] | 381 |       if (key_block_valid && lowest_version > combined_version) | 
| Randall Spangler | 6668028 | 2010-08-16 12:33:44 -0700 | [diff] [blame] | 382 |         lowest_version = combined_version; | 
| Randall Spangler | d183644 | 2010-06-10 09:59:04 -0700 | [diff] [blame] | 383 |  | 
 | 384 |       /* If we already have a good kernel, no need to read another | 
 | 385 |        * one; we only needed to look at the versions to check for | 
| Randall Spangler | 77ae389 | 2010-09-09 17:37:51 -0700 | [diff] [blame] | 386 |        * rollback.  So skip to the next kernel preamble. */ | 
| Randall Spangler | d183644 | 2010-06-10 09:59:04 -0700 | [diff] [blame] | 387 |       if (-1 != good_partition) | 
| Randall Spangler | 77ae389 | 2010-09-09 17:37:51 -0700 | [diff] [blame] | 388 |         continue; | 
| Randall Spangler | d183644 | 2010-06-10 09:59:04 -0700 | [diff] [blame] | 389 |  | 
 | 390 |       /* Verify body load address matches what we expect */ | 
| Randall Spangler | 695cd16 | 2010-06-15 23:38:23 -0700 | [diff] [blame] | 391 |       if ((preamble->body_load_address != (size_t)params->kernel_buffer) && | 
 | 392 |           !(params->boot_flags & BOOT_FLAG_SKIP_ADDR_CHECK)) { | 
| Randall Spangler | e2ec984 | 2010-06-23 21:17:07 -0700 | [diff] [blame] | 393 |         VBDEBUG(("Wrong body load address.\n")); | 
| Randall Spangler | 741d2b2 | 2010-08-20 16:37:12 -0700 | [diff] [blame] | 394 |         goto bad_kernel; | 
| Randall Spangler | d183644 | 2010-06-10 09:59:04 -0700 | [diff] [blame] | 395 |       } | 
 | 396 |  | 
 | 397 |       /* Verify kernel body starts at a multiple of the sector size. */ | 
 | 398 |       body_offset = key_block->key_block_size + preamble->preamble_size; | 
 | 399 |       if (0 != body_offset % blba) { | 
| Randall Spangler | e2ec984 | 2010-06-23 21:17:07 -0700 | [diff] [blame] | 400 |         VBDEBUG(("Kernel body not at multiple of sector size.\n")); | 
| Randall Spangler | 741d2b2 | 2010-08-20 16:37:12 -0700 | [diff] [blame] | 401 |         goto bad_kernel; | 
| Randall Spangler | d183644 | 2010-06-10 09:59:04 -0700 | [diff] [blame] | 402 |       } | 
| Randall Spangler | 4bb5e4b | 2010-08-19 09:05:22 -0700 | [diff] [blame] | 403 |       body_offset_sectors = body_offset / blba; | 
 | 404 |  | 
 | 405 |       /* Verify kernel body fits in the buffer */ | 
 | 406 |       body_sectors = (preamble->body_signature.data_size + blba - 1) / blba; | 
 | 407 |       if (body_sectors * blba > params->kernel_buffer_size) { | 
 | 408 |         VBDEBUG(("Kernel body doesn't fit in memory.\n")); | 
| Randall Spangler | 741d2b2 | 2010-08-20 16:37:12 -0700 | [diff] [blame] | 409 |         goto bad_kernel; | 
| Randall Spangler | 4bb5e4b | 2010-08-19 09:05:22 -0700 | [diff] [blame] | 410 |       } | 
| Randall Spangler | d183644 | 2010-06-10 09:59:04 -0700 | [diff] [blame] | 411 |  | 
 | 412 |       /* Verify kernel body fits in the partition */ | 
| Randall Spangler | 4bb5e4b | 2010-08-19 09:05:22 -0700 | [diff] [blame] | 413 |       if (body_offset_sectors + body_sectors > part_size) { | 
| Randall Spangler | e2ec984 | 2010-06-23 21:17:07 -0700 | [diff] [blame] | 414 |         VBDEBUG(("Kernel body doesn't fit in partition.\n")); | 
| Randall Spangler | 741d2b2 | 2010-08-20 16:37:12 -0700 | [diff] [blame] | 415 |         goto bad_kernel; | 
| Randall Spangler | d183644 | 2010-06-10 09:59:04 -0700 | [diff] [blame] | 416 |       } | 
 | 417 |  | 
 | 418 |       /* Read the kernel data */ | 
| Randall Spangler | 6078ca3 | 2010-10-18 15:49:28 -0700 | [diff] [blame] | 419 |       VBPERFSTART("VB_RKD"); | 
| Randall Spangler | 4bb5e4b | 2010-08-19 09:05:22 -0700 | [diff] [blame] | 420 |       if (0 != BootDeviceReadLBA(part_start + body_offset_sectors, | 
 | 421 |                                  body_sectors, | 
 | 422 |                                  params->kernel_buffer)) { | 
| Randall Spangler | e2ec984 | 2010-06-23 21:17:07 -0700 | [diff] [blame] | 423 |         VBDEBUG(("Unable to read kernel data.\n")); | 
| Randall Spangler | 6078ca3 | 2010-10-18 15:49:28 -0700 | [diff] [blame] | 424 |         VBPERFEND("VB_RKD"); | 
| Randall Spangler | 741d2b2 | 2010-08-20 16:37:12 -0700 | [diff] [blame] | 425 |         goto bad_kernel; | 
| Randall Spangler | d183644 | 2010-06-10 09:59:04 -0700 | [diff] [blame] | 426 |       } | 
| Randall Spangler | 6078ca3 | 2010-10-18 15:49:28 -0700 | [diff] [blame] | 427 |       VBPERFEND("VB_RKD"); | 
| Randall Spangler | d183644 | 2010-06-10 09:59:04 -0700 | [diff] [blame] | 428 |  | 
 | 429 |       /* Verify kernel data */ | 
 | 430 |       if (0 != VerifyData((const uint8_t*)params->kernel_buffer, | 
| Randall Spangler | 87c13d8 | 2010-07-19 10:35:40 -0700 | [diff] [blame] | 431 |                           params->kernel_buffer_size, | 
| Randall Spangler | d183644 | 2010-06-10 09:59:04 -0700 | [diff] [blame] | 432 |                           &preamble->body_signature, data_key)) { | 
| Randall Spangler | e2ec984 | 2010-06-23 21:17:07 -0700 | [diff] [blame] | 433 |         VBDEBUG(("Kernel data verification failed.\n")); | 
| Randall Spangler | 741d2b2 | 2010-08-20 16:37:12 -0700 | [diff] [blame] | 434 |         goto bad_kernel; | 
| Randall Spangler | d183644 | 2010-06-10 09:59:04 -0700 | [diff] [blame] | 435 |       } | 
 | 436 |  | 
 | 437 |       /* Done with the kernel signing key, so can free it now */ | 
 | 438 |       RSAPublicKeyFree(data_key); | 
| Randall Spangler | 741d2b2 | 2010-08-20 16:37:12 -0700 | [diff] [blame] | 439 |       data_key = NULL; | 
| Randall Spangler | d183644 | 2010-06-10 09:59:04 -0700 | [diff] [blame] | 440 |  | 
 | 441 |       /* If we're still here, the kernel is valid. */ | 
 | 442 |       /* Save the first good partition we find; that's the one we'll boot */ | 
| Randall Spangler | 640fb51 | 2011-03-03 10:11:17 -0800 | [diff] [blame] | 443 |       VBDEBUG(("Partition is good.\n")); | 
 | 444 |       good_partition_key_block_valid = key_block_valid; | 
| Randall Spangler | beb5bae | 2010-06-21 16:33:26 -0700 | [diff] [blame] | 445 |       /* TODO: GPT partitions start at 1, but cgptlib starts them at 0. | 
 | 446 |        * Adjust here, until cgptlib is fixed. */ | 
 | 447 |       good_partition = gpt.current_kernel + 1; | 
| Randall Spangler | b9d60a5 | 2010-06-23 12:43:01 -0700 | [diff] [blame] | 448 |       params->partition_number = gpt.current_kernel + 1; | 
| Bill Richardson | 5deb67f | 2010-07-23 17:22:25 -0700 | [diff] [blame] | 449 |       GetCurrentKernelUniqueGuid(&gpt, ¶ms->partition_guid); | 
| Randall Spangler | 63dffcb | 2010-08-05 15:13:14 -0700 | [diff] [blame] | 450 |       /* TODO: GetCurrentKernelUniqueGuid() should take a destination size, or | 
 | 451 |        * the dest should be a struct, so we know it's big enough. */ | 
| Randall Spangler | 695cd16 | 2010-06-15 23:38:23 -0700 | [diff] [blame] | 452 |       params->bootloader_address = preamble->bootloader_address; | 
 | 453 |       params->bootloader_size = preamble->bootloader_size; | 
| Randall Spangler | 741d2b2 | 2010-08-20 16:37:12 -0700 | [diff] [blame] | 454 |  | 
 | 455 |       /* Update GPT to note this is the kernel we're trying */ | 
 | 456 |       GptUpdateKernelEntry(&gpt, GPT_UPDATE_ENTRY_TRY); | 
 | 457 |  | 
| Randall Spangler | 640fb51 | 2011-03-03 10:11:17 -0800 | [diff] [blame] | 458 |       /* If we're in recovery mode or we're about to boot a dev-signed kernel, | 
 | 459 |        * there's no rollback protection, so we can stop at the first valid | 
 | 460 |        * kernel. */ | 
 | 461 |       if (kBootRecovery == boot_mode || !key_block_valid) { | 
 | 462 |         VBDEBUG(("In recovery mode or dev-signed kernel\n")); | 
| Randall Spangler | 695cd16 | 2010-06-15 23:38:23 -0700 | [diff] [blame] | 463 |         break; | 
| Randall Spangler | beb5bae | 2010-06-21 16:33:26 -0700 | [diff] [blame] | 464 |       } | 
| Randall Spangler | d183644 | 2010-06-10 09:59:04 -0700 | [diff] [blame] | 465 |  | 
| Randall Spangler | 640fb51 | 2011-03-03 10:11:17 -0800 | [diff] [blame] | 466 |       /* Otherwise, we do care about the key index in the TPM.  If the good | 
 | 467 |        * partition's key version is the same as the tpm, then the TPM doesn't | 
 | 468 |        * need updating; we can stop now.  Otherwise, we'll check all the other | 
 | 469 |        * headers to see if they contain a newer key. */ | 
| Randall Spangler | 6668028 | 2010-08-16 12:33:44 -0700 | [diff] [blame] | 470 |       if (combined_version == tpm_version) { | 
 | 471 |         VBDEBUG(("Same kernel version\n")); | 
| Randall Spangler | 695cd16 | 2010-06-15 23:38:23 -0700 | [diff] [blame] | 472 |         break; | 
| Randall Spangler | beb5bae | 2010-06-21 16:33:26 -0700 | [diff] [blame] | 473 |       } | 
| Randall Spangler | 741d2b2 | 2010-08-20 16:37:12 -0700 | [diff] [blame] | 474 |  | 
 | 475 |       /* Continue, so that we skip the error handling code below */ | 
 | 476 |       continue; | 
 | 477 |  | 
 | 478 |    bad_kernel: | 
 | 479 |       /* Handle errors parsing this kernel */ | 
 | 480 |       if (NULL != data_key) | 
 | 481 |         RSAPublicKeyFree(data_key); | 
 | 482 |  | 
 | 483 |       VBDEBUG(("Marking kernel as invalid.\n")); | 
 | 484 |       GptUpdateKernelEntry(&gpt, GPT_UPDATE_ENTRY_BAD); | 
 | 485 |  | 
 | 486 |  | 
| Randall Spangler | d183644 | 2010-06-10 09:59:04 -0700 | [diff] [blame] | 487 |     } /* while(GptNextKernelEntry) */ | 
 | 488 |   } while(0); | 
 | 489 |  | 
 | 490 |   /* Free kernel buffer */ | 
 | 491 |   if (kbuf) | 
 | 492 |     Free(kbuf); | 
 | 493 |  | 
 | 494 |   /* Write and free GPT data */ | 
 | 495 |   WriteAndFreeGptData(&gpt); | 
 | 496 |  | 
 | 497 |   /* Handle finding a good partition */ | 
 | 498 |   if (good_partition >= 0) { | 
| Randall Spangler | e2ec984 | 2010-06-23 21:17:07 -0700 | [diff] [blame] | 499 |     VBDEBUG(("Good_partition >= 0\n")); | 
| Randall Spangler | d183644 | 2010-06-10 09:59:04 -0700 | [diff] [blame] | 500 |  | 
 | 501 |     /* See if we need to update the TPM */ | 
| Randall Spangler | c324fbf | 2011-03-04 12:19:25 -0800 | [diff] [blame] | 502 |     if (kBootRecovery != boot_mode && good_partition_key_block_valid) { | 
| Randall Spangler | 640fb51 | 2011-03-03 10:11:17 -0800 | [diff] [blame] | 503 |       /* We only update the TPM in normal and developer boot modes.  In | 
 | 504 |        * developer mode, we only advanced lowest_version for kernels with valid | 
 | 505 |        * key blocks, and didn't count self-signed key blocks.  In recovery | 
 | 506 |        * mode, the TPM stays PP-unlocked, so anything we write gets blown away | 
 | 507 |        * by the firmware when we go back to normal mode. */ | 
 | 508 |       VBDEBUG(("Boot_flags = not recovery\n")); | 
| Randall Spangler | 6668028 | 2010-08-16 12:33:44 -0700 | [diff] [blame] | 509 |       if (lowest_version > tpm_version) { | 
 | 510 |         status = RollbackKernelWrite((uint32_t)lowest_version); | 
| Randall Spangler | 7a786b7 | 2010-07-08 13:29:42 -0700 | [diff] [blame] | 511 |         if (0 != status) { | 
| Randall Spangler | e2ec984 | 2010-06-23 21:17:07 -0700 | [diff] [blame] | 512 |           VBDEBUG(("Error writing kernel versions to TPM.\n")); | 
| Randall Spangler | 640fb51 | 2011-03-03 10:11:17 -0800 | [diff] [blame] | 513 |           if (status == TPM_E_MUST_REBOOT) | 
 | 514 |             retval = LOAD_KERNEL_REBOOT; | 
 | 515 |           else | 
 | 516 |             recovery = VBNV_RECOVERY_RW_TPM_ERROR; | 
 | 517 |           goto LoadKernelExit; | 
| Randall Spangler | 1078838 | 2010-06-23 15:35:31 -0700 | [diff] [blame] | 518 |         } | 
| Randall Spangler | d183644 | 2010-06-10 09:59:04 -0700 | [diff] [blame] | 519 |       } | 
 | 520 |     } | 
 | 521 |  | 
| Randall Spangler | 63dffcb | 2010-08-05 15:13:14 -0700 | [diff] [blame] | 522 |     /* Lock the kernel versions */ | 
 | 523 |     status = RollbackKernelLock(); | 
 | 524 |     if (0 != status) { | 
 | 525 |       VBDEBUG(("Error locking kernel versions.\n")); | 
 | 526 |       /* Don't reboot to recovery mode if we're already there */ | 
| Randall Spangler | 640fb51 | 2011-03-03 10:11:17 -0800 | [diff] [blame] | 527 |       if (kBootRecovery != boot_mode) { | 
 | 528 |         if (status == TPM_E_MUST_REBOOT) | 
 | 529 |           retval = LOAD_KERNEL_REBOOT; | 
 | 530 |         else | 
 | 531 |           recovery = VBNV_RECOVERY_RW_TPM_ERROR; | 
 | 532 |         goto LoadKernelExit; | 
 | 533 |       } | 
| Randall Spangler | d183644 | 2010-06-10 09:59:04 -0700 | [diff] [blame] | 534 |     } | 
 | 535 |  | 
 | 536 |     /* Success! */ | 
| Randall Spangler | 640fb51 | 2011-03-03 10:11:17 -0800 | [diff] [blame] | 537 |     retval = LOAD_KERNEL_SUCCESS; | 
| Randall Spangler | d183644 | 2010-06-10 09:59:04 -0700 | [diff] [blame] | 538 |   } | 
 | 539 |  | 
| Randall Spangler | 640fb51 | 2011-03-03 10:11:17 -0800 | [diff] [blame] | 540 | LoadKernelExit: | 
 | 541 |  | 
 | 542 |   /* Save whether the good partition's key block was fully verified */ | 
 | 543 |   VbNvSet(vnc, VBNV_FW_VERIFIED_KERNEL_KEY, good_partition_key_block_valid); | 
 | 544 |  | 
 | 545 |   /* Store recovery request, if any, then tear down non-volatile storage */ | 
 | 546 |   VbNvSet(vnc, VBNV_RECOVERY_REQUEST, LOAD_KERNEL_RECOVERY == retval ? | 
 | 547 |           recovery : VBNV_RECOVERY_NOT_REQUESTED); | 
 | 548 |   VbNvTeardown(vnc); | 
 | 549 |  | 
| Randall Spangler | 95c4031 | 2011-03-09 15:54:16 -0800 | [diff] [blame] | 550 |   /* Store how much shared data we used, if any */ | 
 | 551 |   if (shared) | 
 | 552 |     params->shared_data_size = shared->data_used; | 
 | 553 |  | 
| Randall Spangler | 640fb51 | 2011-03-03 10:11:17 -0800 | [diff] [blame] | 554 |   return retval; | 
| Randall Spangler | d183644 | 2010-06-10 09:59:04 -0700 | [diff] [blame] | 555 | } |