| OLD | NEW |
| 1 /* Copyright (c) 2010 The Chromium OS Authors. All rights reserved. | 1 /* Copyright (c) 2010 The Chromium OS Authors. All rights reserved. |
| 2 * Use of this source code is governed by a BSD-style license that can be | 2 * Use of this source code is governed by a BSD-style license that can be |
| 3 * found in the LICENSE file. | 3 * found in the LICENSE file. |
| 4 * | 4 * |
| 5 * Functions for loading a kernel from disk. | 5 * Functions for loading a kernel from disk. |
| 6 * (Firmware portion) | 6 * (Firmware portion) |
| 7 */ | 7 */ |
| 8 | 8 |
| 9 #include "vboot_kernel.h" | 9 #include "vboot_kernel.h" |
| 10 | 10 |
| 11 #include <inttypes.h> /* For PRIu64 */ |
| 11 #include "boot_device.h" | 12 #include "boot_device.h" |
| 12 #include "cgptlib.h" | 13 #include "cgptlib.h" |
| 13 #include "load_kernel_fw.h" | 14 #include "load_kernel_fw.h" |
| 14 #include "rollback_index.h" | 15 #include "rollback_index.h" |
| 15 #include "utility.h" | 16 #include "utility.h" |
| 16 #include "vboot_common.h" | 17 #include "vboot_common.h" |
| 17 | 18 |
| 18 | 19 |
| 19 #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 */ |
| 20 | 21 |
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 128 /* Clear output params in case we fail */ | 129 /* Clear output params in case we fail */ |
| 129 params->partition_number = 0; | 130 params->partition_number = 0; |
| 130 params->bootloader_address = 0; | 131 params->bootloader_address = 0; |
| 131 params->bootloader_size = 0; | 132 params->bootloader_size = 0; |
| 132 | 133 |
| 133 if (is_normal) { | 134 if (is_normal) { |
| 134 /* Read current kernel key index from TPM. Assumes TPM is already | 135 /* Read current kernel key index from TPM. Assumes TPM is already |
| 135 * initialized. */ | 136 * initialized. */ |
| 136 if (0 != GetStoredVersions(KERNEL_VERSIONS, | 137 if (0 != GetStoredVersions(KERNEL_VERSIONS, |
| 137 &tpm_key_version, | 138 &tpm_key_version, |
| 138 &tpm_kernel_version)) | 139 &tpm_kernel_version)) { |
| 140 debug("Unable to get stored version from TPM\n"); |
| 139 return LOAD_KERNEL_RECOVERY; | 141 return LOAD_KERNEL_RECOVERY; |
| 142 } |
| 140 } else if (is_dev) { | 143 } else if (is_dev) { |
| 141 /* In developer mode, we ignore the kernel subkey, and just use | 144 /* In developer mode, we ignore the kernel subkey, and just use |
| 142 * the SHA-512 hash to verify the key block. */ | 145 * the SHA-512 hash to verify the key block. */ |
| 143 kernel_subkey = NULL; | 146 kernel_subkey = NULL; |
| 144 } | 147 } |
| 145 | 148 |
| 146 do { | 149 do { |
| 147 /* Read GPT data */ | 150 /* Read GPT data */ |
| 148 gpt.sector_bytes = blba; | 151 gpt.sector_bytes = blba; |
| 149 gpt.drive_sectors = params->ending_lba + 1; | 152 gpt.drive_sectors = params->ending_lba + 1; |
| 150 if (0 != AllocAndReadGptData(&gpt)) | 153 if (0 != AllocAndReadGptData(&gpt)) { |
| 154 debug("Unable to read GPT data\n"); |
| 151 break; | 155 break; |
| 156 } |
| 152 | 157 |
| 153 /* Initialize GPT library */ | 158 /* Initialize GPT library */ |
| 154 if (GPT_SUCCESS != GptInit(&gpt)) | 159 if (GPT_SUCCESS != GptInit(&gpt)) { |
| 160 debug("Error parsing GPT\n"); |
| 155 break; | 161 break; |
| 162 } |
| 156 | 163 |
| 157 /* Allocate kernel header buffers */ | 164 /* Allocate kernel header buffers */ |
| 158 kbuf = (uint8_t*)Malloc(KBUF_SIZE); | 165 kbuf = (uint8_t*)Malloc(KBUF_SIZE); |
| 159 if (!kbuf) | 166 if (!kbuf) |
| 160 break; | 167 break; |
| 161 | 168 |
| 162 /* Loop over candidate kernel partitions */ | 169 /* Loop over candidate kernel partitions */ |
| 163 while (GPT_SUCCESS == GptNextKernelEntry(&gpt, &part_start, &part_size)) { | 170 while (GPT_SUCCESS == GptNextKernelEntry(&gpt, &part_start, &part_size)) { |
| 164 VbKeyBlockHeader* key_block; | 171 VbKeyBlockHeader* key_block; |
| 165 VbKernelPreambleHeader* preamble; | 172 VbKernelPreambleHeader* preamble; |
| 166 RSAPublicKey* data_key; | 173 RSAPublicKey* data_key; |
| 167 uint64_t key_version; | 174 uint64_t key_version; |
| 168 uint64_t body_offset; | 175 uint64_t body_offset; |
| 169 | 176 |
| 177 debug("Found kernel entry at %" PRIu64 " size %" PRIu64 "\n", |
| 178 part_start, part_size); |
| 179 |
| 170 /* Found at least one kernel partition. */ | 180 /* Found at least one kernel partition. */ |
| 171 found_partitions++; | 181 found_partitions++; |
| 172 | 182 |
| 173 /* Read the first part of the kernel partition */ | 183 /* Read the first part of the kernel partition */ |
| 174 if (part_size < kbuf_sectors) | 184 if (part_size < kbuf_sectors) |
| 175 continue; | 185 continue; |
| 176 if (0 != BootDeviceReadLBA(part_start, kbuf_sectors, kbuf)) | 186 if (0 != BootDeviceReadLBA(part_start, kbuf_sectors, kbuf)) |
| 177 continue; | 187 continue; |
| 178 | 188 |
| 179 /* Verify the key block */ | 189 /* Verify the key block */ |
| 180 key_block = (VbKeyBlockHeader*)kbuf; | 190 key_block = (VbKeyBlockHeader*)kbuf; |
| 181 if ((0 != KeyBlockVerify(key_block, KBUF_SIZE, kernel_subkey))) | 191 if ((0 != KeyBlockVerify(key_block, KBUF_SIZE, kernel_subkey))) { |
| 192 debug("Verifying key block failed.\n"); |
| 182 continue; | 193 continue; |
| 194 } |
| 183 | 195 |
| 184 /* Check the key block flags against the current boot mode */ | 196 /* Check the key block flags against the current boot mode */ |
| 185 if (!(key_block->key_block_flags && | 197 if (!(key_block->key_block_flags && |
| 186 ((BOOT_FLAG_DEVELOPER & params->boot_flags) ? | 198 ((BOOT_FLAG_DEVELOPER & params->boot_flags) ? |
| 187 KEY_BLOCK_FLAG_DEVELOPER_1 : KEY_BLOCK_FLAG_DEVELOPER_0))) | 199 KEY_BLOCK_FLAG_DEVELOPER_1 : KEY_BLOCK_FLAG_DEVELOPER_0))) { |
| 200 debug("Developer flag mismatch.\n"); |
| 188 continue; | 201 continue; |
| 202 } |
| 189 if (!(key_block->key_block_flags && | 203 if (!(key_block->key_block_flags && |
| 190 ((BOOT_FLAG_RECOVERY & params->boot_flags) ? | 204 ((BOOT_FLAG_RECOVERY & params->boot_flags) ? |
| 191 KEY_BLOCK_FLAG_RECOVERY_1 : KEY_BLOCK_FLAG_RECOVERY_0))) | 205 KEY_BLOCK_FLAG_RECOVERY_1 : KEY_BLOCK_FLAG_RECOVERY_0))) { |
| 206 debug("Recovery flag mismatch.\n"); |
| 192 continue; | 207 continue; |
| 208 } |
| 193 | 209 |
| 194 /* Check for rollback of key version. Note this is implicitly | 210 /* Check for rollback of key version. Note this is implicitly |
| 195 * skipped in recovery and developer modes because those set | 211 * skipped in recovery and developer modes because those set |
| 196 * key_version=0 above. */ | 212 * key_version=0 above. */ |
| 197 key_version = key_block->data_key.key_version; | 213 key_version = key_block->data_key.key_version; |
| 198 if (key_version < tpm_key_version) | 214 if (key_version < tpm_key_version) { |
| 215 debug("Key version too old.\n"); |
| 199 continue; | 216 continue; |
| 217 } |
| 200 | 218 |
| 201 /* Get the key for preamble/data verification from the key block */ | 219 /* Get the key for preamble/data verification from the key block */ |
| 202 data_key = PublicKeyToRSA(&key_block->data_key); | 220 data_key = PublicKeyToRSA(&key_block->data_key); |
| 203 if (!data_key) | 221 if (!data_key) |
| 204 continue; | 222 continue; |
| 205 | 223 |
| 206 /* Verify the preamble, which follows the key block */ | 224 /* Verify the preamble, which follows the key block */ |
| 207 preamble = (VbKernelPreambleHeader*)(kbuf + key_block->key_block_size); | 225 preamble = (VbKernelPreambleHeader*)(kbuf + key_block->key_block_size); |
| 208 if ((0 != VerifyKernelPreamble2(preamble, | 226 if ((0 != VerifyKernelPreamble2(preamble, |
| 209 KBUF_SIZE - key_block->key_block_size, | 227 KBUF_SIZE - key_block->key_block_size, |
| 210 data_key))) { | 228 data_key))) { |
| 229 debug("Preamble verification failed.\n"); |
| 211 RSAPublicKeyFree(data_key); | 230 RSAPublicKeyFree(data_key); |
| 212 continue; | 231 continue; |
| 213 } | 232 } |
| 214 | 233 |
| 215 /* Check for rollback of kernel version. Note this is implicitly | 234 /* Check for rollback of kernel version. Note this is implicitly |
| 216 * skipped in recovery and developer modes because those set | 235 * skipped in recovery and developer modes because those set |
| 217 * key_version=0 and kernel_version=0 above. */ | 236 * key_version=0 and kernel_version=0 above. */ |
| 218 if (key_version == tpm_key_version && | 237 if (key_version == tpm_key_version && |
| 219 preamble->kernel_version < tpm_kernel_version) { | 238 preamble->kernel_version < tpm_kernel_version) { |
| 239 debug("Kernel version too low.\n"); |
| 220 RSAPublicKeyFree(data_key); | 240 RSAPublicKeyFree(data_key); |
| 221 continue; | 241 continue; |
| 222 } | 242 } |
| 223 | 243 |
| 244 debug("Kernel preamble is good.\n"); |
| 245 |
| 224 /* Check for lowest key version from a valid header. */ | 246 /* Check for lowest key version from a valid header. */ |
| 225 if (lowest_key_version > key_version) { | 247 if (lowest_key_version > key_version) { |
| 226 lowest_key_version = key_version; | 248 lowest_key_version = key_version; |
| 227 lowest_kernel_version = preamble->kernel_version; | 249 lowest_kernel_version = preamble->kernel_version; |
| 228 } | 250 } |
| 229 else if (lowest_key_version == key_version && | 251 else if (lowest_key_version == key_version && |
| 230 lowest_kernel_version > preamble->kernel_version) { | 252 lowest_kernel_version > preamble->kernel_version) { |
| 231 lowest_kernel_version = preamble->kernel_version; | 253 lowest_kernel_version = preamble->kernel_version; |
| 232 } | 254 } |
| 233 | 255 |
| 234 /* If we already have a good kernel, no need to read another | 256 /* If we already have a good kernel, no need to read another |
| 235 * one; we only needed to look at the versions to check for | 257 * one; we only needed to look at the versions to check for |
| 236 * rollback. */ | 258 * rollback. */ |
| 237 if (-1 != good_partition) | 259 if (-1 != good_partition) |
| 238 continue; | 260 continue; |
| 239 | 261 |
| 240 /* Verify body load address matches what we expect */ | 262 /* Verify body load address matches what we expect */ |
| 241 if (preamble->body_load_address != (size_t)params->kernel_buffer) { | 263 if ((preamble->body_load_address != (size_t)params->kernel_buffer) && |
| 264 !(params->boot_flags & BOOT_FLAG_SKIP_ADDR_CHECK)) { |
| 265 debug("Wrong body load address.\n"); |
| 242 RSAPublicKeyFree(data_key); | 266 RSAPublicKeyFree(data_key); |
| 243 continue; | 267 continue; |
| 244 } | 268 } |
| 245 | 269 |
| 246 /* Verify kernel body starts at a multiple of the sector size. */ | 270 /* Verify kernel body starts at a multiple of the sector size. */ |
| 247 body_offset = key_block->key_block_size + preamble->preamble_size; | 271 body_offset = key_block->key_block_size + preamble->preamble_size; |
| 248 if (0 != body_offset % blba) { | 272 if (0 != body_offset % blba) { |
| 273 debug("Kernel body not at multiple of sector size.\n"); |
| 249 RSAPublicKeyFree(data_key); | 274 RSAPublicKeyFree(data_key); |
| 250 continue; | 275 continue; |
| 251 } | 276 } |
| 252 | 277 |
| 253 /* Verify kernel body fits in the partition */ | 278 /* Verify kernel body fits in the partition */ |
| 254 if (body_offset + preamble->body_signature.data_size > | 279 if (body_offset + preamble->body_signature.data_size > |
| 255 part_size * blba) { | 280 part_size * blba) { |
| 281 debug("Kernel body doesn't fit in partition.\n"); |
| 256 RSAPublicKeyFree(data_key); | 282 RSAPublicKeyFree(data_key); |
| 257 continue; | 283 continue; |
| 258 } | 284 } |
| 259 | 285 |
| 260 /* Read the kernel data */ | 286 /* Read the kernel data */ |
| 261 if (0 != BootDeviceReadLBA( | 287 if (0 != BootDeviceReadLBA( |
| 262 part_start + (body_offset / blba), | 288 part_start + (body_offset / blba), |
| 263 (preamble->body_signature.data_size + blba - 1) / blba, | 289 (preamble->body_signature.data_size + blba - 1) / blba, |
| 264 params->kernel_buffer)) { | 290 params->kernel_buffer)) { |
| 291 debug("Unable to read kernel data.\n"); |
| 265 RSAPublicKeyFree(data_key); | 292 RSAPublicKeyFree(data_key); |
| 266 continue; | 293 continue; |
| 267 } | 294 } |
| 268 | 295 |
| 269 /* Verify kernel data */ | 296 /* Verify kernel data */ |
| 270 if (0 != VerifyData((const uint8_t*)params->kernel_buffer, | 297 if (0 != VerifyData((const uint8_t*)params->kernel_buffer, |
| 271 &preamble->body_signature, data_key)) { | 298 &preamble->body_signature, data_key)) { |
| 299 debug("Kernel data verification failed.\n"); |
| 272 RSAPublicKeyFree(data_key); | 300 RSAPublicKeyFree(data_key); |
| 273 continue; | 301 continue; |
| 274 } | 302 } |
| 275 | 303 |
| 276 /* Done with the kernel signing key, so can free it now */ | 304 /* Done with the kernel signing key, so can free it now */ |
| 277 RSAPublicKeyFree(data_key); | 305 RSAPublicKeyFree(data_key); |
| 278 | 306 |
| 279 /* If we're still here, the kernel is valid. */ | 307 /* If we're still here, the kernel is valid. */ |
| 280 /* Save the first good partition we find; that's the one we'll boot */ | 308 /* Save the first good partition we find; that's the one we'll boot */ |
| 281 if (-1 == good_partition) { | 309 debug("Partiton is good.\n"); |
| 282 good_partition = gpt.current_kernel; | 310 good_partition = gpt.current_kernel; |
| 283 params->partition_number = gpt.current_kernel; | 311 params->partition_number = gpt.current_kernel; |
| 284 params->bootloader_address = preamble->bootloader_address; | 312 params->bootloader_address = preamble->bootloader_address; |
| 285 params->bootloader_size = preamble->bootloader_size; | 313 params->bootloader_size = preamble->bootloader_size; |
| 286 /* If we're in developer or recovery mode, there's no rollback | 314 /* If we're in developer or recovery mode, there's no rollback |
| 287 * protection, so we can stop at the first valid kernel. */ | 315 * protection, so we can stop at the first valid kernel. */ |
| 288 if (!is_normal) | 316 if (!is_normal) |
| 289 break; | 317 break; |
| 290 | 318 |
| 291 /* Otherwise, we're in normal boot mode, so we do care about | 319 /* Otherwise, we're in normal boot mode, so we do care about the |
| 292 * the key index in the TPM. If the good partition's key | 320 * key index in the TPM. If the good partition's key version is |
| 293 * version is the same as the tpm, then the TPM doesn't need | 321 * the same as the tpm, then the TPM doesn't need updating; we |
| 294 * updating; we can stop now. Otherwise, we'll check all the | 322 * can stop now. Otherwise, we'll check all the other headers |
| 295 * other headers to see if they contain a newer key. */ | 323 * to see if they contain a newer key. */ |
| 296 if (key_version == tpm_key_version && | 324 if (key_version == tpm_key_version && |
| 297 preamble->kernel_version == tpm_kernel_version) | 325 preamble->kernel_version == tpm_kernel_version) |
| 298 break; | 326 break; |
| 299 } | |
| 300 } /* while(GptNextKernelEntry) */ | 327 } /* while(GptNextKernelEntry) */ |
| 301 } while(0); | 328 } while(0); |
| 302 | 329 |
| 303 /* Free kernel buffer */ | 330 /* Free kernel buffer */ |
| 304 if (kbuf) | 331 if (kbuf) |
| 305 Free(kbuf); | 332 Free(kbuf); |
| 306 | 333 |
| 307 /* Write and free GPT data */ | 334 /* Write and free GPT data */ |
| 308 WriteAndFreeGptData(&gpt); | 335 WriteAndFreeGptData(&gpt); |
| 309 | 336 |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 344 /* Success! */ | 371 /* Success! */ |
| 345 return LOAD_KERNEL_SUCCESS; | 372 return LOAD_KERNEL_SUCCESS; |
| 346 } | 373 } |
| 347 | 374 |
| 348 // Handle error cases | 375 // Handle error cases |
| 349 if (found_partitions) | 376 if (found_partitions) |
| 350 return LOAD_KERNEL_INVALID; | 377 return LOAD_KERNEL_INVALID; |
| 351 else | 378 else |
| 352 return LOAD_KERNEL_NOT_FOUND; | 379 return LOAD_KERNEL_NOT_FOUND; |
| 353 } | 380 } |
| OLD | NEW |