summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRandall Spangler <rspangler@chromium.org>2013-01-30 13:19:19 -0800
committerChromeBot <chrome-bot@google.com>2013-01-31 13:00:41 -0800
commit5d0a2e7b391649b6ba5a5fc4c87097a191e594c8 (patch)
tree64f660eca07b81edafa46a9710e63704782d6b3c
parentcefe12c105a91e6ee9f44bca218bd6e4f89bcb71 (diff)
downloadvboot-5d0a2e7b391649b6ba5a5fc4c87097a191e594c8.tar.gz
Add more vboot_kernel tests
BUG=chromium-os:38139 BRANCH=none TEST=make runtests && FEATURES=test emerge-daisy vboot_reference Change-Id: I69fdbb9d392ba34c8411362aef0f9f0ace284a3c Signed-off-by: Randall Spangler <rspangler@chromium.org> Reviewed-on: https://gerrit.chromium.org/gerrit/42400 Reviewed-by: Bill Richardson <wfrichar@chromium.org>
-rw-r--r--tests/vboot_kernel_tests.c225
1 files changed, 216 insertions, 9 deletions
diff --git a/tests/vboot_kernel_tests.c b/tests/vboot_kernel_tests.c
index 0d491910..7e7beca6 100644
--- a/tests/vboot_kernel_tests.c
+++ b/tests/vboot_kernel_tests.c
@@ -23,11 +23,27 @@
#define LOGCALL(fmt, args...) sprintf(call_log + strlen(call_log), fmt, ##args)
#define TEST_CALLS(expect_log) TEST_STR_EQ(call_log, expect_log, " calls")
+/* Mock kernel partition */
+struct mock_part {
+ uint32_t start;
+ uint32_t size;
+};
+
+/* Partition list; ends with a 0-size partition. */
+#define MOCK_PART_COUNT 8
+static struct mock_part mock_parts[MOCK_PART_COUNT];
+static int mock_part_next;
+
/* Mock data */
static char call_log[4096];
-static int disk_call_to_fail;
-static int disk_calls;
+static uint8_t kernel_buffer[80000];
+static int disk_read_to_fail;
+static int disk_write_to_fail;
static int gpt_init_fail;
+static int key_block_verify_fail; /* 0=ok, 1=sig, 2=hash */
+static int preamble_verify_fail;
+static RSAPublicKey *mock_data_key;
+static int mock_data_key_allocated;
static GoogleBinaryBlockHeader gbb;
static VbExDiskHandle_t handle;
@@ -35,6 +51,8 @@ static VbNvContext vnc;
static uint8_t shared_data[VB_SHARED_DATA_MIN_SIZE];
static VbSharedDataHeader *shared = (VbSharedDataHeader *)shared_data;
static LoadKernelParams lkp;
+static VbKeyBlockHeader kbh;
+static VbKernelPreambleHeader kph;
static void ResetCallLog(void)
{
@@ -48,10 +66,15 @@ static void ResetMocks(void)
{
ResetCallLog();
- disk_call_to_fail = 0;
- disk_calls = 0;
+ disk_read_to_fail = -1;
+ disk_write_to_fail = -1;
gpt_init_fail = 0;
+ key_block_verify_fail = 0;
+ preamble_verify_fail = 0;
+
+ mock_data_key = (RSAPublicKey *)"TestDataKey";
+ mock_data_key_allocated = 0;
memset(&gbb, 0, sizeof(gbb));
gbb.major_version = GBB_MAJOR_VER;
@@ -64,6 +87,7 @@ static void ResetMocks(void)
memset(&shared_data, 0, sizeof(shared_data));
VbSharedDataInit(shared, sizeof(shared_data));
+ shared->kernel_version_tpm = 0x20001;
memset(&lkp, 0, sizeof(lkp));
lkp.nv_context = &vnc;
@@ -71,6 +95,23 @@ static void ResetMocks(void)
lkp.gbb_data = &gbb;
lkp.bytes_per_lba = 512;
lkp.ending_lba = 1023;
+ lkp.kernel_buffer = kernel_buffer;
+ lkp.kernel_buffer_size = sizeof(kernel_buffer);
+
+ memset(&kbh, 0, sizeof(kbh));
+ kbh.data_key.key_version = 2;
+ kbh.key_block_flags = -1;
+ kbh.key_block_size = sizeof(kbh);
+
+ memset(&kph, 0, sizeof(kph));
+ kph.kernel_version = 1;
+ kph.preamble_size = 4096 - kbh.key_block_size;
+ kph.body_signature.data_size = 70000;
+
+ memset(mock_parts, 0, sizeof(mock_parts));
+ mock_parts[0].start = 100;
+ mock_parts[0].size = 150; /* 75 KB */
+ mock_part_next = 0;
}
/* Mocks */
@@ -80,7 +121,7 @@ VbError_t VbExDiskRead(VbExDiskHandle_t handle, uint64_t lba_start,
{
LOGCALL("VbExDiskRead(h, %d, %d)\n", (int)lba_start, (int)lba_count);
- if (++disk_calls == disk_call_to_fail)
+ if ((int)lba_start == disk_read_to_fail)
return VBERROR_SIMULATED;
return VBERROR_SUCCESS;
@@ -91,7 +132,7 @@ VbError_t VbExDiskWrite(VbExDiskHandle_t handle, uint64_t lba_start,
{
LOGCALL("VbExDiskWrite(h, %d, %d)\n", (int)lba_start, (int)lba_count);
- if (++disk_calls == disk_call_to_fail)
+ if ((int)lba_start == disk_write_to_fail)
return VBERROR_SIMULATED;
return VBERROR_SUCCESS;
@@ -102,6 +143,61 @@ int GptInit(GptData *gpt)
return gpt_init_fail;
}
+int GptNextKernelEntry(GptData *gpt, uint64_t *start_sector, uint64_t *size)
+{
+ struct mock_part *p = mock_parts + mock_part_next;
+
+ if (!p->size)
+ return GPT_ERROR_NO_VALID_KERNEL;
+
+ gpt->current_kernel = mock_part_next;
+ *start_sector = p->start;
+ *size = p->size;
+ mock_part_next++;
+ return GPT_SUCCESS;
+}
+
+int KeyBlockVerify(const VbKeyBlockHeader *block, uint64_t size,
+ const VbPublicKey *key, int hash_only) {
+
+ if (hash_only && key_block_verify_fail >= 2)
+ return VBERROR_SIMULATED;
+ else if (!hash_only && key_block_verify_fail >= 1)
+ return VBERROR_SIMULATED;
+
+ /* Use this as an opportunity to override the key block */
+ memcpy((void *)block, &kbh, sizeof(kbh));
+ return VBERROR_SUCCESS;
+}
+
+RSAPublicKey *PublicKeyToRSA(const VbPublicKey *key)
+{
+ TEST_EQ(mock_data_key_allocated, 0, " mock data key not allocated");
+
+ if (mock_data_key)
+ mock_data_key_allocated++;
+
+ return mock_data_key;
+}
+
+void RSAPublicKeyFree(RSAPublicKey* key)
+{
+ TEST_EQ(mock_data_key_allocated, 1, " mock data key allocated");
+ TEST_PTR_EQ(key, mock_data_key, " data key ptr");
+ mock_data_key_allocated--;
+}
+
+int VerifyKernelPreamble(const VbKernelPreambleHeader *preamble,
+ uint64_t size, const RSAPublicKey *key)
+{
+ if (preamble_verify_fail)
+ return VBERROR_SIMULATED;
+
+ /* Use this as an opportunity to override the preamble */
+ memcpy((void *)preamble, &kph, sizeof(kph));
+ return VBERROR_SUCCESS;
+}
+
/**
* Test reading/writing GPT
*/
@@ -156,13 +252,13 @@ static void ReadWriteGptTest(void)
/* Error reading */
ResetMocks();
- disk_call_to_fail = 1;
+ disk_read_to_fail = 1;
TEST_NEQ(AllocAndReadGptData(handle, &g), 0, "AllocAndRead disk fail");
WriteAndFreeGptData(handle, &g);
/* Error writing */
ResetMocks();
- disk_call_to_fail = 5;
+ disk_write_to_fail = 1;
AllocAndReadGptData(handle, &g);
g.modified = -1;
TEST_NEQ(WriteAndFreeGptData(handle, &g), 0, "WriteAndFree disk fail");
@@ -186,7 +282,7 @@ static void InvalidParamsTest(void)
TEST_EQ(LoadKernel(&lkp), VBERROR_INVALID_PARAMETER, "Huge lba size");
ResetMocks();
- disk_call_to_fail = 1;
+ disk_read_to_fail = 1;
TEST_EQ(LoadKernel(&lkp), VBERROR_NO_KERNEL_FOUND, "Can't read disk");
ResetMocks();
@@ -194,10 +290,121 @@ static void InvalidParamsTest(void)
TEST_EQ(LoadKernel(&lkp), VBERROR_NO_KERNEL_FOUND, "Bad GPT");
}
+static void KernelLoopTest(void)
+{
+ /* Fail if no kernels found */
+ ResetMocks();
+ mock_parts[0].size = 0;
+ TEST_EQ(LoadKernel(&lkp), VBERROR_NO_KERNEL_FOUND, "No kernels");
+
+ /* Skip kernels which are too small */
+ ResetMocks();
+ mock_parts[0].size = 10;
+ TEST_EQ(LoadKernel(&lkp), VBERROR_INVALID_KERNEL_FOUND, "Too small");
+
+ ResetMocks();
+ disk_read_to_fail = 100;
+ TEST_EQ(LoadKernel(&lkp), VBERROR_INVALID_KERNEL_FOUND,
+ "Fail reading kernel start");
+
+ ResetMocks();
+ key_block_verify_fail = 1;
+ TEST_EQ(LoadKernel(&lkp), VBERROR_INVALID_KERNEL_FOUND,
+ "Fail key block sig");
+
+ /* In dev mode, fail if hash is bad too */
+ ResetMocks();
+ lkp.boot_flags |= BOOT_FLAG_DEVELOPER;
+ key_block_verify_fail = 2;
+ TEST_EQ(LoadKernel(&lkp), VBERROR_INVALID_KERNEL_FOUND,
+ "Fail key block dev hash");
+
+ /* In dev mode and requiring signed kernel, fail if sig is bad */
+ ResetMocks();
+ lkp.boot_flags |= BOOT_FLAG_DEVELOPER;
+ VbNvSet(&vnc, VBNV_DEV_BOOT_SIGNED_ONLY, 1);
+ VbNvTeardown(&vnc);
+ key_block_verify_fail = 1;
+ TEST_EQ(LoadKernel(&lkp), VBERROR_INVALID_KERNEL_FOUND,
+ "Fail key block dev sig");
+
+ /* Check key block flag mismatches */
+ ResetMocks();
+ kbh.key_block_flags =
+ KEY_BLOCK_FLAG_RECOVERY_0 | KEY_BLOCK_FLAG_DEVELOPER_1;
+ TEST_EQ(LoadKernel(&lkp), VBERROR_INVALID_KERNEL_FOUND,
+ "Key block dev flag mismatch");
+
+ ResetMocks();
+ kbh.key_block_flags =
+ KEY_BLOCK_FLAG_RECOVERY_1 | KEY_BLOCK_FLAG_DEVELOPER_0;
+ TEST_EQ(LoadKernel(&lkp), VBERROR_INVALID_KERNEL_FOUND,
+ "Key block rec flag mismatch");
+
+ ResetMocks();
+ lkp.boot_flags |= BOOT_FLAG_RECOVERY;
+ kbh.key_block_flags =
+ KEY_BLOCK_FLAG_RECOVERY_1 | KEY_BLOCK_FLAG_DEVELOPER_1;
+ TEST_EQ(LoadKernel(&lkp), VBERROR_INVALID_KERNEL_FOUND,
+ "Key block recdev flag mismatch");
+
+ ResetMocks();
+ lkp.boot_flags |= BOOT_FLAG_RECOVERY | BOOT_FLAG_DEVELOPER;
+ kbh.key_block_flags =
+ KEY_BLOCK_FLAG_RECOVERY_1 | KEY_BLOCK_FLAG_DEVELOPER_0;
+ TEST_EQ(LoadKernel(&lkp), VBERROR_INVALID_KERNEL_FOUND,
+ "Key block rec!dev flag mismatch");
+
+ ResetMocks();
+ kbh.data_key.key_version = 1;
+ TEST_EQ(LoadKernel(&lkp), VBERROR_INVALID_KERNEL_FOUND,
+ "Key block kernel key rollback");
+
+ ResetMocks();
+ kbh.data_key.key_version = 0x10000;
+ TEST_EQ(LoadKernel(&lkp), VBERROR_INVALID_KERNEL_FOUND,
+ "Key block kernel key version too big");
+
+ /* TODO: key version ignored in recovery mode */
+ /* TODO: key block validity ignored in dev mode */
+
+ ResetMocks();
+ mock_data_key = NULL;
+ TEST_EQ(LoadKernel(&lkp), VBERROR_INVALID_KERNEL_FOUND, "Bad data key");
+
+ ResetMocks();
+ preamble_verify_fail = 1;
+ TEST_EQ(LoadKernel(&lkp), VBERROR_INVALID_KERNEL_FOUND, "Bad preamble");
+
+ ResetMocks();
+ kph.kernel_version = 0;
+ TEST_EQ(LoadKernel(&lkp), VBERROR_INVALID_KERNEL_FOUND,
+ "Kernel version rollback");
+
+ /* TODO: kernel version ignored in recovery and dev modes */
+
+ ResetMocks();
+ kph.preamble_size |= 0x07;
+ TEST_EQ(LoadKernel(&lkp), VBERROR_INVALID_KERNEL_FOUND,
+ "Kernel body offset");
+
+ ResetMocks();
+ lkp.kernel_buffer_size = 8192;
+ TEST_EQ(LoadKernel(&lkp), VBERROR_INVALID_KERNEL_FOUND,
+ "Kernel too big for buffer");
+
+ ResetMocks();
+ mock_parts[0].size = 130;
+ TEST_EQ(LoadKernel(&lkp), VBERROR_INVALID_KERNEL_FOUND,
+ "Kernel too big for partition");
+
+}
+
int main(void)
{
ReadWriteGptTest();
InvalidParamsTest();
+ KernelLoopTest();
return gTestSuccess ? 0 : 255;
}