Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(621)

Unified Diff: firmware/lib/vboot_kernel.c

Issue 6688035: Add VbSharedData debug output to LoadKernel() (Closed) Base URL: ssh://git@gitrw.chromium.org:9222/vboot_reference.git@master
Patch Set: Created 9 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « firmware/include/vboot_struct.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: firmware/lib/vboot_kernel.c
diff --git a/firmware/lib/vboot_kernel.c b/firmware/lib/vboot_kernel.c
index 204874f6e03c434f23d7e614595679e0366bd029..3d7d58572aa1eb950cf8d1b9b74ea53b682a0e35 100644
--- a/firmware/lib/vboot_kernel.c
+++ b/firmware/lib/vboot_kernel.c
@@ -21,9 +21,9 @@
#define LOWEST_TPM_VERSION 0xffffffff
typedef enum BootMode {
- kBootNormal, /* Normal firmware */
- kBootDev, /* Dev firmware AND dev switch is on */
- kBootRecovery /* Recovery firmware, regardless of dev switch position */
+ kBootRecovery = 0, /* Recovery firmware, regardless of dev switch position */
+ kBootNormal = 1, /* Normal firmware */
+ kBootDev = 2 /* Dev firmware AND dev switch is on */
} BootMode;
@@ -121,6 +121,7 @@ __pragma(warning(disable: 4127))
int LoadKernel(LoadKernelParams* params) {
VbSharedDataHeader* shared = (VbSharedDataHeader*)params->shared_data_blob;
+ VbSharedDataKernelCall* shcall = NULL;
VbNvContext* vnc = params->nv_context;
GoogleBinaryBlockHeader* gbb = (GoogleBinaryBlockHeader*)params->gbb_data;
VbPublicKey* kernel_subkey;
@@ -161,11 +162,51 @@ int LoadKernel(LoadKernelParams* params) {
params->bootloader_address = 0;
params->bootloader_size = 0;
+ /* Calculate switch positions and boot mode */
+ rec_switch = (BOOT_FLAG_RECOVERY & params->boot_flags ? 1 : 0);
+ dev_switch = (BOOT_FLAG_DEVELOPER & params->boot_flags ? 1 : 0);
+ if (rec_switch)
+ boot_mode = kBootRecovery;
+ else if (BOOT_FLAG_DEV_FIRMWARE & params->boot_flags)
+ boot_mode = kBootDev;
+ else {
+ /* Normal firmware */
+ boot_mode = kBootNormal;
+ dev_switch = 0; /* Always do a fully verified boot */
+ }
+
+ if (kBootRecovery == boot_mode) {
+ /* Initialize the shared data structure, since LoadFirmware() didn't do it
+ * for us. */
+ if (0 != VbSharedDataInit(shared, params->shared_data_size)) {
+ /* Error initializing the shared data, but we can keep going. We just
+ * can't use the shared data. */
+ VBDEBUG(("Shared data init error\n"));
+ params->shared_data_size = 0;
+ shared = NULL;
+ }
+ }
+
+ if (shared) {
+ /* Set up tracking for this call. This wraps around if called many times,
+ * so we need to initialize the call entry each time. */
+ shcall = shared->lk_calls + (shared->lk_call_count
+ & (VBSD_MAX_KERNEL_CALLS - 1));
+ Memset(shcall, 0, sizeof(VbSharedDataKernelCall));
+ shcall->boot_flags = (uint32_t)params->boot_flags;
+ shcall->boot_mode = boot_mode;
+ shcall->sector_size = (uint32_t)params->bytes_per_lba;
+ shcall->sector_count = params->ending_lba + 1;
+ shared->lk_call_count++;
+ }
+
/* Handle test errors */
VbNvGet(vnc, VBNV_TEST_ERROR_FUNC, &test_err);
if (VBNV_TEST_ERROR_LOAD_KERNEL == test_err) {
/* Get error code */
VbNvGet(vnc, VBNV_TEST_ERROR_NUM, &test_err);
+ if (shcall)
+ shcall->test_error_num = (uint8_t)test_err;
/* Clear test params so we don't repeat the error */
VbNvSet(vnc, VBNV_TEST_ERROR_FUNC, 0);
VbNvSet(vnc, VBNV_TEST_ERROR_NUM, 0);
@@ -192,43 +233,25 @@ int LoadKernel(LoadKernelParams* params) {
goto LoadKernelExit;
}
- rec_switch = (BOOT_FLAG_RECOVERY & params->boot_flags ? 1 : 0);
- dev_switch = (BOOT_FLAG_DEVELOPER & params->boot_flags ? 1 : 0);
-
- if (rec_switch)
- boot_mode = kBootRecovery;
- else if (BOOT_FLAG_DEV_FIRMWARE & params->boot_flags) {
- if (!dev_switch) {
+ if (kBootDev == boot_mode && !dev_switch) {
/* Dev firmware should be signed such that it never boots with the dev
* switch is off; so something is terribly wrong. */
VBDEBUG(("LoadKernel() called with dev firmware but dev switch off\n"));
+ if (shcall)
+ shcall->check_result = VBSD_LKC_CHECK_DEV_SWITCH_MISMATCH;
recovery = VBNV_RECOVERY_RW_DEV_MISMATCH;
goto LoadKernelExit;
}
- boot_mode = kBootDev;
- } else {
- /* Normal firmware */
- boot_mode = kBootNormal;
- dev_switch = 0; /* Always do a fully verified boot */
- }
if (kBootRecovery == boot_mode) {
- /* Initialize the shared data structure, since LoadFirmware() didn't do it
- * for us. */
- if (0 != VbSharedDataInit(shared, params->shared_data_size)) {
- /* Error initializing the shared data, but we can keep going. We just
- * can't use the shared data. */
- VBDEBUG(("Shared data init error\n"));
- params->shared_data_size = 0;
- shared = NULL;
- }
-
/* Use the recovery key to verify the kernel */
kernel_subkey = (VbPublicKey*)((uint8_t*)gbb + gbb->recovery_key_offset);
/* Let the TPM know if we're in recovery mode */
if (0 != RollbackKernelRecovery(dev_switch)) {
VBDEBUG(("Error setting up TPM for recovery kernel\n"));
+ if (shcall)
+ shcall->flags |= VBSD_LK_FLAG_REC_TPM_INIT_ERROR;
/* Ignore return code, since we need to boot recovery mode to
* fix the TPM. */
}
@@ -263,12 +286,16 @@ int LoadKernel(LoadKernelParams* params) {
gpt.drive_sectors = params->ending_lba + 1;
if (0 != AllocAndReadGptData(&gpt)) {
VBDEBUG(("Unable to read GPT data\n"));
+ if (shcall)
+ shcall->check_result = VBSD_LKC_CHECK_GPT_READ_ERROR;
break;
}
/* Initialize GPT library */
if (GPT_SUCCESS != GptInit(&gpt)) {
VBDEBUG(("Error parsing GPT\n"));
+ if (shcall)
+ shcall->check_result = VBSD_LKC_CHECK_GPT_PARSE_ERROR;
break;
}
@@ -279,6 +306,7 @@ int LoadKernel(LoadKernelParams* params) {
/* Loop over candidate kernel partitions */
while (GPT_SUCCESS == GptNextKernelEntry(&gpt, &part_start, &part_size)) {
+ VbSharedDataKernelPart* shpart = NULL;
VbKeyBlockHeader* key_block;
VbKernelPreambleHeader* preamble;
RSAPublicKey* data_key = NULL;
@@ -292,17 +320,35 @@ int LoadKernel(LoadKernelParams* params) {
VBDEBUG(("Found kernel entry at %" PRIu64 " size %" PRIu64 "\n",
part_start, part_size));
+ if (shcall) {
+ /* Set up tracking for this call. This wraps around if called many
+ * times, so we need to initialize the partition entry each time. */
+ shpart = shcall->parts + (shcall->kernel_parts_found
+ & (VBSD_MAX_KERNEL_PARTS - 1));
+ Memset(shpart, 0, sizeof(VbSharedDataKernelPart));
+ shpart->sector_start = part_start;
+ shpart->sector_count = part_size;
+ /* TODO: GPT partitions start at 1, but cgptlib starts them at 0.
+ * Adjust here, until cgptlib is fixed. */
+ shpart->gpt_index = (uint8_t)(gpt.current_kernel + 1);
+ shcall->kernel_parts_found++;
+ }
+
/* Found at least one kernel partition. */
found_partitions++;
/* Read the first part of the kernel partition. */
if (part_size < kbuf_sectors) {
VBDEBUG(("Partition too small to hold kernel.\n"));
+ if (shpart)
+ shpart->check_result = VBSD_LKP_CHECK_TOO_SMALL;
goto bad_kernel;
}
if (0 != BootDeviceReadLBA(part_start, kbuf_sectors, kbuf)) {
VBDEBUG(("Unable to read start of partition.\n"));
+ if (shpart)
+ shpart->check_result = VBSD_LKP_CHECK_READ_START;
goto bad_kernel;
}
@@ -310,6 +356,9 @@ int LoadKernel(LoadKernelParams* params) {
key_block = (VbKeyBlockHeader*)kbuf;
if (0 != KeyBlockVerify(key_block, KBUF_SIZE, kernel_subkey, 0)) {
VBDEBUG(("Verifying key block signature failed.\n"));
+ if (shpart)
+ shpart->check_result = VBSD_LKP_CHECK_KEY_BLOCK_SIG;
+
key_block_valid = 0;
/* If we're not in developer mode, this kernel is bad. */
@@ -320,6 +369,8 @@ int LoadKernel(LoadKernelParams* params) {
* block is valid. */
if (0 != KeyBlockVerify(key_block, KBUF_SIZE, kernel_subkey, 1)) {
VBDEBUG(("Verifying key block hash failed.\n"));
+ if (shpart)
+ shpart->check_result = VBSD_LKP_CHECK_KEY_BLOCK_HASH;
goto bad_kernel;
}
}
@@ -329,12 +380,16 @@ int LoadKernel(LoadKernelParams* params) {
(dev_switch ? KEY_BLOCK_FLAG_DEVELOPER_1 :
KEY_BLOCK_FLAG_DEVELOPER_0))) {
VBDEBUG(("Key block developer flag mismatch.\n"));
+ if (shpart)
+ shpart->check_result = VBSD_LKP_CHECK_DEV_MISMATCH;
key_block_valid = 0;
}
if (!(key_block->key_block_flags &
(rec_switch ? KEY_BLOCK_FLAG_RECOVERY_1 :
KEY_BLOCK_FLAG_RECOVERY_0))) {
VBDEBUG(("Key block recovery flag mismatch.\n"));
+ if (shpart)
+ shpart->check_result = VBSD_LKP_CHECK_REC_MISMATCH;
key_block_valid = 0;
}
@@ -343,6 +398,8 @@ int LoadKernel(LoadKernelParams* params) {
if (kBootRecovery != boot_mode) {
if (key_version < (tpm_version >> 16)) {
VBDEBUG(("Key version too old.\n"));
+ if (shpart)
+ shpart->check_result = VBSD_LKP_CHECK_KEY_ROLLBACK;
key_block_valid = 0;
}
}
@@ -357,6 +414,8 @@ int LoadKernel(LoadKernelParams* params) {
data_key = PublicKeyToRSA(&key_block->data_key);
if (!data_key) {
VBDEBUG(("Data key bad.\n"));
+ if (shpart)
+ shpart->check_result = VBSD_LKP_CHECK_DATA_KEY_PARSE;
goto bad_kernel;
}
@@ -366,6 +425,8 @@ int LoadKernel(LoadKernelParams* params) {
KBUF_SIZE - key_block->key_block_size,
data_key))) {
VBDEBUG(("Preamble verification failed.\n"));
+ if (shpart)
+ shpart->check_result = VBSD_LKP_CHECK_VERIFY_PREAMBLE;
goto bad_kernel;
}
@@ -373,9 +434,13 @@ int LoadKernel(LoadKernelParams* params) {
* rollback of the kernel version. */
combined_version = ((key_version << 16) |
(preamble->kernel_version & 0xFFFF));
+ if (shpart)
+ shpart->combined_version = (uint32_t)combined_version;
if (key_block_valid && kBootRecovery != boot_mode) {
if (combined_version < tpm_version) {
VBDEBUG(("Kernel version too low.\n"));
+ if (shpart)
+ shpart->check_result = VBSD_LKP_CHECK_KERNEL_ROLLBACK;
/* If we're not in developer mode, kernel version must be valid. */
if (kBootDev != boot_mode)
goto bad_kernel;
@@ -383,6 +448,8 @@ int LoadKernel(LoadKernelParams* params) {
}
VBDEBUG(("Kernel preamble is good.\n"));
+ if (shpart)
+ shpart->check_result = VBSD_LKP_CHECK_PREAMBLE_VALID;
/* Check for lowest version from a valid header. */
if (key_block_valid && lowest_version > combined_version)
@@ -402,6 +469,8 @@ int LoadKernel(LoadKernelParams* params) {
if ((preamble->body_load_address != (size_t)params->kernel_buffer) &&
!(params->boot_flags & BOOT_FLAG_SKIP_ADDR_CHECK)) {
VBDEBUG(("Wrong body load address.\n"));
+ if (shpart)
+ shpart->check_result = VBSD_LKP_CHECK_BODY_ADDRESS;
goto bad_kernel;
}
@@ -409,6 +478,8 @@ int LoadKernel(LoadKernelParams* params) {
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"));
+ if (shpart)
+ shpart->check_result = VBSD_LKP_CHECK_BODY_OFFSET;
goto bad_kernel;
}
body_offset_sectors = body_offset / blba;
@@ -417,12 +488,16 @@ 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"));
+ if (shpart)
+ shpart->check_result = VBSD_LKP_CHECK_BODY_EXCEEDS_MEM;
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"));
+ if (shpart)
+ shpart->check_result = VBSD_LKP_CHECK_BODY_EXCEEDS_PART;
goto bad_kernel;
}
@@ -433,6 +508,8 @@ int LoadKernel(LoadKernelParams* params) {
params->kernel_buffer)) {
VBDEBUG(("Unable to read kernel data.\n"));
VBPERFEND("VB_RKD");
+ if (shpart)
+ shpart->check_result = VBSD_LKP_CHECK_READ_DATA;
goto bad_kernel;
}
VBPERFEND("VB_RKD");
@@ -442,6 +519,8 @@ int LoadKernel(LoadKernelParams* params) {
params->kernel_buffer_size,
&preamble->body_signature, data_key)) {
VBDEBUG(("Kernel data verification failed.\n"));
+ if (shpart)
+ shpart->check_result = VBSD_LKP_CHECK_VERIFY_DATA;
goto bad_kernel;
}
@@ -452,6 +531,12 @@ int LoadKernel(LoadKernelParams* params) {
/* If we're still here, the kernel is valid. */
/* Save the first good partition we find; that's the one we'll boot */
VBDEBUG(("Partition is good.\n"));
+ if (shpart) {
+ shpart->check_result = VBSD_LKP_CHECK_KERNEL_GOOD;
+ if (key_block_valid)
+ shpart->flags |= VBSD_LKP_FLAG_KEY_BLOCK_VALID;
+ }
+
good_partition_key_block_valid = key_block_valid;
/* TODO: GPT partitions start at 1, but cgptlib starts them at 0.
* Adjust here, until cgptlib is fixed. */
@@ -508,6 +593,8 @@ int LoadKernel(LoadKernelParams* params) {
/* Handle finding a good partition */
if (good_partition >= 0) {
VBDEBUG(("Good_partition >= 0\n"));
+ if (shcall)
+ shcall->check_result = VBSD_LKC_CHECK_GOOD_PARTITION;
/* See if we need to update the TPM */
if (kBootRecovery != boot_mode && good_partition_key_block_valid) {
@@ -551,6 +638,11 @@ int LoadKernel(LoadKernelParams* params) {
/* Success! */
retval = LOAD_KERNEL_SUCCESS;
} else {
+ if (shcall)
+ shcall->check_result = (found_partitions > 0
+ ? VBSD_LKC_CHECK_INVALID_PARTITIONS
+ : VBSD_LKC_CHECK_NO_PARTITIONS);
+
/* TODO: differentiate between finding an invalid kernel
* (found_partitions>0) and not finding one at all. Right now we
* treat them the same, and return LOAD_KERNEL_INVALID for both. */
@@ -568,6 +660,13 @@ LoadKernelExit:
VbNvTeardown(vnc);
if (shared) {
+ if (shcall)
+ shcall->return_code = (uint8_t)retval;
+
+ /* Save whether the good partition's key block was fully verified */
+ if (good_partition_key_block_valid)
+ shared->flags |= VBSD_KERNEL_KEY_VERIFIED;
+
/* Save timer values */
shared->timer_load_kernel_enter = timer_enter;
shared->timer_load_kernel_exit = VbGetTimer();
« no previous file with comments | « firmware/include/vboot_struct.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698