VBoot Reference: Add kernel rollback prevention and choosing logic.
Also adds tests for kernel rollback prevention.
Review URL: http://codereview.chromium.org/1320010
diff --git a/include/kernel_image.h b/include/kernel_image.h
index c098c07..6adf3f8 100644
--- a/include/kernel_image.h
+++ b/include/kernel_image.h
@@ -17,6 +17,9 @@
#define KERNEL_MAGIC_SIZE 8
#define KERNEL_CMD_LINE_SIZE 4096
+#define DEV_MODE_ENABLED 1
+#define DEV_MODE_DISABLED 0
+
/* Kernel config file options according to the Chrome OS drive map design. */
typedef struct kconfig_options {
uint32_t version[2]; /* Configuration file version. */
@@ -221,4 +224,44 @@
int AddKernelSignature(KernelImage* image,
const char* kernel_sigining_key_file);
+/* Returns the logical version of a kernel blob which is calculated as
+ * (kernel_key_version << 16 | kernel_version). */
+uint32_t GetLogicalKernelVersion(uint8_t* kernel_blob);
+
+#define BOOT_KERNEL_A_CONTINUE 1
+#define BOOT_KERNEL_B_CONTINUE 2
+#define BOOT_KERNEL_RECOVERY_CONTINUE 3
+
+/* Contains information about the kernel paritition
+ * gleaned from the GPT partition table.
+ *
+ * Based on the Chromium OS Drive Map design document by
+ * rspangler@chromium.org.
+ *
+*/
+typedef struct kernel_entry {
+ uint8_t* kernel_blob; /* Pointer to actual kernel. */
+ uint8_t boot_priority; /* 15 = highest, 1 = lowest, 0 = not bootable. */
+ uint8_t boot_tries_remaining; /* Used when boot_priority = 0. */
+ uint8_t boot_success_flag; /* Set to 1 on successful boot by AU. */
+} kernel_entry;
+
+void PrintKernelEntry(kernel_entry* entry);
+
+/* This function is the driver used by the RW firmware to
+ * determine which copy of the kernel to boot from. It performs
+ * the requisite priority and remaining tries checking for a specific
+ * kernel partition, does rollback index checking, including updating
+ * if required.
+ *
+ * Returns the code path to follow. It is one of:
+ * BOOT_KERNEL_A_CONTINUE Boot from Kenrel A
+ * BOOT_KERNEL_B_CONTINUE Boot from Kernel B
+ * BOOT_KERNEL_RECOVERY_CONTINUE Jump to recovery mode
+ */
+int VerifyKernelDriver_f(uint8_t* firmware_key_blob,
+ kernel_entry* kernelA,
+ kernel_entry* kernelB,
+ int dev_mode);
+
#endif /* VBOOT_REFERENCE_KERNEL_IMAGE_H_ */
diff --git a/tests/Makefile b/tests/Makefile
index d2e70c3..5475bfb 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -16,6 +16,7 @@
firmware_rollback_tests \
firmware_verify_benchmark \
kernel_image_tests \
+ kernel_rollback_tests \
kernel_verify_benchmark \
rsa_padding_test \
rsa_verify_benchmark \
@@ -38,6 +39,10 @@
kernel_image_tests: kernel_image_tests.c rollback_index_mock.c test_common.c
$(CC) $(CFLAGS) $(INCLUDES) $^ -o $@ $(LIBS)
+kernel_rollback_tests: kernel_rollback_tests.c rollback_index_mock.c \
+ test_common.c
+ $(CC) $(CFLAGS) $(INCLUDES) $^ -o $@ $(LIBS)
+
kernel_verify_benchmark: kernel_verify_benchmark.c timer_utils.c \
rollback_index_mock.c test_common.c
$(CC) $(CFLAGS) $(INCLUDES) $^ -o $@ -lrt $(LIBS)
@@ -68,6 +73,7 @@
firmware_rollback_tests \
firmware_verify_benchmark \
kernel_image_tests \
+ kernel_rollback_tests \
kernel_verify_benchmark \
rsa_padding_test \
rsa_verify_benchmark \
diff --git a/tests/firmware_rollback_tests.c b/tests/firmware_rollback_tests.c
index 0df0c3c..e36c003 100644
--- a/tests/firmware_rollback_tests.c
+++ b/tests/firmware_rollback_tests.c
@@ -30,10 +30,10 @@
g_firmware_key_version = 1;
g_firmware_version = 1;
- valid_firmwareA = GenerateRollbackTestImage(1, 1, 0);
- valid_firmwareB = GenerateRollbackTestImage(1, 1, 0);
- corrupt_firmwareA = GenerateRollbackTestImage(1, 1, 1);
- corrupt_firmwareB = GenerateRollbackTestImage(1, 1, 1);
+ valid_firmwareA = GenerateRollbackTestFirmwareBlob(1, 1, 0);
+ valid_firmwareB = GenerateRollbackTestFirmwareBlob(1, 1, 0);
+ corrupt_firmwareA = GenerateRollbackTestFirmwareBlob(1, 1, 1);
+ corrupt_firmwareB = GenerateRollbackTestFirmwareBlob(1, 1, 1);
TEST_EQ(VerifyFirmwareDriver_f(root_key_pub,
valid_firmwareA, valid_firmwareB),
diff --git a/tests/kernel_image_tests.c b/tests/kernel_image_tests.c
index a565011..3d37bb7 100644
--- a/tests/kernel_image_tests.c
+++ b/tests/kernel_image_tests.c
@@ -14,9 +14,6 @@
#include "test_common.h"
#include "utility.h"
-#define DEV_MODE_ENABLED 1
-#define DEV_MODE_DISABLED 0
-
/* Normal Kernel Blob Verification Tests. */
void VerifyKernelTest(uint8_t* kernel_blob, uint8_t* firmware_key_blob) {
TEST_EQ(VerifyKernel(firmware_key_blob, kernel_blob, DEV_MODE_ENABLED),
diff --git a/tests/kernel_rollback_tests.c b/tests/kernel_rollback_tests.c
new file mode 100644
index 0000000..c956300
--- /dev/null
+++ b/tests/kernel_rollback_tests.c
@@ -0,0 +1,149 @@
+/* Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ *
+ * Tests for checking kernel rollback-prevention logic.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "file_keys.h"
+#include "kernel_image.h"
+#include "rsa_utility.h"
+#include "rollback_index.h"
+#include "test_common.h"
+#include "utility.h"
+
+/* Tests that check for correctness of the VerifyFirmwareDriver_f() logic
+ * and rollback prevention. */
+void VerifyKernelDriverTest(void) {
+ uint64_t len;
+ uint8_t* firmware_key_pub = BufferFromFile("testkeys/key_rsa1024.keyb",
+ &len);
+ /* Initialize kernel blobs, including their associated parition
+ * table attributed. */
+ kernel_entry valid_kernelA = {
+ GenerateRollbackTestKernelBlob(1, 1, 0),
+ 15, /* Highest Priority. */
+ 5, /* Enough for tests. */
+ 0 /* Assume we haven't boot off it yet. */
+ };
+ kernel_entry corrupt_kernelA = {
+ GenerateRollbackTestKernelBlob(1, 1, 1),
+ 15, /* Highest Priority. */
+ 5, /* Enough for tests. */
+ 0 /* Assume we haven't boot off it yet. */
+ };
+ kernel_entry valid_kernelB = {
+ GenerateRollbackTestKernelBlob(1, 1, 0),
+ 1, /* Lower Priority. */
+ 5, /* Enough for tests. */
+ 0 /* Assume we haven't boot off it yet. */
+ };
+ kernel_entry corrupt_kernelB = {
+ GenerateRollbackTestKernelBlob(1, 1, 1),
+ 1, /* Lower Priority. */
+ 5, /* Enough for tests. */
+ 0 /* Assume we haven't boot off it yet. */
+ };
+
+ /* Initialize rollback index state. */
+ g_kernel_key_version = 1;
+ g_kernel_version = 1;
+
+ /* Note: This test just checks the rollback prevention mechanism and not
+ * the full blown kernel boot logic. Updates to the kernel attributes
+ * in the paritition table are not tested.
+ */
+ fprintf(stderr, "Kernel A boot priority(15) > Kernel B boot priority(1)\n");
+ TEST_EQ(VerifyKernelDriver_f(firmware_key_pub,
+ &valid_kernelA, &valid_kernelB,
+ DEV_MODE_DISABLED),
+ BOOT_KERNEL_A_CONTINUE,
+ "(Valid Kernel A (current version)\n"
+ " Valid Kernel B (current version) runs A):");
+ TEST_EQ(VerifyKernelDriver_f(firmware_key_pub,
+ &corrupt_kernelA, &valid_kernelB,
+ DEV_MODE_DISABLED),
+ BOOT_KERNEL_B_CONTINUE,
+ "(Corrupt Kernel A (current version)\n"
+ " Valid Kernel B (current version) runs B):");
+ TEST_EQ(VerifyKernelDriver_f(firmware_key_pub,
+ &valid_kernelA, &corrupt_kernelB,
+ DEV_MODE_DISABLED),
+ BOOT_KERNEL_A_CONTINUE,
+ "(Valid Kernel A (current version)\n"
+ " Corrupt Kernel B (current version) runs A):");
+ TEST_EQ(VerifyKernelDriver_f(firmware_key_pub,
+ &corrupt_kernelA, &corrupt_kernelB,
+ DEV_MODE_DISABLED),
+ BOOT_KERNEL_RECOVERY_CONTINUE,
+ "(Corrupt Kernel A (current version)\n"
+ " Corrupt Kernel B (current version) runs Recovery):");
+
+ fprintf(stderr, "\nSwapping boot priorities...\n"
+ "Kernel B boot priority(15) > Kernel A boot priority(1)\n");
+ valid_kernelA.boot_priority = corrupt_kernelA.boot_priority = 1;
+ valid_kernelB.boot_priority = corrupt_kernelB.boot_priority = 15;
+ TEST_EQ(VerifyKernelDriver_f(firmware_key_pub,
+ &valid_kernelA, &valid_kernelB,
+ DEV_MODE_DISABLED),
+ BOOT_KERNEL_B_CONTINUE,
+ "(Valid Kernel A (current version)\n"
+ " Valid Kernel B (current version) runs B):");
+ TEST_EQ(VerifyKernelDriver_f(firmware_key_pub,
+ &corrupt_kernelA, &valid_kernelB,
+ DEV_MODE_DISABLED),
+ BOOT_KERNEL_B_CONTINUE,
+ "(Corrupt Kernel A (current version)\n"
+ " Valid Kernel B (current version) runs B):");
+ TEST_EQ(VerifyKernelDriver_f(firmware_key_pub,
+ &valid_kernelA, &corrupt_kernelB,
+ DEV_MODE_DISABLED),
+ BOOT_KERNEL_A_CONTINUE,
+ "(Valid Kernel A (current version)\n"
+ " Corrupt Kernel B (current version) runs A):");
+ TEST_EQ(VerifyKernelDriver_f(firmware_key_pub,
+ &corrupt_kernelA, &corrupt_kernelB,
+ DEV_MODE_DISABLED),
+ BOOT_KERNEL_RECOVERY_CONTINUE,
+ "(Corrupt Kernel A (current version)\n"
+ " Corrupt Kernel B (current version) runs Recovery):");
+
+ fprintf(stderr, "\nUpdating stored version information. Obsoleting "
+ "exiting kernel images.\n");
+ g_kernel_key_version = 2;
+ g_kernel_version = 2;
+ TEST_EQ(VerifyKernelDriver_f(firmware_key_pub,
+ &valid_kernelA, &valid_kernelB,
+ DEV_MODE_DISABLED),
+ BOOT_KERNEL_RECOVERY_CONTINUE,
+ "(Valid Kernel A (old version)\n"
+ " Valid Kernel B (old version) runs Recovery):");
+
+ fprintf(stderr, "\nGenerating updated Kernel A blob with "
+ "new version.\n");
+ Free(valid_kernelA.kernel_blob);
+ valid_kernelA.kernel_blob = GenerateRollbackTestKernelBlob(3, 3, 0);
+ TEST_EQ(VerifyKernelDriver_f(firmware_key_pub,
+ &valid_kernelA, &valid_kernelB,
+ DEV_MODE_DISABLED),
+ BOOT_KERNEL_A_CONTINUE,
+ "(Valid Kernel A (new version)\n"
+ " Valid Kernel B (old version) runs A):");
+
+ Free(firmware_key_pub);
+ Free(valid_kernelA.kernel_blob);
+ Free(valid_kernelB.kernel_blob);
+ Free(corrupt_kernelA.kernel_blob);
+ Free(corrupt_kernelB.kernel_blob);
+}
+
+int main(int argc, char* argv[]) {
+ int error_code = 0;
+ VerifyKernelDriverTest();
+ if (!gTestSuccess)
+ error_code = 255;
+ return error_code;
+}
diff --git a/tests/rollback_index_mock.c b/tests/rollback_index_mock.c
index 047fb8a..6317214 100644
--- a/tests/rollback_index_mock.c
+++ b/tests/rollback_index_mock.c
@@ -16,7 +16,9 @@
uint16_t g_kernel_version = 0;
void SetupTPM(void) {
+#ifndef NDEBUG
fprintf(stderr, "Rollback Index Library Mock: TPM initialized.\n");
+#endif
}
uint16_t GetStoredVersion(int type) {
@@ -52,10 +54,14 @@
g_kernel_version = version;
break;
}
+#ifndef NDEBUG
fprintf(stderr, "Rollback Index Library Mock: Stored Version written.\n");
+#endif
return 1;
}
void LockStoredVersion(int type) {
+#ifndef NDEBUG
fprintf(stderr, "Rollback Index Library Mock: Version Locked.\n");
+#endif
}
diff --git a/tests/test_common.c b/tests/test_common.c
index 5cc0805..c1d1108 100644
--- a/tests/test_common.c
+++ b/tests/test_common.c
@@ -23,11 +23,11 @@
int TEST_EQ(int result, int expected_result, char* testname) {
if (result == expected_result) {
- fprintf(stderr, "%s Test " COL_GREEN " PASSED\n" COL_STOP, testname);
+ fprintf(stderr, "%s Test " COL_GREEN "PASSED\n" COL_STOP, testname);
return 1;
}
else {
- fprintf(stderr, "%s Test " COL_RED " FAILED\n" COL_STOP, testname);
+ fprintf(stderr, "%s Test " COL_RED "FAILED\n" COL_STOP, testname);
gTestSuccess = 0;
return 0;
}
@@ -102,9 +102,9 @@
return firmware_blob;
}
-uint8_t* GenerateRollbackTestImage(int firmware_key_version,
- int firmware_version,
- int is_corrupt) {
+uint8_t* GenerateRollbackTestFirmwareBlob(int firmware_key_version,
+ int firmware_version,
+ int is_corrupt) {
FirmwareImage* image = NULL;
uint64_t len;
uint8_t* firmware_blob = NULL;
@@ -213,3 +213,33 @@
KernelImageFree(image);
return kernel_blob;
}
+
+uint8_t* GenerateRollbackTestKernelBlob(int kernel_key_version,
+ int kernel_version,
+ int is_corrupt) {
+ KernelImage* image = NULL;
+ uint64_t len;
+ uint8_t* kernel_blob = NULL;
+ uint8_t* kernel_sign_key = NULL;
+ kernel_sign_key = BufferFromFile("testkeys/key_rsa1024.keyb",
+ &len);
+ if (!kernel_sign_key)
+ return NULL;
+ image = GenerateTestKernelImage(0, /* Firmware algo: RSA1024/SHA1 */
+ 0, /* Kernel algo: RSA1024/SHA1 */
+ kernel_sign_key,
+ kernel_key_version,
+ kernel_version,
+ 1, /* kernel length. */
+ "testkeys/key_rsa1024.pem",
+ "testkeys/key_rsa1024.pem");
+ if (!image)
+ return NULL;
+ if (is_corrupt) {
+ /* Invalidate image. */
+ Memset(image->kernel_data, 'X', image->options.kernel_len);
+ }
+ kernel_blob = GetKernelBlob(image, &len);
+ KernelImageFree(image);
+ return kernel_blob;
+}
diff --git a/tests/test_common.h b/tests/test_common.h
index a449bdd..d203d76 100644
--- a/tests/test_common.h
+++ b/tests/test_common.h
@@ -50,11 +50,18 @@
int kernel_len,
const char* firmware_key_file,
const char* kernel_key_file);
+
/* Generates a test firmware image for rollback tests with a given
* [firmware_key_version] and [firmware_version]. If [is_corrupt] is 1,
* then the image has invalid signatures and will fail verification. */
-uint8_t* GenerateRollbackTestImage(int firmware_key_version,
- int firmware_version,
- int is_corrupt);
+uint8_t* GenerateRollbackTestFirmwareBlob(int firmware_key_version,
+ int firmware_version,
+ int is_corrupt);
+/* Generates a test kernel iamge for rollback tests with a given
+ * [kernel_key_version} and [kernel_version]. If [is_corrupt] is 1,
+ * then the image has invalid signatures and will fail verification. */
+uint8_t* GenerateRollbackTestKernelBlob(int kernel_key_version,
+ int kernel_version,
+ int is_corrupt);
#endif /* VBOOT_REFERENCE_TEST_COMMON_H_ */
diff --git a/utils/firmware_image.c b/utils/firmware_image.c
index 13eba6c..a197708 100644
--- a/utils/firmware_image.c
+++ b/utils/firmware_image.c
@@ -680,15 +680,15 @@
/* Stored version may need to be updated but only if FirmwareB
* is successfully verified and has a logical version greater than
* the stored logical version. */
- if (VERIFY_FIRMWARE_SUCCESS == VerifyFirmware(root_key_blob, firmwareB)) {
- if (stored_lversion < firmwareB_lversion) {
- WriteStoredVersion(FIRMWARE_KEY_VERSION,
- (uint16_t) (min_lversion >> 16));
- WriteStoredVersion(FIRMWARE_VERSION,
- (uint16_t) (min_lversion & 0x00FFFF));
- stored_lversion = min_lversion; /* Update stored version as it's used
- * later. */
- }
+ if (stored_lversion < firmwareB_lversion) {
+ if (VERIFY_FIRMWARE_SUCCESS == VerifyFirmware(root_key_blob, firmwareB)) {
+ WriteStoredVersion(FIRMWARE_KEY_VERSION,
+ (uint16_t) (min_lversion >> 16));
+ WriteStoredVersion(FIRMWARE_VERSION,
+ (uint16_t) (min_lversion & 0x00FFFF));
+ stored_lversion = min_lversion; /* Update stored version as it's used
+ * later. */
+ }
}
}
/* Lock Firmware TPM rollback indices from further writes. */
@@ -724,7 +724,7 @@
*/
if (stored_lversion <= firmwareB_lversion &&
(VERIFY_FIRMWARE_SUCCESS == VerifyFirmware(root_key_blob, firmwareB)))
- return BOOT_FIRMWARE_B_CONTINUE;
+ return BOOT_FIRMWARE_B_CONTINUE;
}
/* D'oh: No bootable firmware. */
return BOOT_FIRMWARE_RECOVERY_CONTINUE;
diff --git a/utils/kernel_image.c b/utils/kernel_image.c
index 991374f..e635291 100644
--- a/utils/kernel_image.c
+++ b/utils/kernel_image.c
@@ -15,6 +15,7 @@
#include "file_keys.h"
#include "padding.h"
+#include "rollback_index.h"
#include "rsa_utility.h"
#include "sha_utility.h"
#include "signature_digest.h"
@@ -710,3 +711,147 @@
Free(kernel_signature);
return 1;
}
+
+uint32_t GetLogicalKernelVersion(uint8_t* kernel_blob) {
+ uint8_t* kernel_ptr;
+ uint16_t kernel_key_version;
+ uint16_t kernel_version;
+ uint16_t firmware_sign_algorithm;
+ uint16_t kernel_sign_algorithm;
+ int kernel_key_signature_len;
+ int kernel_sign_key_len;
+ kernel_ptr = kernel_blob + (FIELD_LEN(magic) +
+ FIELD_LEN(header_version) +
+ FIELD_LEN(header_len));
+ Memcpy(&firmware_sign_algorithm, kernel_ptr, sizeof(firmware_sign_algorithm));
+ kernel_ptr += FIELD_LEN(firmware_sign_algorithm);
+ Memcpy(&kernel_sign_algorithm, kernel_ptr, sizeof(kernel_sign_algorithm));
+ kernel_ptr += FIELD_LEN(kernel_sign_algorithm);
+ Memcpy(&kernel_key_version, kernel_ptr, sizeof(kernel_key_version));
+
+ if (firmware_sign_algorithm >= kNumAlgorithms)
+ return 0;
+ if (kernel_sign_algorithm >= kNumAlgorithms)
+ return 0;
+ kernel_key_signature_len = siglen_map[firmware_sign_algorithm];
+ kernel_sign_key_len = RSAProcessedKeySize(kernel_sign_algorithm);
+ kernel_ptr += (FIELD_LEN(kernel_key_version) +
+ kernel_sign_key_len +
+ FIELD_LEN(header_checksum) +
+ kernel_key_signature_len);
+ Memcpy(&kernel_version, kernel_ptr, sizeof(kernel_version));
+ return CombineUint16Pair(kernel_key_version, kernel_version);
+}
+
+void PrintKernelEntry(kernel_entry* entry) {
+ fprintf(stderr, "Boot Priority = %d\n", entry->boot_priority);
+ fprintf(stderr, "Boot Tries Remaining = %d\n", entry->boot_tries_remaining);
+ fprintf(stderr, "Boot Success Flag = %d\n", entry->boot_success_flag);
+}
+
+int VerifyKernelDriver_f(uint8_t* firmware_key_blob,
+ kernel_entry* kernelA,
+ kernel_entry* kernelB,
+ int dev_mode) {
+ int i;
+ /* Contains the logical kernel version (32-bit) which is calculated as
+ * (kernel_key_version << 16 | kernel_version) where
+ * [kernel_key_version], [firmware_version] are both 16-bit.
+ */
+ uint32_t kernelA_lversion, kernelB_lversion;
+ uint32_t min_lversion; /* Minimum of kernel A and kernel B lversion. */
+ uint32_t stored_lversion; /* Stored logical version in the TPM. */
+ kernel_entry* try_kernel[2]; /* Kernel in try order. */
+ int try_kernel_which[2]; /* Which corresponding kernel in the try order */
+ uint32_t try_kernel_lversion[2]; /* Their logical versions. */
+
+ /* [kernel_to_boot] will eventually contain the boot path to follow
+ * and is returned to the caller. Initially, we set it to recovery. If
+ * a valid bootable kernel is found, it will be set to that. */
+ int kernel_to_boot = BOOT_KERNEL_RECOVERY_CONTINUE;
+
+
+ /* The TPM must already have be initialized, so no need to call SetupTPM(). */
+
+ /* We get the key versions by reading directly from the image blobs without
+ * any additional (expensive) sanity checking on the blob since it's faster to
+ * outright reject a kernel with an older kernel key version. A malformed
+ * or corrupted kernel blob will still fail when VerifyKernel() is called
+ * on it.
+ */
+ kernelA_lversion = GetLogicalKernelVersion(kernelA->kernel_blob);
+ kernelB_lversion = GetLogicalKernelVersion(kernelB->kernel_blob);
+ min_lversion = Min(kernelA_lversion, kernelB_lversion);
+ stored_lversion = CombineUint16Pair(GetStoredVersion(KERNEL_KEY_VERSION),
+ GetStoredVersion(KERNEL_VERSION));
+
+ /* TODO(gauravsh): The kernel entries kernelA and kernelB come from the
+ * partition table - verify its signature/checksum before proceeding
+ * further. */
+
+ /* The logic for deciding which kernel to boot from is taken from the
+ * the Chromium OS Drive Map design document.
+ *
+ * We went to consider the kernels in their according to their boot
+ * priority attribute value.
+ */
+
+ if (kernelA->boot_priority >= kernelB->boot_priority) {
+ try_kernel[0] = kernelA;
+ try_kernel_which[0] = BOOT_KERNEL_A_CONTINUE;
+ try_kernel_lversion[0] = kernelA_lversion;
+ try_kernel[1] = kernelB;
+ try_kernel_which[1] = BOOT_KERNEL_B_CONTINUE;
+ try_kernel_lversion[1] = kernelB_lversion;
+ } else {
+ try_kernel[0] = kernelB;
+ try_kernel_which[0] = BOOT_KERNEL_B_CONTINUE;
+ try_kernel_lversion[0] = kernelB_lversion;
+ try_kernel[1] = kernelA;
+ try_kernel_which[1] = BOOT_KERNEL_A_CONTINUE;
+ try_kernel_lversion[1] = kernelA_lversion;
+ }
+
+ /* TODO(gauravsh): Changes to boot_tries_remaining and boot_priority
+ * below should be propagated to partition table. This will be added
+ * once the firmware parition table parsing code is in. */
+ for (i = 0; i < 2; i++) {
+ if ((try_kernel[i]->boot_success_flag ||
+ try_kernel[i]->boot_tries_remaining) &&
+ (VERIFY_KERNEL_SUCCESS == VerifyKernel(firmware_key_blob,
+ try_kernel[i]->kernel_blob,
+ dev_mode))) {
+ if (try_kernel[i]->boot_tries_remaining > 0)
+ try_kernel[i]->boot_tries_remaining--;
+ if (stored_lversion > try_kernel_lversion[i])
+ continue; /* Rollback: I am afraid I can't let you do that Dave. */
+ if (i == 0 && (stored_lversion < try_kernel_lversion[1])) {
+ /* The higher priority kernel is valid and bootable, See if we
+ * need to update the stored version for rollback prevention. */
+ if (VERIFY_KERNEL_SUCCESS == VerifyKernel(firmware_key_blob,
+ try_kernel[1]->kernel_blob,
+ dev_mode)) {
+ WriteStoredVersion(KERNEL_KEY_VERSION,
+ (uint16_t) (min_lversion >> 16));
+ WriteStoredVersion(KERNEL_VERSION,
+ (uint16_t) (min_lversion & 0xFFFF));
+ stored_lversion = min_lversion; /* Update stored version as it's
+ * used later. */
+ }
+ }
+ kernel_to_boot = try_kernel_which[i];
+ break; /* We found a valid kernel. */
+ }
+ try_kernel[i]->boot_priority = 0;
+ } /* for loop. */
+
+ /* Lock Kernel TPM rollback indices from further writes.
+ * TODO(gauravsh): Figure out if these can be combined into one
+ * 32-bit location since we seem to always use them together. This can help
+ * us minimize the number of NVRAM writes/locks (which are limited over flash
+ * memory lifetimes.
+ */
+ LockStoredVersion(KERNEL_KEY_VERSION);
+ LockStoredVersion(KERNEL_VERSION);
+ return kernel_to_boot;
+}