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/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_ */