| OLD | NEW |
| 1 /* Copyright (c) 2011 The Chromium OS Authors. All rights reserved. | 1 /* Copyright (c) 2011 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 "gbb_header.h" | 14 #include "gbb_header.h" |
| 15 #include "load_kernel_fw.h" | 15 #include "load_kernel_fw.h" |
| 16 #include "rollback_index.h" | 16 #include "rollback_index.h" |
| 17 #include "utility.h" | 17 #include "utility.h" |
| 18 #include "vboot_common.h" | 18 #include "vboot_common.h" |
| 19 | 19 |
| 20 #define KBUF_SIZE 65536 /* Bytes to read at start of kernel partition */ | 20 #define KBUF_SIZE 65536 /* Bytes to read at start of kernel partition */ |
| 21 #define LOWEST_TPM_VERSION 0xffffffff | 21 #define LOWEST_TPM_VERSION 0xffffffff |
| 22 | 22 |
| 23 typedef enum BootMode { | 23 typedef enum BootMode { |
| 24 kBootNormal, /* Normal firmware */ | 24 kBootRecovery = 0, /* Recovery firmware, regardless of dev switch position */ |
| 25 kBootDev, /* Dev firmware AND dev switch is on */ | 25 kBootNormal = 1, /* Normal firmware */ |
| 26 kBootRecovery /* Recovery firmware, regardless of dev switch position */ | 26 kBootDev = 2 /* Dev firmware AND dev switch is on */ |
| 27 } BootMode; | 27 } BootMode; |
| 28 | 28 |
| 29 | 29 |
| 30 /* Allocates and reads GPT data from the drive. The sector_bytes and | 30 /* Allocates and reads GPT data from the drive. The sector_bytes and |
| 31 * drive_sectors fields should be filled on input. The primary and | 31 * drive_sectors fields should be filled on input. The primary and |
| 32 * secondary header and entries are filled on output. | 32 * secondary header and entries are filled on output. |
| 33 * | 33 * |
| 34 * Returns 0 if successful, 1 if error. */ | 34 * Returns 0 if successful, 1 if error. */ |
| 35 int AllocAndReadGptData(GptData* gptdata) { | 35 int AllocAndReadGptData(GptData* gptdata) { |
| 36 | 36 |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 114 | 114 |
| 115 /* Success */ | 115 /* Success */ |
| 116 return 0; | 116 return 0; |
| 117 } | 117 } |
| 118 | 118 |
| 119 /* disable MSVC warning on const logical expression (as in } while(0);) */ | 119 /* disable MSVC warning on const logical expression (as in } while(0);) */ |
| 120 __pragma(warning(disable: 4127)) | 120 __pragma(warning(disable: 4127)) |
| 121 | 121 |
| 122 int LoadKernel(LoadKernelParams* params) { | 122 int LoadKernel(LoadKernelParams* params) { |
| 123 VbSharedDataHeader* shared = (VbSharedDataHeader*)params->shared_data_blob; | 123 VbSharedDataHeader* shared = (VbSharedDataHeader*)params->shared_data_blob; |
| 124 VbSharedDataKernelCall* shcall = NULL; |
| 124 VbNvContext* vnc = params->nv_context; | 125 VbNvContext* vnc = params->nv_context; |
| 125 GoogleBinaryBlockHeader* gbb = (GoogleBinaryBlockHeader*)params->gbb_data; | 126 GoogleBinaryBlockHeader* gbb = (GoogleBinaryBlockHeader*)params->gbb_data; |
| 126 VbPublicKey* kernel_subkey; | 127 VbPublicKey* kernel_subkey; |
| 127 GptData gpt; | 128 GptData gpt; |
| 128 uint64_t part_start, part_size; | 129 uint64_t part_start, part_size; |
| 129 uint64_t blba; | 130 uint64_t blba; |
| 130 uint64_t kbuf_sectors; | 131 uint64_t kbuf_sectors; |
| 131 uint8_t* kbuf = NULL; | 132 uint8_t* kbuf = NULL; |
| 132 int found_partitions = 0; | 133 int found_partitions = 0; |
| 133 int good_partition = -1; | 134 int good_partition = -1; |
| 134 int good_partition_key_block_valid = 0; | 135 int good_partition_key_block_valid = 0; |
| 135 uint32_t tpm_version = 0; | 136 uint32_t tpm_version = 0; |
| 136 uint64_t lowest_version = LOWEST_TPM_VERSION; | 137 uint64_t lowest_version = LOWEST_TPM_VERSION; |
| 137 int rec_switch, dev_switch; | 138 int rec_switch, dev_switch; |
| 138 BootMode boot_mode; | 139 BootMode boot_mode; |
| 140 uint32_t test_err = 0; |
| 139 uint32_t status; | 141 uint32_t status; |
| 140 | 142 |
| 141 /* TODO: differentiate between finding an invalid kernel (found_partitions>0) | 143 int retval = LOAD_KERNEL_RECOVERY; |
| 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; | 144 int recovery = VBNV_RECOVERY_RO_UNSPECIFIED; |
| 145 uint64_t timer_enter = VbGetTimer(); |
| 146 | 146 |
| 147 /* Setup NV storage */ | 147 /* Setup NV storage */ |
| 148 VbNvSetup(vnc); | 148 VbNvSetup(vnc); |
| 149 | 149 |
| 150 /* Sanity Checks */ | 150 /* Sanity Checks */ |
| 151 if (!params || | 151 if (!params || |
| 152 !params->bytes_per_lba || | 152 !params->bytes_per_lba || |
| 153 !params->ending_lba || | 153 !params->ending_lba || |
| 154 !params->kernel_buffer || | 154 !params->kernel_buffer || |
| 155 !params->kernel_buffer_size) { | 155 !params->kernel_buffer_size) { |
| 156 VBDEBUG(("LoadKernel() called with invalid params\n")); | 156 VBDEBUG(("LoadKernel() called with invalid params\n")); |
| 157 goto LoadKernelExit; | 157 goto LoadKernelExit; |
| 158 } | 158 } |
| 159 | 159 |
| 160 /* Initialization */ | |
| 161 blba = params->bytes_per_lba; | |
| 162 kbuf_sectors = KBUF_SIZE / blba; | |
| 163 if (0 == kbuf_sectors) { | |
| 164 VBDEBUG(("LoadKernel() called with sector size > KBUF_SIZE\n")); | |
| 165 goto LoadKernelExit; | |
| 166 } | |
| 167 | |
| 168 rec_switch = (BOOT_FLAG_RECOVERY & params->boot_flags ? 1 : 0); | |
| 169 dev_switch = (BOOT_FLAG_DEVELOPER & params->boot_flags ? 1 : 0); | |
| 170 | |
| 171 if (rec_switch) | |
| 172 boot_mode = kBootRecovery; | |
| 173 else if (BOOT_FLAG_DEV_FIRMWARE & params->boot_flags) { | |
| 174 if (!dev_switch) { | |
| 175 /* Dev firmware should be signed such that it never boots with the dev | |
| 176 * switch is off; so something is terribly wrong. */ | |
| 177 VBDEBUG(("LoadKernel() called with dev firmware but dev switch off\n")); | |
| 178 recovery = VBNV_RECOVERY_RW_DEV_MISMATCH; | |
| 179 goto LoadKernelExit; | |
| 180 } | |
| 181 boot_mode = kBootDev; | |
| 182 } else { | |
| 183 /* Normal firmware */ | |
| 184 boot_mode = kBootNormal; | |
| 185 dev_switch = 0; /* Always do a fully verified boot */ | |
| 186 } | |
| 187 | |
| 188 /* Clear output params in case we fail */ | 160 /* Clear output params in case we fail */ |
| 189 params->partition_number = 0; | 161 params->partition_number = 0; |
| 190 params->bootloader_address = 0; | 162 params->bootloader_address = 0; |
| 191 params->bootloader_size = 0; | 163 params->bootloader_size = 0; |
| 192 | 164 |
| 165 /* Calculate switch positions and boot mode */ |
| 166 rec_switch = (BOOT_FLAG_RECOVERY & params->boot_flags ? 1 : 0); |
| 167 dev_switch = (BOOT_FLAG_DEVELOPER & params->boot_flags ? 1 : 0); |
| 168 if (rec_switch) |
| 169 boot_mode = kBootRecovery; |
| 170 else if (BOOT_FLAG_DEV_FIRMWARE & params->boot_flags) |
| 171 boot_mode = kBootDev; |
| 172 else { |
| 173 /* Normal firmware */ |
| 174 boot_mode = kBootNormal; |
| 175 dev_switch = 0; /* Always do a fully verified boot */ |
| 176 } |
| 177 |
| 193 if (kBootRecovery == boot_mode) { | 178 if (kBootRecovery == boot_mode) { |
| 194 /* Initialize the shared data structure, since LoadFirmware() didn't do it | 179 /* Initialize the shared data structure, since LoadFirmware() didn't do it |
| 195 * for us. */ | 180 * for us. */ |
| 196 if (0 != VbSharedDataInit(shared, params->shared_data_size)) { | 181 if (0 != VbSharedDataInit(shared, params->shared_data_size)) { |
| 197 /* Error initializing the shared data, but we can keep going. We just | 182 /* Error initializing the shared data, but we can keep going. We just |
| 198 * can't use the shared data. */ | 183 * can't use the shared data. */ |
| 199 VBDEBUG(("Shared data init error\n")); | 184 VBDEBUG(("Shared data init error\n")); |
| 200 params->shared_data_size = 0; | 185 params->shared_data_size = 0; |
| 201 shared = NULL; | 186 shared = NULL; |
| 202 } | 187 } |
| 188 } |
| 203 | 189 |
| 190 if (shared) { |
| 191 /* Set up tracking for this call. This wraps around if called many times, |
| 192 * so we need to initialize the call entry each time. */ |
| 193 shcall = shared->lk_calls + (shared->lk_call_count |
| 194 & (VBSD_MAX_KERNEL_CALLS - 1)); |
| 195 Memset(shcall, 0, sizeof(VbSharedDataKernelCall)); |
| 196 shcall->boot_flags = (uint32_t)params->boot_flags; |
| 197 shcall->boot_mode = boot_mode; |
| 198 shcall->sector_size = (uint32_t)params->bytes_per_lba; |
| 199 shcall->sector_count = params->ending_lba + 1; |
| 200 shared->lk_call_count++; |
| 201 } |
| 202 |
| 203 /* Handle test errors */ |
| 204 VbNvGet(vnc, VBNV_TEST_ERROR_FUNC, &test_err); |
| 205 if (VBNV_TEST_ERROR_LOAD_KERNEL == test_err) { |
| 206 /* Get error code */ |
| 207 VbNvGet(vnc, VBNV_TEST_ERROR_NUM, &test_err); |
| 208 if (shcall) |
| 209 shcall->test_error_num = (uint8_t)test_err; |
| 210 /* Clear test params so we don't repeat the error */ |
| 211 VbNvSet(vnc, VBNV_TEST_ERROR_FUNC, 0); |
| 212 VbNvSet(vnc, VBNV_TEST_ERROR_NUM, 0); |
| 213 /* Handle error codes */ |
| 214 switch (test_err) { |
| 215 case LOAD_KERNEL_RECOVERY: |
| 216 recovery = VBNV_RECOVERY_RW_TEST_LK; |
| 217 goto LoadKernelExit; |
| 218 case LOAD_KERNEL_NOT_FOUND: |
| 219 case LOAD_KERNEL_INVALID: |
| 220 case LOAD_KERNEL_REBOOT: |
| 221 retval = test_err; |
| 222 goto LoadKernelExit; |
| 223 default: |
| 224 break; |
| 225 } |
| 226 } |
| 227 |
| 228 /* Initialization */ |
| 229 blba = params->bytes_per_lba; |
| 230 kbuf_sectors = KBUF_SIZE / blba; |
| 231 if (0 == kbuf_sectors) { |
| 232 VBDEBUG(("LoadKernel() called with sector size > KBUF_SIZE\n")); |
| 233 goto LoadKernelExit; |
| 234 } |
| 235 |
| 236 if (kBootDev == boot_mode && !dev_switch) { |
| 237 /* Dev firmware should be signed such that it never boots with the dev |
| 238 * switch is off; so something is terribly wrong. */ |
| 239 VBDEBUG(("LoadKernel() called with dev firmware but dev switch off\n")); |
| 240 if (shcall) |
| 241 shcall->check_result = VBSD_LKC_CHECK_DEV_SWITCH_MISMATCH; |
| 242 recovery = VBNV_RECOVERY_RW_DEV_MISMATCH; |
| 243 goto LoadKernelExit; |
| 244 } |
| 245 |
| 246 if (kBootRecovery == boot_mode) { |
| 204 /* Use the recovery key to verify the kernel */ | 247 /* Use the recovery key to verify the kernel */ |
| 205 kernel_subkey = (VbPublicKey*)((uint8_t*)gbb + gbb->recovery_key_offset); | 248 kernel_subkey = (VbPublicKey*)((uint8_t*)gbb + gbb->recovery_key_offset); |
| 206 | 249 |
| 207 /* Let the TPM know if we're in recovery mode */ | 250 /* Let the TPM know if we're in recovery mode */ |
| 208 if (0 != RollbackKernelRecovery(dev_switch)) { | 251 if (0 != RollbackKernelRecovery(dev_switch)) { |
| 209 VBDEBUG(("Error setting up TPM for recovery kernel\n")); | 252 VBDEBUG(("Error setting up TPM for recovery kernel\n")); |
| 253 if (shcall) |
| 254 shcall->flags |= VBSD_LK_FLAG_REC_TPM_INIT_ERROR; |
| 210 /* Ignore return code, since we need to boot recovery mode to | 255 /* Ignore return code, since we need to boot recovery mode to |
| 211 * fix the TPM. */ | 256 * fix the TPM. */ |
| 212 } | 257 } |
| 258 |
| 259 /* Read the key indices from the TPM; ignore any errors */ |
| 260 if (shared) { |
| 261 RollbackFirmwareRead(&shared->fw_version_tpm); |
| 262 RollbackKernelRead(&shared->kernel_version_tpm); |
| 263 } |
| 213 } else { | 264 } else { |
| 214 /* Use the kernel subkey passed from LoadFirmware(). */ | 265 /* Use the kernel subkey passed from LoadFirmware(). */ |
| 215 kernel_subkey = &shared->kernel_subkey; | 266 kernel_subkey = &shared->kernel_subkey; |
| 216 | 267 |
| 217 /* Read current kernel key index from TPM. Assumes TPM is already | 268 /* Read current kernel key index from TPM. Assumes TPM is already |
| 218 * initialized. */ | 269 * initialized. */ |
| 219 status = RollbackKernelRead(&tpm_version); | 270 status = RollbackKernelRead(&tpm_version); |
| 220 if (0 != status) { | 271 if (0 != status) { |
| 221 VBDEBUG(("Unable to get kernel versions from TPM\n")); | 272 VBDEBUG(("Unable to get kernel versions from TPM\n")); |
| 222 if (status == TPM_E_MUST_REBOOT) | 273 if (status == TPM_E_MUST_REBOOT) |
| 223 retval = LOAD_KERNEL_REBOOT; | 274 retval = LOAD_KERNEL_REBOOT; |
| 224 else | 275 else |
| 225 recovery = VBNV_RECOVERY_RW_TPM_ERROR; | 276 recovery = VBNV_RECOVERY_RW_TPM_ERROR; |
| 226 goto LoadKernelExit; | 277 goto LoadKernelExit; |
| 227 } | 278 } |
| 279 if (shared) |
| 280 shared->kernel_version_tpm = tpm_version; |
| 228 } | 281 } |
| 229 | 282 |
| 230 do { | 283 do { |
| 231 /* Read GPT data */ | 284 /* Read GPT data */ |
| 232 gpt.sector_bytes = (uint32_t)blba; | 285 gpt.sector_bytes = (uint32_t)blba; |
| 233 gpt.drive_sectors = params->ending_lba + 1; | 286 gpt.drive_sectors = params->ending_lba + 1; |
| 234 if (0 != AllocAndReadGptData(&gpt)) { | 287 if (0 != AllocAndReadGptData(&gpt)) { |
| 235 VBDEBUG(("Unable to read GPT data\n")); | 288 VBDEBUG(("Unable to read GPT data\n")); |
| 289 if (shcall) |
| 290 shcall->check_result = VBSD_LKC_CHECK_GPT_READ_ERROR; |
| 236 break; | 291 break; |
| 237 } | 292 } |
| 238 | 293 |
| 239 /* Initialize GPT library */ | 294 /* Initialize GPT library */ |
| 240 if (GPT_SUCCESS != GptInit(&gpt)) { | 295 if (GPT_SUCCESS != GptInit(&gpt)) { |
| 241 VBDEBUG(("Error parsing GPT\n")); | 296 VBDEBUG(("Error parsing GPT\n")); |
| 297 if (shcall) |
| 298 shcall->check_result = VBSD_LKC_CHECK_GPT_PARSE_ERROR; |
| 242 break; | 299 break; |
| 243 } | 300 } |
| 244 | 301 |
| 245 /* Allocate kernel header buffers */ | 302 /* Allocate kernel header buffers */ |
| 246 kbuf = (uint8_t*)Malloc(KBUF_SIZE); | 303 kbuf = (uint8_t*)Malloc(KBUF_SIZE); |
| 247 if (!kbuf) | 304 if (!kbuf) |
| 248 break; | 305 break; |
| 249 | 306 |
| 250 /* Loop over candidate kernel partitions */ | 307 /* Loop over candidate kernel partitions */ |
| 251 while (GPT_SUCCESS == GptNextKernelEntry(&gpt, &part_start, &part_size)) { | 308 while (GPT_SUCCESS == GptNextKernelEntry(&gpt, &part_start, &part_size)) { |
| 309 VbSharedDataKernelPart* shpart = NULL; |
| 252 VbKeyBlockHeader* key_block; | 310 VbKeyBlockHeader* key_block; |
| 253 VbKernelPreambleHeader* preamble; | 311 VbKernelPreambleHeader* preamble; |
| 254 RSAPublicKey* data_key = NULL; | 312 RSAPublicKey* data_key = NULL; |
| 255 uint64_t key_version; | 313 uint64_t key_version; |
| 256 uint64_t combined_version; | 314 uint64_t combined_version; |
| 257 uint64_t body_offset; | 315 uint64_t body_offset; |
| 258 uint64_t body_offset_sectors; | 316 uint64_t body_offset_sectors; |
| 259 uint64_t body_sectors; | 317 uint64_t body_sectors; |
| 260 int key_block_valid = 1; | 318 int key_block_valid = 1; |
| 261 | 319 |
| 262 VBDEBUG(("Found kernel entry at %" PRIu64 " size %" PRIu64 "\n", | 320 VBDEBUG(("Found kernel entry at %" PRIu64 " size %" PRIu64 "\n", |
| 263 part_start, part_size)); | 321 part_start, part_size)); |
| 264 | 322 |
| 323 if (shcall) { |
| 324 /* Set up tracking for this partition. This wraps around if called |
| 325 * many times, so initialize the partition entry each time. */ |
| 326 shpart = shcall->parts + (shcall->kernel_parts_found |
| 327 & (VBSD_MAX_KERNEL_PARTS - 1)); |
| 328 Memset(shpart, 0, sizeof(VbSharedDataKernelPart)); |
| 329 shpart->sector_start = part_start; |
| 330 shpart->sector_count = part_size; |
| 331 /* TODO: GPT partitions start at 1, but cgptlib starts them at 0. |
| 332 * Adjust here, until cgptlib is fixed. */ |
| 333 shpart->gpt_index = (uint8_t)(gpt.current_kernel + 1); |
| 334 shcall->kernel_parts_found++; |
| 335 } |
| 336 |
| 265 /* Found at least one kernel partition. */ | 337 /* Found at least one kernel partition. */ |
| 266 found_partitions++; | 338 found_partitions++; |
| 267 | 339 |
| 268 /* Read the first part of the kernel partition. */ | 340 /* Read the first part of the kernel partition. */ |
| 269 if (part_size < kbuf_sectors) { | 341 if (part_size < kbuf_sectors) { |
| 270 VBDEBUG(("Partition too small to hold kernel.\n")); | 342 VBDEBUG(("Partition too small to hold kernel.\n")); |
| 343 if (shpart) |
| 344 shpart->check_result = VBSD_LKP_CHECK_TOO_SMALL; |
| 271 goto bad_kernel; | 345 goto bad_kernel; |
| 272 } | 346 } |
| 273 | 347 |
| 274 if (0 != BootDeviceReadLBA(part_start, kbuf_sectors, kbuf)) { | 348 if (0 != BootDeviceReadLBA(part_start, kbuf_sectors, kbuf)) { |
| 275 VBDEBUG(("Unable to read start of partition.\n")); | 349 VBDEBUG(("Unable to read start of partition.\n")); |
| 350 if (shpart) |
| 351 shpart->check_result = VBSD_LKP_CHECK_READ_START; |
| 276 goto bad_kernel; | 352 goto bad_kernel; |
| 277 } | 353 } |
| 278 | 354 |
| 279 /* Verify the key block. */ | 355 /* Verify the key block. */ |
| 280 key_block = (VbKeyBlockHeader*)kbuf; | 356 key_block = (VbKeyBlockHeader*)kbuf; |
| 281 if (0 != KeyBlockVerify(key_block, KBUF_SIZE, kernel_subkey, 0)) { | 357 if (0 != KeyBlockVerify(key_block, KBUF_SIZE, kernel_subkey, 0)) { |
| 282 VBDEBUG(("Verifying key block signature failed.\n")); | 358 VBDEBUG(("Verifying key block signature failed.\n")); |
| 359 if (shpart) |
| 360 shpart->check_result = VBSD_LKP_CHECK_KEY_BLOCK_SIG; |
| 361 |
| 283 key_block_valid = 0; | 362 key_block_valid = 0; |
| 284 | 363 |
| 285 /* If we're not in developer mode, this kernel is bad. */ | 364 /* If we're not in developer mode, this kernel is bad. */ |
| 286 if (kBootDev != boot_mode) | 365 if (kBootDev != boot_mode) |
| 287 goto bad_kernel; | 366 goto bad_kernel; |
| 288 | 367 |
| 289 /* In developer mode, we can continue if the SHA-512 hash of the key | 368 /* In developer mode, we can continue if the SHA-512 hash of the key |
| 290 * block is valid. */ | 369 * block is valid. */ |
| 291 if (0 != KeyBlockVerify(key_block, KBUF_SIZE, kernel_subkey, 1)) { | 370 if (0 != KeyBlockVerify(key_block, KBUF_SIZE, kernel_subkey, 1)) { |
| 292 VBDEBUG(("Verifying key block hash failed.\n")); | 371 VBDEBUG(("Verifying key block hash failed.\n")); |
| 372 if (shpart) |
| 373 shpart->check_result = VBSD_LKP_CHECK_KEY_BLOCK_HASH; |
| 293 goto bad_kernel; | 374 goto bad_kernel; |
| 294 } | 375 } |
| 295 } | 376 } |
| 296 | 377 |
| 297 /* Check the key block flags against the current boot mode. */ | 378 /* Check the key block flags against the current boot mode. */ |
| 298 if (!(key_block->key_block_flags & | 379 if (!(key_block->key_block_flags & |
| 299 (dev_switch ? KEY_BLOCK_FLAG_DEVELOPER_1 : | 380 (dev_switch ? KEY_BLOCK_FLAG_DEVELOPER_1 : |
| 300 KEY_BLOCK_FLAG_DEVELOPER_0))) { | 381 KEY_BLOCK_FLAG_DEVELOPER_0))) { |
| 301 VBDEBUG(("Key block developer flag mismatch.\n")); | 382 VBDEBUG(("Key block developer flag mismatch.\n")); |
| 383 if (shpart) |
| 384 shpart->check_result = VBSD_LKP_CHECK_DEV_MISMATCH; |
| 302 key_block_valid = 0; | 385 key_block_valid = 0; |
| 303 } | 386 } |
| 304 if (!(key_block->key_block_flags & | 387 if (!(key_block->key_block_flags & |
| 305 (rec_switch ? KEY_BLOCK_FLAG_RECOVERY_1 : | 388 (rec_switch ? KEY_BLOCK_FLAG_RECOVERY_1 : |
| 306 KEY_BLOCK_FLAG_RECOVERY_0))) { | 389 KEY_BLOCK_FLAG_RECOVERY_0))) { |
| 307 VBDEBUG(("Key block recovery flag mismatch.\n")); | 390 VBDEBUG(("Key block recovery flag mismatch.\n")); |
| 391 if (shpart) |
| 392 shpart->check_result = VBSD_LKP_CHECK_REC_MISMATCH; |
| 308 key_block_valid = 0; | 393 key_block_valid = 0; |
| 309 } | 394 } |
| 310 | 395 |
| 311 /* Check for rollback of key version except in recovery mode. */ | 396 /* Check for rollback of key version except in recovery mode. */ |
| 312 key_version = key_block->data_key.key_version; | 397 key_version = key_block->data_key.key_version; |
| 313 if (kBootRecovery != boot_mode) { | 398 if (kBootRecovery != boot_mode) { |
| 314 if (key_version < (tpm_version >> 16)) { | 399 if (key_version < (tpm_version >> 16)) { |
| 315 VBDEBUG(("Key version too old.\n")); | 400 VBDEBUG(("Key version too old.\n")); |
| 401 if (shpart) |
| 402 shpart->check_result = VBSD_LKP_CHECK_KEY_ROLLBACK; |
| 316 key_block_valid = 0; | 403 key_block_valid = 0; |
| 317 } | 404 } |
| 318 } | 405 } |
| 319 | 406 |
| 320 /* If we're not in developer mode, require the key block to be valid. */ | 407 /* If we're not in developer mode, require the key block to be valid. */ |
| 321 if (kBootDev != boot_mode && !key_block_valid) { | 408 if (kBootDev != boot_mode && !key_block_valid) { |
| 322 VBDEBUG(("Key block is invalid.\n")); | 409 VBDEBUG(("Key block is invalid.\n")); |
| 323 goto bad_kernel; | 410 goto bad_kernel; |
| 324 } | 411 } |
| 325 | 412 |
| 326 /* Get the key for preamble/data verification from the key block. */ | 413 /* Get the key for preamble/data verification from the key block. */ |
| 327 data_key = PublicKeyToRSA(&key_block->data_key); | 414 data_key = PublicKeyToRSA(&key_block->data_key); |
| 328 if (!data_key) { | 415 if (!data_key) { |
| 329 VBDEBUG(("Data key bad.\n")); | 416 VBDEBUG(("Data key bad.\n")); |
| 417 if (shpart) |
| 418 shpart->check_result = VBSD_LKP_CHECK_DATA_KEY_PARSE; |
| 330 goto bad_kernel; | 419 goto bad_kernel; |
| 331 } | 420 } |
| 332 | 421 |
| 333 /* Verify the preamble, which follows the key block */ | 422 /* Verify the preamble, which follows the key block */ |
| 334 preamble = (VbKernelPreambleHeader*)(kbuf + key_block->key_block_size); | 423 preamble = (VbKernelPreambleHeader*)(kbuf + key_block->key_block_size); |
| 335 if ((0 != VerifyKernelPreamble(preamble, | 424 if ((0 != VerifyKernelPreamble(preamble, |
| 336 KBUF_SIZE - key_block->key_block_size, | 425 KBUF_SIZE - key_block->key_block_size, |
| 337 data_key))) { | 426 data_key))) { |
| 338 VBDEBUG(("Preamble verification failed.\n")); | 427 VBDEBUG(("Preamble verification failed.\n")); |
| 428 if (shpart) |
| 429 shpart->check_result = VBSD_LKP_CHECK_VERIFY_PREAMBLE; |
| 339 goto bad_kernel; | 430 goto bad_kernel; |
| 340 } | 431 } |
| 341 | 432 |
| 342 /* If the key block is valid and we're not in recovery mode, check for | 433 /* If the key block is valid and we're not in recovery mode, check for |
| 343 * rollback of the kernel version. */ | 434 * rollback of the kernel version. */ |
| 344 combined_version = ((key_version << 16) | | 435 combined_version = ((key_version << 16) | |
| 345 (preamble->kernel_version & 0xFFFF)); | 436 (preamble->kernel_version & 0xFFFF)); |
| 437 if (shpart) |
| 438 shpart->combined_version = (uint32_t)combined_version; |
| 346 if (key_block_valid && kBootRecovery != boot_mode) { | 439 if (key_block_valid && kBootRecovery != boot_mode) { |
| 347 if (combined_version < tpm_version) { | 440 if (combined_version < tpm_version) { |
| 348 VBDEBUG(("Kernel version too low.\n")); | 441 VBDEBUG(("Kernel version too low.\n")); |
| 442 if (shpart) |
| 443 shpart->check_result = VBSD_LKP_CHECK_KERNEL_ROLLBACK; |
| 349 /* If we're not in developer mode, kernel version must be valid. */ | 444 /* If we're not in developer mode, kernel version must be valid. */ |
| 350 if (kBootDev != boot_mode) | 445 if (kBootDev != boot_mode) |
| 351 goto bad_kernel; | 446 goto bad_kernel; |
| 352 } | 447 } |
| 353 } | 448 } |
| 354 | 449 |
| 355 VBDEBUG(("Kernel preamble is good.\n")); | 450 VBDEBUG(("Kernel preamble is good.\n")); |
| 451 if (shpart) |
| 452 shpart->check_result = VBSD_LKP_CHECK_PREAMBLE_VALID; |
| 356 | 453 |
| 357 /* Check for lowest version from a valid header. */ | 454 /* Check for lowest version from a valid header. */ |
| 358 if (key_block_valid && lowest_version > combined_version) | 455 if (key_block_valid && lowest_version > combined_version) |
| 359 lowest_version = combined_version; | 456 lowest_version = combined_version; |
| 360 else { | 457 else { |
| 361 VBDEBUG(("Key block valid: %d\n", key_block_valid)); | 458 VBDEBUG(("Key block valid: %d\n", key_block_valid)); |
| 362 VBDEBUG(("Combined version: %" PRIu64 "\n", combined_version)); | 459 VBDEBUG(("Combined version: %" PRIu64 "\n", combined_version)); |
| 363 } | 460 } |
| 364 | 461 |
| 365 /* If we already have a good kernel, no need to read another | 462 /* If we already have a good kernel, no need to read another |
| 366 * one; we only needed to look at the versions to check for | 463 * one; we only needed to look at the versions to check for |
| 367 * rollback. So skip to the next kernel preamble. */ | 464 * rollback. So skip to the next kernel preamble. */ |
| 368 if (-1 != good_partition) | 465 if (-1 != good_partition) |
| 369 continue; | 466 continue; |
| 370 | 467 |
| 371 /* Verify body load address matches what we expect */ | 468 /* Verify body load address matches what we expect */ |
| 372 if ((preamble->body_load_address != (size_t)params->kernel_buffer) && | 469 if ((preamble->body_load_address != (size_t)params->kernel_buffer) && |
| 373 !(params->boot_flags & BOOT_FLAG_SKIP_ADDR_CHECK)) { | 470 !(params->boot_flags & BOOT_FLAG_SKIP_ADDR_CHECK)) { |
| 374 VBDEBUG(("Wrong body load address.\n")); | 471 VBDEBUG(("Wrong body load address.\n")); |
| 472 if (shpart) |
| 473 shpart->check_result = VBSD_LKP_CHECK_BODY_ADDRESS; |
| 375 goto bad_kernel; | 474 goto bad_kernel; |
| 376 } | 475 } |
| 377 | 476 |
| 378 /* Verify kernel body starts at a multiple of the sector size. */ | 477 /* Verify kernel body starts at a multiple of the sector size. */ |
| 379 body_offset = key_block->key_block_size + preamble->preamble_size; | 478 body_offset = key_block->key_block_size + preamble->preamble_size; |
| 380 if (0 != body_offset % blba) { | 479 if (0 != body_offset % blba) { |
| 381 VBDEBUG(("Kernel body not at multiple of sector size.\n")); | 480 VBDEBUG(("Kernel body not at multiple of sector size.\n")); |
| 481 if (shpart) |
| 482 shpart->check_result = VBSD_LKP_CHECK_BODY_OFFSET; |
| 382 goto bad_kernel; | 483 goto bad_kernel; |
| 383 } | 484 } |
| 384 body_offset_sectors = body_offset / blba; | 485 body_offset_sectors = body_offset / blba; |
| 385 | 486 |
| 386 /* Verify kernel body fits in the buffer */ | 487 /* Verify kernel body fits in the buffer */ |
| 387 body_sectors = (preamble->body_signature.data_size + blba - 1) / blba; | 488 body_sectors = (preamble->body_signature.data_size + blba - 1) / blba; |
| 388 if (body_sectors * blba > params->kernel_buffer_size) { | 489 if (body_sectors * blba > params->kernel_buffer_size) { |
| 389 VBDEBUG(("Kernel body doesn't fit in memory.\n")); | 490 VBDEBUG(("Kernel body doesn't fit in memory.\n")); |
| 491 if (shpart) |
| 492 shpart->check_result = VBSD_LKP_CHECK_BODY_EXCEEDS_MEM; |
| 390 goto bad_kernel; | 493 goto bad_kernel; |
| 391 } | 494 } |
| 392 | 495 |
| 393 /* Verify kernel body fits in the partition */ | 496 /* Verify kernel body fits in the partition */ |
| 394 if (body_offset_sectors + body_sectors > part_size) { | 497 if (body_offset_sectors + body_sectors > part_size) { |
| 395 VBDEBUG(("Kernel body doesn't fit in partition.\n")); | 498 VBDEBUG(("Kernel body doesn't fit in partition.\n")); |
| 499 if (shpart) |
| 500 shpart->check_result = VBSD_LKP_CHECK_BODY_EXCEEDS_PART; |
| 396 goto bad_kernel; | 501 goto bad_kernel; |
| 397 } | 502 } |
| 398 | 503 |
| 399 /* Read the kernel data */ | 504 /* Read the kernel data */ |
| 400 VBPERFSTART("VB_RKD"); | 505 VBPERFSTART("VB_RKD"); |
| 401 if (0 != BootDeviceReadLBA(part_start + body_offset_sectors, | 506 if (0 != BootDeviceReadLBA(part_start + body_offset_sectors, |
| 402 body_sectors, | 507 body_sectors, |
| 403 params->kernel_buffer)) { | 508 params->kernel_buffer)) { |
| 404 VBDEBUG(("Unable to read kernel data.\n")); | 509 VBDEBUG(("Unable to read kernel data.\n")); |
| 405 VBPERFEND("VB_RKD"); | 510 VBPERFEND("VB_RKD"); |
| 511 if (shpart) |
| 512 shpart->check_result = VBSD_LKP_CHECK_READ_DATA; |
| 406 goto bad_kernel; | 513 goto bad_kernel; |
| 407 } | 514 } |
| 408 VBPERFEND("VB_RKD"); | 515 VBPERFEND("VB_RKD"); |
| 409 | 516 |
| 410 /* Verify kernel data */ | 517 /* Verify kernel data */ |
| 411 if (0 != VerifyData((const uint8_t*)params->kernel_buffer, | 518 if (0 != VerifyData((const uint8_t*)params->kernel_buffer, |
| 412 params->kernel_buffer_size, | 519 params->kernel_buffer_size, |
| 413 &preamble->body_signature, data_key)) { | 520 &preamble->body_signature, data_key)) { |
| 414 VBDEBUG(("Kernel data verification failed.\n")); | 521 VBDEBUG(("Kernel data verification failed.\n")); |
| 522 if (shpart) |
| 523 shpart->check_result = VBSD_LKP_CHECK_VERIFY_DATA; |
| 415 goto bad_kernel; | 524 goto bad_kernel; |
| 416 } | 525 } |
| 417 | 526 |
| 418 /* Done with the kernel signing key, so can free it now */ | 527 /* Done with the kernel signing key, so can free it now */ |
| 419 RSAPublicKeyFree(data_key); | 528 RSAPublicKeyFree(data_key); |
| 420 data_key = NULL; | 529 data_key = NULL; |
| 421 | 530 |
| 422 /* If we're still here, the kernel is valid. */ | 531 /* If we're still here, the kernel is valid. */ |
| 423 /* Save the first good partition we find; that's the one we'll boot */ | 532 /* Save the first good partition we find; that's the one we'll boot */ |
| 424 VBDEBUG(("Partition is good.\n")); | 533 VBDEBUG(("Partition is good.\n")); |
| 534 if (shpart) { |
| 535 shpart->check_result = VBSD_LKP_CHECK_KERNEL_GOOD; |
| 536 if (key_block_valid) |
| 537 shpart->flags |= VBSD_LKP_FLAG_KEY_BLOCK_VALID; |
| 538 } |
| 539 |
| 425 good_partition_key_block_valid = key_block_valid; | 540 good_partition_key_block_valid = key_block_valid; |
| 426 /* TODO: GPT partitions start at 1, but cgptlib starts them at 0. | 541 /* TODO: GPT partitions start at 1, but cgptlib starts them at 0. |
| 427 * Adjust here, until cgptlib is fixed. */ | 542 * Adjust here, until cgptlib is fixed. */ |
| 428 good_partition = gpt.current_kernel + 1; | 543 good_partition = gpt.current_kernel + 1; |
| 429 params->partition_number = gpt.current_kernel + 1; | 544 params->partition_number = gpt.current_kernel + 1; |
| 430 GetCurrentKernelUniqueGuid(&gpt, ¶ms->partition_guid); | 545 GetCurrentKernelUniqueGuid(&gpt, ¶ms->partition_guid); |
| 431 /* TODO: GetCurrentKernelUniqueGuid() should take a destination size, or | 546 /* TODO: GetCurrentKernelUniqueGuid() should take a destination size, or |
| 432 * the dest should be a struct, so we know it's big enough. */ | 547 * the dest should be a struct, so we know it's big enough. */ |
| 433 params->bootloader_address = preamble->bootloader_address; | 548 params->bootloader_address = preamble->bootloader_address; |
| 434 params->bootloader_size = preamble->bootloader_size; | 549 params->bootloader_size = preamble->bootloader_size; |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 471 /* Free kernel buffer */ | 586 /* Free kernel buffer */ |
| 472 if (kbuf) | 587 if (kbuf) |
| 473 Free(kbuf); | 588 Free(kbuf); |
| 474 | 589 |
| 475 /* Write and free GPT data */ | 590 /* Write and free GPT data */ |
| 476 WriteAndFreeGptData(&gpt); | 591 WriteAndFreeGptData(&gpt); |
| 477 | 592 |
| 478 /* Handle finding a good partition */ | 593 /* Handle finding a good partition */ |
| 479 if (good_partition >= 0) { | 594 if (good_partition >= 0) { |
| 480 VBDEBUG(("Good_partition >= 0\n")); | 595 VBDEBUG(("Good_partition >= 0\n")); |
| 596 if (shcall) |
| 597 shcall->check_result = VBSD_LKC_CHECK_GOOD_PARTITION; |
| 481 | 598 |
| 482 /* See if we need to update the TPM */ | 599 /* See if we need to update the TPM */ |
| 483 if (kBootRecovery != boot_mode && good_partition_key_block_valid) { | 600 if (kBootRecovery != boot_mode && good_partition_key_block_valid) { |
| 484 /* We only update the TPM in normal and developer boot modes. In | 601 /* We only update the TPM in normal and developer boot modes. In |
| 485 * developer mode, we only advanced lowest_version for kernels with valid | 602 * developer mode, we only advanced lowest_version for kernels with valid |
| 486 * key blocks, and didn't count self-signed key blocks. In recovery | 603 * key blocks, and didn't count self-signed key blocks. In recovery |
| 487 * mode, the TPM stays PP-unlocked, so anything we write gets blown away | 604 * mode, the TPM stays PP-unlocked, so anything we write gets blown away |
| 488 * by the firmware when we go back to normal mode. */ | 605 * by the firmware when we go back to normal mode. */ |
| 489 VBDEBUG(("Boot_flags = not recovery\n")); | 606 VBDEBUG(("Boot_flags = not recovery\n")); |
| 490 | 607 |
| 491 if ((lowest_version > tpm_version) && | 608 if ((lowest_version > tpm_version) && |
| 492 (lowest_version != LOWEST_TPM_VERSION)) { | 609 (lowest_version != LOWEST_TPM_VERSION)) { |
| 493 status = RollbackKernelWrite((uint32_t)lowest_version); | 610 status = RollbackKernelWrite((uint32_t)lowest_version); |
| 494 if (0 != status) { | 611 if (0 != status) { |
| 495 VBDEBUG(("Error writing kernel versions to TPM.\n")); | 612 VBDEBUG(("Error writing kernel versions to TPM.\n")); |
| 496 if (status == TPM_E_MUST_REBOOT) | 613 if (status == TPM_E_MUST_REBOOT) |
| 497 retval = LOAD_KERNEL_REBOOT; | 614 retval = LOAD_KERNEL_REBOOT; |
| 498 else | 615 else |
| 499 recovery = VBNV_RECOVERY_RW_TPM_ERROR; | 616 recovery = VBNV_RECOVERY_RW_TPM_ERROR; |
| 500 goto LoadKernelExit; | 617 goto LoadKernelExit; |
| 501 } | 618 } |
| 619 if (shared) |
| 620 shared->kernel_version_tpm = (uint32_t)lowest_version; |
| 502 } | 621 } |
| 503 } | 622 } |
| 504 | 623 |
| 505 /* Lock the kernel versions */ | 624 /* Lock the kernel versions */ |
| 506 status = RollbackKernelLock(); | 625 status = RollbackKernelLock(); |
| 507 if (0 != status) { | 626 if (0 != status) { |
| 508 VBDEBUG(("Error locking kernel versions.\n")); | 627 VBDEBUG(("Error locking kernel versions.\n")); |
| 509 /* Don't reboot to recovery mode if we're already there */ | 628 /* Don't reboot to recovery mode if we're already there */ |
| 510 if (kBootRecovery != boot_mode) { | 629 if (kBootRecovery != boot_mode) { |
| 511 if (status == TPM_E_MUST_REBOOT) | 630 if (status == TPM_E_MUST_REBOOT) |
| 512 retval = LOAD_KERNEL_REBOOT; | 631 retval = LOAD_KERNEL_REBOOT; |
| 513 else | 632 else |
| 514 recovery = VBNV_RECOVERY_RW_TPM_ERROR; | 633 recovery = VBNV_RECOVERY_RW_TPM_ERROR; |
| 515 goto LoadKernelExit; | 634 goto LoadKernelExit; |
| 516 } | 635 } |
| 517 } | 636 } |
| 518 | 637 |
| 519 /* Success! */ | 638 /* Success! */ |
| 520 retval = LOAD_KERNEL_SUCCESS; | 639 retval = LOAD_KERNEL_SUCCESS; |
| 640 } else { |
| 641 if (shcall) |
| 642 shcall->check_result = (found_partitions > 0 |
| 643 ? VBSD_LKC_CHECK_INVALID_PARTITIONS |
| 644 : VBSD_LKC_CHECK_NO_PARTITIONS); |
| 645 |
| 646 /* TODO: differentiate between finding an invalid kernel |
| 647 * (found_partitions>0) and not finding one at all. Right now we |
| 648 * treat them the same, and return LOAD_KERNEL_INVALID for both. */ |
| 649 retval = LOAD_KERNEL_INVALID; |
| 521 } | 650 } |
| 522 | 651 |
| 523 LoadKernelExit: | 652 LoadKernelExit: |
| 524 | 653 |
| 525 /* Save whether the good partition's key block was fully verified */ | |
| 526 VbNvSet(vnc, VBNV_FW_VERIFIED_KERNEL_KEY, good_partition_key_block_valid); | |
| 527 | |
| 528 /* Store recovery request, if any, then tear down non-volatile storage */ | 654 /* Store recovery request, if any, then tear down non-volatile storage */ |
| 529 VbNvSet(vnc, VBNV_RECOVERY_REQUEST, LOAD_KERNEL_RECOVERY == retval ? | 655 VbNvSet(vnc, VBNV_RECOVERY_REQUEST, LOAD_KERNEL_RECOVERY == retval ? |
| 530 recovery : VBNV_RECOVERY_NOT_REQUESTED); | 656 recovery : VBNV_RECOVERY_NOT_REQUESTED); |
| 531 VbNvTeardown(vnc); | 657 VbNvTeardown(vnc); |
| 532 | 658 |
| 533 /* Store how much shared data we used, if any */ | 659 if (shared) { |
| 534 if (shared) | 660 if (shcall) |
| 661 shcall->return_code = (uint8_t)retval; |
| 662 |
| 663 /* Save whether the good partition's key block was fully verified */ |
| 664 if (good_partition_key_block_valid) |
| 665 shared->flags |= VBSD_KERNEL_KEY_VERIFIED; |
| 666 |
| 667 /* Save timer values */ |
| 668 shared->timer_load_kernel_enter = timer_enter; |
| 669 shared->timer_load_kernel_exit = VbGetTimer(); |
| 670 /* Store how much shared data we used, if any */ |
| 535 params->shared_data_size = shared->data_used; | 671 params->shared_data_size = shared->data_used; |
| 672 } |
| 536 | 673 |
| 537 return retval; | 674 return retval; |
| 538 } | 675 } |
| OLD | NEW |