Index: firmware/lib/vboot_kernel.c |
diff --git a/firmware/lib/vboot_kernel.c b/firmware/lib/vboot_kernel.c |
index d1d4004b32fb8633fca4bc0b309475ee5d84039d..93ed4d1ec35ac1775eae963de1283fa133d6c359 100644 |
--- a/firmware/lib/vboot_kernel.c |
+++ b/firmware/lib/vboot_kernel.c |
@@ -199,7 +199,7 @@ int LoadKernel(LoadKernelParams* params) { |
while (GPT_SUCCESS == GptNextKernelEntry(&gpt, &part_start, &part_size)) { |
VbKeyBlockHeader* key_block; |
VbKernelPreambleHeader* preamble; |
- RSAPublicKey* data_key; |
+ RSAPublicKey* data_key = NULL; |
uint64_t key_version; |
uint64_t combined_version; |
uint64_t body_offset; |
@@ -214,9 +214,9 @@ int LoadKernel(LoadKernelParams* params) { |
/* Read the first part of the kernel partition */ |
if (part_size < kbuf_sectors) |
- continue; |
+ goto bad_kernel; |
if (0 != BootDeviceReadLBA(part_start, kbuf_sectors, kbuf)) |
- continue; |
+ goto bad_kernel; |
/* Verify the key block. In developer mode, we ignore the key |
* and use only the SHA-512 hash to verify the key block. */ |
@@ -224,7 +224,7 @@ int LoadKernel(LoadKernelParams* params) { |
if ((0 != KeyBlockVerify(key_block, KBUF_SIZE, kernel_subkey, |
is_dev && !is_rec))) { |
VBDEBUG(("Verifying key block failed.\n")); |
- continue; |
+ goto bad_kernel; |
} |
/* Check the key block flags against the current boot mode in normal |
@@ -234,13 +234,13 @@ int LoadKernel(LoadKernelParams* params) { |
(is_dev ? KEY_BLOCK_FLAG_DEVELOPER_1 : |
KEY_BLOCK_FLAG_DEVELOPER_0))) { |
VBDEBUG(("Developer flag mismatch.\n")); |
- continue; |
+ goto bad_kernel; |
} |
if (!(key_block->key_block_flags & |
(is_rec ? KEY_BLOCK_FLAG_RECOVERY_1 : |
KEY_BLOCK_FLAG_RECOVERY_0))) { |
VBDEBUG(("Recovery flag mismatch.\n")); |
- continue; |
+ goto bad_kernel; |
} |
} |
@@ -250,13 +250,13 @@ int LoadKernel(LoadKernelParams* params) { |
key_version = key_block->data_key.key_version; |
if (key_version < (tpm_version >> 16)) { |
VBDEBUG(("Key version too old.\n")); |
- continue; |
+ goto bad_kernel; |
} |
/* Get the key for preamble/data verification from the key block */ |
data_key = PublicKeyToRSA(&key_block->data_key); |
if (!data_key) |
- continue; |
+ goto bad_kernel; |
/* Verify the preamble, which follows the key block */ |
preamble = (VbKernelPreambleHeader*)(kbuf + key_block->key_block_size); |
@@ -264,8 +264,7 @@ int LoadKernel(LoadKernelParams* params) { |
KBUF_SIZE - key_block->key_block_size, |
data_key))) { |
VBDEBUG(("Preamble verification failed.\n")); |
- RSAPublicKeyFree(data_key); |
- continue; |
+ goto bad_kernel; |
} |
/* Check for rollback of kernel version. Note this is implicitly |
@@ -275,8 +274,7 @@ int LoadKernel(LoadKernelParams* params) { |
(preamble->kernel_version & 0xFFFF)); |
if (combined_version < tpm_version) { |
VBDEBUG(("Kernel version too low.\n")); |
- RSAPublicKeyFree(data_key); |
- continue; |
+ goto bad_kernel; |
} |
VBDEBUG(("Kernel preamble is good.\n")); |
@@ -289,22 +287,20 @@ int LoadKernel(LoadKernelParams* params) { |
* one; we only needed to look at the versions to check for |
* rollback. */ |
if (-1 != good_partition) |
- continue; |
+ goto bad_kernel; |
Randall Spangler
2010/08/20 21:20:47
Heh, note that we'd previously missed freeing the
|
/* Verify body load address matches what we expect */ |
if ((preamble->body_load_address != (size_t)params->kernel_buffer) && |
!(params->boot_flags & BOOT_FLAG_SKIP_ADDR_CHECK)) { |
VBDEBUG(("Wrong body load address.\n")); |
- RSAPublicKeyFree(data_key); |
- continue; |
+ goto bad_kernel; |
} |
/* Verify kernel body starts at a multiple of the sector size. */ |
body_offset = key_block->key_block_size + preamble->preamble_size; |
if (0 != body_offset % blba) { |
VBDEBUG(("Kernel body not at multiple of sector size.\n")); |
- RSAPublicKeyFree(data_key); |
- continue; |
+ goto bad_kernel; |
} |
body_offset_sectors = body_offset / blba; |
@@ -312,15 +308,13 @@ int LoadKernel(LoadKernelParams* params) { |
body_sectors = (preamble->body_signature.data_size + blba - 1) / blba; |
if (body_sectors * blba > params->kernel_buffer_size) { |
VBDEBUG(("Kernel body doesn't fit in memory.\n")); |
- RSAPublicKeyFree(data_key); |
- continue; |
+ goto bad_kernel; |
} |
/* Verify kernel body fits in the partition */ |
if (body_offset_sectors + body_sectors > part_size) { |
VBDEBUG(("Kernel body doesn't fit in partition.\n")); |
- RSAPublicKeyFree(data_key); |
- continue; |
+ goto bad_kernel; |
} |
/* Read the kernel data */ |
@@ -328,8 +322,7 @@ int LoadKernel(LoadKernelParams* params) { |
body_sectors, |
params->kernel_buffer)) { |
VBDEBUG(("Unable to read kernel data.\n")); |
- RSAPublicKeyFree(data_key); |
- continue; |
+ goto bad_kernel; |
} |
/* Verify kernel data */ |
@@ -337,12 +330,12 @@ int LoadKernel(LoadKernelParams* params) { |
params->kernel_buffer_size, |
&preamble->body_signature, data_key)) { |
VBDEBUG(("Kernel data verification failed.\n")); |
- RSAPublicKeyFree(data_key); |
- continue; |
+ goto bad_kernel; |
} |
/* Done with the kernel signing key, so can free it now */ |
RSAPublicKeyFree(data_key); |
+ data_key = NULL; |
/* If we're still here, the kernel is valid. */ |
/* Save the first good partition we find; that's the one we'll boot */ |
@@ -356,6 +349,10 @@ int LoadKernel(LoadKernelParams* params) { |
* the dest should be a struct, so we know it's big enough. */ |
params->bootloader_address = preamble->bootloader_address; |
params->bootloader_size = preamble->bootloader_size; |
+ |
+ /* Update GPT to note this is the kernel we're trying */ |
+ GptUpdateKernelEntry(&gpt, GPT_UPDATE_ENTRY_TRY); |
+ |
/* If we're in developer or recovery mode, there's no rollback |
* protection, so we can stop at the first valid kernel. */ |
if (!is_normal) { |
@@ -372,6 +369,19 @@ int LoadKernel(LoadKernelParams* params) { |
VBDEBUG(("Same kernel version\n")); |
break; |
} |
+ |
+ /* Continue, so that we skip the error handling code below */ |
+ continue; |
+ |
+ bad_kernel: |
+ /* Handle errors parsing this kernel */ |
+ if (NULL != data_key) |
gauravsh
2010/08/20 21:29:01
this null check is not needed. All the *Free() fun
|
+ RSAPublicKeyFree(data_key); |
+ |
+ VBDEBUG(("Marking kernel as invalid.\n")); |
+ GptUpdateKernelEntry(&gpt, GPT_UPDATE_ENTRY_BAD); |
+ |
+ |
} /* while(GptNextKernelEntry) */ |
} while(0); |