| /* Copyright (c) 2013 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 vboot_kernel.c | |
| */ | |
| #include "2api.h" | |
| #include "2common.h" | |
| #include "2misc.h" | |
| #include "2nvstorage.h" | |
| #include "2secdata.h" | |
| #include "2secdata_struct.h" | |
| #include "cgptlib.h" | |
| #include "cgptlib_internal.h" | |
| #include "common/boot_mode.h" | |
| #include "common/tests.h" | |
| #include "gpt.h" | |
| #include "vboot_api.h" | |
| /* 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 uint8_t kernel_buffer[80000]; | |
| static int disk_read_to_fail; | |
| static int gpt_init_fail; | |
| static int keyblock_verify_fail; /* 0=ok, 1=sig, 2=hash */ | |
| static int preamble_verify_fail; | |
| static int verify_data_fail; | |
| static int unpack_key_fail; | |
| static int gpt_flag_external; | |
| static struct vb2_gbb_header gbb; | |
| static struct vb2_kernel_params lkp; | |
| static struct vb2_disk_info disk_info; | |
| static struct vb2_keyblock kbh; | |
| static struct vb2_kernel_preamble kph; | |
| static struct vb2_secdata_fwmp *fwmp; | |
| static uint8_t mock_digest[VB2_SHA256_DIGEST_SIZE] = {12, 34, 56, 78}; | |
| static uint8_t workbuf[VB2_KERNEL_WORKBUF_RECOMMENDED_SIZE] | |
| __attribute__((aligned(VB2_WORKBUF_ALIGN))); | |
| static struct vb2_context *ctx; | |
| static struct vb2_shared_data *sd; | |
| static struct vb2_packed_key mock_key; | |
| /** | |
| * Reset mock data (for use before each test) | |
| */ | |
| static void ResetMocks(void) | |
| { | |
| disk_read_to_fail = -1; | |
| gpt_init_fail = 0; | |
| keyblock_verify_fail = 0; | |
| preamble_verify_fail = 0; | |
| verify_data_fail = 0; | |
| unpack_key_fail = 0; | |
| gpt_flag_external = 0; | |
| memset(&gbb, 0, sizeof(gbb)); | |
| gbb.major_version = VB2_GBB_MAJOR_VER; | |
| gbb.minor_version = VB2_GBB_MINOR_VER; | |
| gbb.flags = 0; | |
| memset(&lkp, 0, sizeof(lkp)); | |
| lkp.kernel_buffer = kernel_buffer; | |
| lkp.kernel_buffer_size = sizeof(kernel_buffer); | |
| memset(&disk_info, 0, sizeof(disk_info)); | |
| disk_info.bytes_per_lba = 512; | |
| disk_info.streaming_lba_count = 1024; | |
| disk_info.lba_count = 1024; | |
| disk_info.handle = (vb2ex_disk_handle_t)1; | |
| memset(&kbh, 0, sizeof(kbh)); | |
| kbh.data_key.key_version = 2; | |
| kbh.keyblock_flags = -1; | |
| kbh.keyblock_size = sizeof(kbh); | |
| memset(&kph, 0, sizeof(kph)); | |
| kph.kernel_version = 1; | |
| kph.preamble_size = 4096 - kbh.keyblock_size; | |
| kph.body_signature.data_size = 70144; | |
| kph.bootloader_address = 0xbeadd008; | |
| kph.bootloader_size = 0x1234; | |
| memset(mock_parts, 0, sizeof(mock_parts)); | |
| mock_parts[0].start = 100; | |
| mock_parts[0].size = 150; /* 75 KB */ | |
| mock_part_next = 0; | |
| memset(&mock_key, 0, sizeof(mock_key)); | |
| TEST_SUCC(vb2api_init(workbuf, sizeof(workbuf), &ctx), | |
| "vb2api_init failed"); | |
| vb2_nv_init(ctx); | |
| sd = vb2_get_sd(ctx); | |
| sd->kernel_version_secdata = 0x20001; | |
| /* CRC will be invalid after here, but nobody's checking */ | |
| sd->status |= VB2_SD_STATUS_SECDATA_FWMP_INIT; | |
| fwmp = (struct vb2_secdata_fwmp *)ctx->secdata_fwmp; | |
| memcpy(&fwmp->dev_key_hash, mock_digest, sizeof(fwmp->dev_key_hash)); | |
| SET_BOOT_MODE(ctx, VB2_BOOT_MODE_NORMAL); | |
| // TODO: more workbuf fields - flags, secdata_firmware | |
| vb2api_secdata_kernel_create(ctx); | |
| vb2_secdata_kernel_init(ctx); | |
| vb2_secdata_kernel_set(ctx, VB2_SECDATA_KERNEL_FLAGS, | |
| VB2_SECDATA_KERNEL_FLAG_HWCRYPTO_ALLOWED); | |
| } | |
| /* Mocks */ | |
| struct vb2_gbb_header *vb2_get_gbb(struct vb2_context *c) | |
| { | |
| return &gbb; | |
| } | |
| vb2_error_t vb2ex_read_resource(struct vb2_context *c, | |
| enum vb2_resource_index index, uint32_t offset, | |
| void *buf, uint32_t size) | |
| { | |
| memset(buf, 0, size); | |
| return VB2_SUCCESS; | |
| } | |
| vb2_error_t vb2_gbb_read_root_key(struct vb2_context *c, | |
| struct vb2_packed_key **keyp, uint32_t *size, | |
| struct vb2_workbuf *wb) | |
| { | |
| *keyp = &mock_key; | |
| return VB2_SUCCESS; | |
| } | |
| vb2_error_t vb2_gbb_read_recovery_key(struct vb2_context *c, | |
| struct vb2_packed_key **keyp, | |
| uint32_t *size, struct vb2_workbuf *wb) | |
| { | |
| *keyp = &mock_key; | |
| return VB2_SUCCESS; | |
| } | |
| vb2_error_t VbExDiskRead(vb2ex_disk_handle_t h, uint64_t lba_start, | |
| uint64_t lba_count, void *buffer) | |
| { | |
| if ((int)lba_start == disk_read_to_fail) | |
| return VB2_ERROR_MOCK; | |
| return VB2_SUCCESS; | |
| } | |
| int AllocAndReadGptData(vb2ex_disk_handle_t disk_handle, GptData *gptdata) | |
| { | |
| return GPT_SUCCESS; | |
| } | |
| 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; | |
| if (gpt->flags & GPT_FLAG_EXTERNAL) | |
| gpt_flag_external++; | |
| gpt->current_kernel = mock_part_next; | |
| *start_sector = p->start; | |
| *size = p->size; | |
| mock_part_next++; | |
| return GPT_SUCCESS; | |
| } | |
| int GptUpdateKernelEntry(GptData *gpt, uint32_t update_type) | |
| { | |
| return GPT_SUCCESS; | |
| } | |
| int WriteAndFreeGptData(vb2ex_disk_handle_t disk_handle, GptData *gptdata) | |
| { | |
| return GPT_SUCCESS; | |
| } | |
| void GetCurrentKernelUniqueGuid(GptData *gpt, void *dest) | |
| { | |
| static char fake_guid[] = "FakeGuid"; | |
| memcpy(dest, fake_guid, sizeof(fake_guid)); | |
| } | |
| vb2_error_t vb2_unpack_key_buffer(struct vb2_public_key *key, | |
| const uint8_t *buf, uint32_t size) | |
| { | |
| if (--unpack_key_fail == 0) | |
| return VB2_ERROR_MOCK; | |
| return VB2_SUCCESS; | |
| } | |
| vb2_error_t vb2_verify_keyblock(struct vb2_keyblock *block, uint32_t size, | |
| const struct vb2_public_key *key, | |
| const struct vb2_workbuf *wb) | |
| { | |
| if (keyblock_verify_fail >= 1) | |
| return VB2_ERROR_MOCK; | |
| /* Use this as an opportunity to override the keyblock */ | |
| memcpy((void *)block, &kbh, sizeof(kbh)); | |
| return VB2_SUCCESS; | |
| } | |
| vb2_error_t vb2_verify_keyblock_hash(const struct vb2_keyblock *block, | |
| uint32_t size, | |
| const struct vb2_workbuf *wb) | |
| { | |
| if (keyblock_verify_fail >= 2) | |
| return VB2_ERROR_MOCK; | |
| /* Use this as an opportunity to override the keyblock */ | |
| memcpy((void *)block, &kbh, sizeof(kbh)); | |
| return VB2_SUCCESS; | |
| } | |
| vb2_error_t vb2_verify_kernel_preamble(struct vb2_kernel_preamble *preamble, | |
| uint32_t size, const struct vb2_public_key *key, | |
| const struct vb2_workbuf *wb) | |
| { | |
| if (preamble_verify_fail) | |
| return VB2_ERROR_MOCK; | |
| /* Use this as an opportunity to override the preamble */ | |
| memcpy((void *)preamble, &kph, sizeof(kph)); | |
| return VB2_SUCCESS; | |
| } | |
| vb2_error_t vb2_verify_data(const uint8_t *data, uint32_t size, | |
| struct vb2_signature *sig, | |
| const struct vb2_public_key *key, | |
| const struct vb2_workbuf *wb) | |
| { | |
| if (verify_data_fail) | |
| return VB2_ERROR_MOCK; | |
| return VB2_SUCCESS; | |
| } | |
| vb2_error_t vb2_digest_buffer(const uint8_t *buf, uint32_t size, | |
| enum vb2_hash_algorithm hash_alg, uint8_t *digest, | |
| uint32_t digest_size) | |
| { | |
| memcpy(digest, mock_digest, sizeof(mock_digest)); | |
| return VB2_SUCCESS; | |
| } | |
| /* Make sure nothing tested here ever calls this directly. */ | |
| void vb2api_fail(struct vb2_context *c, uint8_t reason, uint8_t subcode) | |
| { | |
| TEST_TRUE(0, " called vb2api_fail()"); | |
| } | |
| static void test_load_kernel(vb2_error_t expect_retval, const char *test_name) | |
| { | |
| TEST_EQ(vb2api_load_kernel(ctx, &lkp, &disk_info), expect_retval, | |
| test_name); | |
| if (expect_retval == VB2_SUCCESS) | |
| TEST_PTR_EQ(lkp.disk_handle, disk_info.handle, | |
| " fill disk_handle when success"); | |
| } | |
| /** | |
| * Trivial invalid calls to vb2api_load_kernel() | |
| */ | |
| static void invalid_params_tests(void) | |
| { | |
| ResetMocks(); | |
| gpt_init_fail = 1; | |
| test_load_kernel(VB2_ERROR_LK_NO_KERNEL_FOUND, "Bad GPT"); | |
| /* This causes the stream open call to fail */ | |
| ResetMocks(); | |
| disk_info.handle = NULL; | |
| test_load_kernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND, "Bad disk handle"); | |
| } | |
| static void load_kernel_tests(void) | |
| { | |
| ResetMocks(); | |
| test_load_kernel(VB2_SUCCESS, "First kernel good"); | |
| TEST_EQ(lkp.partition_number, 1, " part num"); | |
| TEST_EQ(lkp.bootloader_address, 0xbeadd008, " bootloader addr"); | |
| TEST_EQ(lkp.bootloader_size, 0x1234, " bootloader size"); | |
| TEST_STR_EQ((char *)lkp.partition_guid, "FakeGuid", " guid"); | |
| TEST_EQ(gpt_flag_external, 0, "GPT was internal"); | |
| TEST_NEQ(sd->flags & VB2_SD_FLAG_KERNEL_SIGNED, 0, " use signature"); | |
| ResetMocks(); | |
| mock_parts[1].start = 300; | |
| mock_parts[1].size = 150; | |
| test_load_kernel(VB2_SUCCESS, "Two good kernels"); | |
| TEST_EQ(lkp.partition_number, 1, " part num"); | |
| TEST_EQ(mock_part_next, 1, " didn't read second one"); | |
| /* Fail if no kernels found */ | |
| ResetMocks(); | |
| mock_parts[0].size = 0; | |
| test_load_kernel(VB2_ERROR_LK_NO_KERNEL_FOUND, "No kernels"); | |
| /* Skip kernels which are too small */ | |
| ResetMocks(); | |
| mock_parts[0].size = 10; | |
| test_load_kernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND, "Too small"); | |
| ResetMocks(); | |
| disk_read_to_fail = 100; | |
| test_load_kernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND, | |
| "Fail reading kernel start"); | |
| ResetMocks(); | |
| keyblock_verify_fail = 1; | |
| test_load_kernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND, | |
| "Fail key block sig"); | |
| /* In dev mode, fail if hash is bad too */ | |
| ResetMocks(); | |
| SET_BOOT_MODE(ctx, VB2_BOOT_MODE_DEVELOPER); | |
| keyblock_verify_fail = 2; | |
| test_load_kernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND, | |
| "Fail key block dev hash"); | |
| /* But just bad sig is ok */ | |
| ResetMocks(); | |
| SET_BOOT_MODE(ctx, VB2_BOOT_MODE_DEVELOPER); | |
| keyblock_verify_fail = 1; | |
| test_load_kernel(VB2_SUCCESS, "Succeed keyblock dev sig"); | |
| TEST_EQ(sd->flags & VB2_SD_FLAG_KERNEL_SIGNED, 0, " use hash"); | |
| /* In dev mode and requiring signed kernel, fail if sig is bad */ | |
| ResetMocks(); | |
| SET_BOOT_MODE(ctx, VB2_BOOT_MODE_DEVELOPER); | |
| vb2_nv_set(ctx, VB2_NV_DEV_BOOT_SIGNED_ONLY, 1); | |
| keyblock_verify_fail = 1; | |
| test_load_kernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND, | |
| "Fail key block dev sig"); | |
| ResetMocks(); | |
| SET_BOOT_MODE(ctx, VB2_BOOT_MODE_DEVELOPER); | |
| fwmp->flags |= VB2_SECDATA_FWMP_DEV_ENABLE_OFFICIAL_ONLY; | |
| keyblock_verify_fail = 1; | |
| test_load_kernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND, | |
| "Fail key block dev sig fwmp"); | |
| /* Check keyblock flags */ | |
| ResetMocks(); | |
| kbh.keyblock_flags = VB2_KEYBLOCK_FLAG_RECOVERY_0 | |
| | VB2_KEYBLOCK_FLAG_DEVELOPER_1 | |
| | VB2_KEYBLOCK_FLAG_MINIOS_0; | |
| test_load_kernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND, | |
| "Keyblock dev flag mismatch"); | |
| ResetMocks(); | |
| kbh.keyblock_flags = VB2_KEYBLOCK_FLAG_RECOVERY_1 | |
| | VB2_KEYBLOCK_FLAG_DEVELOPER_0 | |
| | VB2_KEYBLOCK_FLAG_MINIOS_0; | |
| test_load_kernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND, | |
| "Keyblock rec flag mismatch"); | |
| ResetMocks(); | |
| kbh.keyblock_flags = VB2_KEYBLOCK_FLAG_RECOVERY_0 | |
| | VB2_KEYBLOCK_FLAG_DEVELOPER_0 | |
| | VB2_KEYBLOCK_FLAG_MINIOS_1; | |
| test_load_kernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND, | |
| "Keyblock minios flag mismatch"); | |
| ResetMocks(); | |
| SET_BOOT_MODE(ctx, VB2_BOOT_MODE_MANUAL_RECOVERY, | |
| VB2_RECOVERY_RO_MANUAL); | |
| kbh.keyblock_flags = VB2_KEYBLOCK_FLAG_RECOVERY_1 | |
| | VB2_KEYBLOCK_FLAG_DEVELOPER_1 | |
| | VB2_KEYBLOCK_FLAG_MINIOS_0; | |
| test_load_kernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND, | |
| "Keyblock recdev flag mismatch"); | |
| ResetMocks(); | |
| SET_BOOT_MODE(ctx, VB2_BOOT_MODE_MANUAL_RECOVERY, | |
| VB2_RECOVERY_RO_MANUAL); | |
| kbh.keyblock_flags = VB2_KEYBLOCK_FLAG_RECOVERY_1 | |
| | VB2_KEYBLOCK_FLAG_DEVELOPER_0 | |
| | VB2_KEYBLOCK_FLAG_MINIOS_0; | |
| test_load_kernel(VB2_SUCCESS, "Keyblock rec flag okay"); | |
| ResetMocks(); | |
| SET_BOOT_MODE(ctx, VB2_BOOT_MODE_MANUAL_RECOVERY, | |
| VB2_RECOVERY_RO_MANUAL); | |
| ctx->flags |= VB2_CONTEXT_DEVELOPER_MODE; | |
| kbh.keyblock_flags = VB2_KEYBLOCK_FLAG_RECOVERY_1 | |
| | VB2_KEYBLOCK_FLAG_DEVELOPER_0 | |
| | VB2_KEYBLOCK_FLAG_MINIOS_0; | |
| test_load_kernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND, | |
| "Keyblock rec!dev flag mismatch"); | |
| ResetMocks(); | |
| SET_BOOT_MODE(ctx, VB2_BOOT_MODE_MANUAL_RECOVERY, | |
| VB2_RECOVERY_RO_MANUAL); | |
| ctx->flags |= VB2_CONTEXT_DEVELOPER_MODE; | |
| kbh.keyblock_flags = VB2_KEYBLOCK_FLAG_RECOVERY_1 | |
| | VB2_KEYBLOCK_FLAG_DEVELOPER_1 | |
| | VB2_KEYBLOCK_FLAG_MINIOS_0; | |
| test_load_kernel(VB2_SUCCESS, "Keyblock recdev flag okay"); | |
| /* Check keyblock flags (dev mode + signed kernel required) */ | |
| ResetMocks(); | |
| SET_BOOT_MODE(ctx, VB2_BOOT_MODE_DEVELOPER); | |
| vb2_nv_set(ctx, VB2_NV_DEV_BOOT_SIGNED_ONLY, 1); | |
| kbh.keyblock_flags = VB2_KEYBLOCK_FLAG_RECOVERY_1 | |
| | VB2_KEYBLOCK_FLAG_DEVELOPER_0 | |
| | VB2_KEYBLOCK_FLAG_MINIOS_0; | |
| test_load_kernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND, | |
| "Keyblock dev flag mismatch (signed kernel required)"); | |
| ResetMocks(); | |
| SET_BOOT_MODE(ctx, VB2_BOOT_MODE_DEVELOPER); | |
| fwmp->flags |= VB2_SECDATA_FWMP_DEV_ENABLE_OFFICIAL_ONLY; | |
| kbh.keyblock_flags = VB2_KEYBLOCK_FLAG_RECOVERY_1 | |
| | VB2_KEYBLOCK_FLAG_DEVELOPER_0 | |
| | VB2_KEYBLOCK_FLAG_MINIOS_0; | |
| test_load_kernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND, | |
| "Keyblock dev flag mismatch (signed kernel required)"); | |
| ResetMocks(); | |
| SET_BOOT_MODE(ctx, VB2_BOOT_MODE_DEVELOPER); | |
| fwmp->flags |= VB2_SECDATA_FWMP_DEV_ENABLE_OFFICIAL_ONLY; | |
| kbh.keyblock_flags = VB2_KEYBLOCK_FLAG_RECOVERY_0 | |
| | VB2_KEYBLOCK_FLAG_DEVELOPER_0 | |
| | VB2_KEYBLOCK_FLAG_MINIOS_1; | |
| test_load_kernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND, | |
| "Keyblock dev flag mismatch (signed kernel required)"); | |
| ResetMocks(); | |
| SET_BOOT_MODE(ctx, VB2_BOOT_MODE_DEVELOPER); | |
| vb2_nv_set(ctx, VB2_NV_DEV_BOOT_SIGNED_ONLY, 1); | |
| kbh.keyblock_flags = VB2_KEYBLOCK_FLAG_RECOVERY_0 | |
| | VB2_KEYBLOCK_FLAG_DEVELOPER_1 | |
| | VB2_KEYBLOCK_FLAG_MINIOS_0; | |
| test_load_kernel(VB2_SUCCESS, | |
| "Keyblock dev flag okay (signed kernel required)"); | |
| /* Check kernel key version */ | |
| ResetMocks(); | |
| kbh.data_key.key_version = 1; | |
| test_load_kernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND, | |
| "Keyblock kernel key rollback"); | |
| ResetMocks(); | |
| kbh.data_key.key_version = 0x10000; | |
| test_load_kernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND, | |
| "Keyblock kernel key version too big"); | |
| ResetMocks(); | |
| kbh.data_key.key_version = 3; | |
| test_load_kernel(VB2_SUCCESS, "Keyblock version roll forward"); | |
| TEST_EQ(sd->kernel_version, 0x30001, " SD version"); | |
| ResetMocks(); | |
| kbh.data_key.key_version = 3; | |
| mock_parts[1].start = 300; | |
| mock_parts[1].size = 150; | |
| test_load_kernel(VB2_SUCCESS, "Two kernels roll forward"); | |
| TEST_EQ(mock_part_next, 2, " read both"); | |
| TEST_EQ(sd->kernel_version, 0x30001, " SD version"); | |
| ResetMocks(); | |
| kbh.data_key.key_version = 1; | |
| SET_BOOT_MODE(ctx, VB2_BOOT_MODE_DEVELOPER); | |
| test_load_kernel(VB2_SUCCESS, "Key version ignored in dev mode"); | |
| ResetMocks(); | |
| kbh.data_key.key_version = 1; | |
| SET_BOOT_MODE(ctx, VB2_BOOT_MODE_MANUAL_RECOVERY, | |
| VB2_RECOVERY_RO_MANUAL); | |
| test_load_kernel(VB2_SUCCESS, "Key version ignored in rec mode"); | |
| ResetMocks(); | |
| unpack_key_fail = 2; | |
| test_load_kernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND, "Bad data key"); | |
| ResetMocks(); | |
| preamble_verify_fail = 1; | |
| test_load_kernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND, "Bad preamble"); | |
| ResetMocks(); | |
| kph.kernel_version = 0; | |
| test_load_kernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND, | |
| "Kernel version rollback"); | |
| ResetMocks(); | |
| kph.kernel_version = 0; | |
| SET_BOOT_MODE(ctx, VB2_BOOT_MODE_DEVELOPER); | |
| test_load_kernel(VB2_SUCCESS, "Kernel version ignored in dev mode"); | |
| ResetMocks(); | |
| kph.kernel_version = 0; | |
| SET_BOOT_MODE(ctx, VB2_BOOT_MODE_MANUAL_RECOVERY, | |
| VB2_RECOVERY_RO_MANUAL); | |
| test_load_kernel(VB2_SUCCESS, "Kernel version ignored in rec mode"); | |
| /* Check kernel version (dev mode + signed kernel required) */ | |
| ResetMocks(); | |
| kbh.data_key.key_version = 0; | |
| SET_BOOT_MODE(ctx, VB2_BOOT_MODE_DEVELOPER); | |
| vb2_nv_set(ctx, VB2_NV_DEV_BOOT_SIGNED_ONLY, 1); | |
| test_load_kernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND, | |
| "Keyblock key version checked in dev mode " | |
| "(signed kernel required)"); | |
| ResetMocks(); | |
| kbh.data_key.key_version = 0; | |
| SET_BOOT_MODE(ctx, VB2_BOOT_MODE_DEVELOPER); | |
| fwmp->flags |= VB2_SECDATA_FWMP_DEV_ENABLE_OFFICIAL_ONLY; | |
| test_load_kernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND, | |
| "Keyblock key version checked in dev mode " | |
| "(signed kernel required)"); | |
| /* Check developer key hash - bad */ | |
| ResetMocks(); | |
| SET_BOOT_MODE(ctx, VB2_BOOT_MODE_DEVELOPER); | |
| fwmp->flags |= VB2_SECDATA_FWMP_DEV_USE_KEY_HASH; | |
| fwmp->dev_key_hash[0]++; | |
| test_load_kernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND, | |
| "Fail keyblock dev fwmp hash"); | |
| /* Check developer key hash - bad (recovery mode) */ | |
| ResetMocks(); | |
| SET_BOOT_MODE(ctx, VB2_BOOT_MODE_MANUAL_RECOVERY, | |
| VB2_RECOVERY_RO_MANUAL); | |
| fwmp->flags |= VB2_SECDATA_FWMP_DEV_USE_KEY_HASH; | |
| fwmp->dev_key_hash[0]++; | |
| test_load_kernel(VB2_SUCCESS, | |
| "Bad keyblock dev fwmp hash ignored in rec mode"); | |
| /* Check developer key hash - good */ | |
| ResetMocks(); | |
| SET_BOOT_MODE(ctx, VB2_BOOT_MODE_DEVELOPER); | |
| fwmp->flags |= VB2_SECDATA_FWMP_DEV_USE_KEY_HASH; | |
| test_load_kernel(VB2_SUCCESS, "Good keyblock dev fwmp hash"); | |
| ResetMocks(); | |
| kph.preamble_size |= 0x07; | |
| test_load_kernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND, | |
| "Kernel body offset"); | |
| ResetMocks(); | |
| kph.preamble_size += 65536; | |
| test_load_kernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND, | |
| "Kernel body offset huge"); | |
| /* Check getting kernel load address from header */ | |
| ResetMocks(); | |
| kph.body_load_address = (size_t)kernel_buffer; | |
| lkp.kernel_buffer = NULL; | |
| test_load_kernel(VB2_SUCCESS, "Get load address from preamble"); | |
| TEST_PTR_EQ(lkp.kernel_buffer, kernel_buffer, " address"); | |
| /* Size is rounded up to nearest sector */ | |
| TEST_EQ(lkp.kernel_buffer_size, 70144, " size"); | |
| ResetMocks(); | |
| lkp.kernel_buffer_size = 8192; | |
| test_load_kernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND, | |
| "Kernel too big for buffer"); | |
| ResetMocks(); | |
| mock_parts[0].size = 130; | |
| test_load_kernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND, | |
| "Kernel too big for partition"); | |
| ResetMocks(); | |
| kph.body_signature.data_size = 8192; | |
| test_load_kernel(VB2_SUCCESS, "Kernel tiny"); | |
| ResetMocks(); | |
| disk_read_to_fail = 228; | |
| test_load_kernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND, | |
| "Fail reading kernel data"); | |
| ResetMocks(); | |
| verify_data_fail = 1; | |
| test_load_kernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND, "Bad data"); | |
| /* Check that EXTERNAL_GPT flag makes it down */ | |
| ResetMocks(); | |
| disk_info.flags |= VB2_DISK_FLAG_EXTERNAL_GPT; | |
| test_load_kernel(VB2_SUCCESS, "Succeed external GPT"); | |
| TEST_EQ(gpt_flag_external, 1, "GPT was external"); | |
| /* Check recovery from unreadble primary GPT */ | |
| ResetMocks(); | |
| disk_read_to_fail = 1; | |
| test_load_kernel(VB2_SUCCESS, "Can't read disk"); | |
| } | |
| int main(void) | |
| { | |
| invalid_params_tests(); | |
| load_kernel_tests(); | |
| return gTestSuccess ? 0 : 255; | |
| } |