Security fixes for LoadKernel()
1) kernel_subkey is one of the input parameters; not read off disk. KeyBlockVerify() now verifies it's not NULL unless we're only using the hash.
2) Added a check for kernel size vs. buffer size.
3) Added a check to make sure kbuf_sectors is nonzero.
BUG=chrome-os-partner:704
TEST=make && make runtests
Review URL: http://codereview.chromium.org/3186013
diff --git a/firmware/lib/vboot_kernel.c b/firmware/lib/vboot_kernel.c
index 2402a09..d1d4004 100644
--- a/firmware/lib/vboot_kernel.c
+++ b/firmware/lib/vboot_kernel.c
@@ -141,6 +141,11 @@
kernel_subkey = (VbPublicKey*)params->header_sign_key_blob;
blba = params->bytes_per_lba;
kbuf_sectors = KBUF_SIZE / blba;
+ if (0 == kbuf_sectors) {
+ VBDEBUG(("LoadKernel() called with sector size > KBUF_SIZE\n"));
+ return LOAD_KERNEL_INVALID;
+ }
+
is_dev = (BOOT_FLAG_DEVELOPER & params->boot_flags ? 1 : 0);
is_rec = (BOOT_FLAG_RECOVERY & params->boot_flags ? 1 : 0);
is_normal = (!is_dev && !is_rec);
@@ -198,6 +203,8 @@
uint64_t key_version;
uint64_t combined_version;
uint64_t body_offset;
+ uint64_t body_offset_sectors;
+ uint64_t body_sectors;
VBDEBUG(("Found kernel entry at %" PRIu64 " size %" PRIu64 "\n",
part_start, part_size));
@@ -299,20 +306,27 @@
RSAPublicKeyFree(data_key);
continue;
}
+ body_offset_sectors = body_offset / blba;
+
+ /* Verify kernel body fits in the buffer */
+ 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;
+ }
/* Verify kernel body fits in the partition */
- if (body_offset + preamble->body_signature.data_size >
- part_size * blba) {
+ if (body_offset_sectors + body_sectors > part_size) {
VBDEBUG(("Kernel body doesn't fit in partition.\n"));
RSAPublicKeyFree(data_key);
continue;
}
/* Read the kernel data */
- if (0 != BootDeviceReadLBA(
- part_start + (body_offset / blba),
- (preamble->body_signature.data_size + blba - 1) / blba,
- params->kernel_buffer)) {
+ if (0 != BootDeviceReadLBA(part_start + body_offset_sectors,
+ body_sectors,
+ params->kernel_buffer)) {
VBDEBUG(("Unable to read kernel data.\n"));
RSAPublicKeyFree(data_key);
continue;