/* 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_api_kernel.c */ #include #include #include #include #include "2sysincludes.h" #include "2api.h" #include "2common.h" #include "2misc.h" #include "2nvstorage.h" #include "2rsa.h" #include "2struct.h" #include "host_common.h" #include "load_kernel_fw.h" #include "test_common.h" #include "vb2_common.h" #include "vboot_api.h" #include "vboot_common.h" #include "vboot_kernel.h" #include "vboot_struct.h" /* Mock data */ static uint8_t workbuf[VB2_KERNEL_WORKBUF_RECOMMENDED_SIZE]; static struct vb2_context ctx; static struct vb2_context ctx_nvram_backend; static VbSelectAndLoadKernelParams kparams; static uint8_t shared_data[VB_SHARED_DATA_MIN_SIZE]; static VbSharedDataHeader *shared = (VbSharedDataHeader *)shared_data; static struct vb2_gbb_header gbb; static struct vb2_packed_key mock_key; static uint8_t kernel_buffer[80000]; static int key_block_verify_fail; /* 0=ok, 1=sig, 2=hash */ static int preamble_verify_fail; static int verify_data_fail; static int unpack_key_fail; static VbKeyBlockHeader kbh; static VbKernelPreambleHeader kph; static int hash_only_check; /** * Reset mock data (for use before each test) */ static void ResetMocks(void) { memset(&kparams, 0, sizeof(kparams)); memset(&gbb, 0, sizeof(gbb)); gbb.major_version = VB2_GBB_MAJOR_VER; gbb.minor_version = VB2_GBB_MINOR_VER; gbb.flags = 0; gbb.rootkey_offset = sizeof(gbb); gbb.rootkey_size = sizeof(struct vb2_packed_key); memset(&mock_key, 0, sizeof(mock_key)); /* ctx.workbuf will be initialized by VbVerifyMemoryBootImage. */ memset(&ctx, 0, sizeof(ctx)); ctx.workbuf = workbuf; ctx.workbuf_size = sizeof(workbuf); vb2_init_context(&ctx); /* * ctx_nvram_backend is only used as an NVRAM backend (see * VbExNvStorageRead and VbExNvStorageWrite), and with * vb2_set_nvdata and nv2_get_nvdata to manually read and tweak * contents. No other initialization is needed. */ memset(&ctx_nvram_backend, 0, sizeof(ctx_nvram_backend)); vb2_nv_init(&ctx_nvram_backend); memset(&shared_data, 0, sizeof(shared_data)); VbSharedDataInit(shared, sizeof(shared_data)); key_block_verify_fail = 0; preamble_verify_fail = 0; verify_data_fail = 0; 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 = 70144; kph.bootloader_address = 0xbeadd008; kph.bootloader_size = 0x1234; memcpy(kernel_buffer, &kbh, sizeof(kbh)); memcpy((kernel_buffer + kbh.key_block_size), &kph, sizeof(kph)); hash_only_check = -1; } static void copy_kbh(void) { memcpy(kernel_buffer, &kbh, sizeof(kbh)); } /* Mock functions */ 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 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) { hash_only_check = 0; if (key_block_verify_fail) return VB2_ERROR_MOCK; /* Use this as an opportunity to override the key block */ 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) { hash_only_check = 1; if (key_block_verify_fail) return VB2_ERROR_MOCK; /* Use this as an opportunity to override the key block */ 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 VbExNvStorageRead(uint8_t *buf) { memcpy(buf, ctx_nvram_backend.nvdata, vb2_nv_get_size(&ctx_nvram_backend)); return VB2_SUCCESS; } static void VerifyMemoryBootImageTest(void) { uint32_t u; int kernel_body_offset; int kernel_body_size; uintptr_t kernel_body_start; size_t kernel_buffer_size = sizeof(kernel_buffer); ResetMocks(); kernel_body_offset = kbh.key_block_size + kph.preamble_size; kernel_body_size = sizeof(kernel_buffer) - kernel_body_offset; kernel_body_start = (uintptr_t)kernel_buffer + kernel_body_offset; u = VbVerifyMemoryBootImage(&ctx, shared, &kparams, kernel_buffer, kernel_buffer_size); TEST_EQ(u, 0, "Image good"); TEST_EQ(kparams.partition_number, 0, " part num"); TEST_EQ(kparams.bootloader_address, 0xbeadd008, " bootloader addr"); TEST_EQ(kparams.bootloader_size, 0x1234, " bootloader size"); TEST_PTR_EQ(kparams.kernel_buffer, (void *)(kernel_body_start), " kernel buffer"); TEST_EQ(kparams.kernel_buffer_size, kernel_body_size, " kernel buffer size"); /* Empty image buffer. */ ResetMocks(); TEST_EQ(VbVerifyMemoryBootImage(&ctx, shared, &kparams, NULL, kernel_buffer_size), VB2_ERROR_INVALID_PARAMETER, "Empty image"); /* Illegal image size. */ ResetMocks(); TEST_EQ(VbVerifyMemoryBootImage(&ctx, shared, &kparams, kernel_buffer, 0), VB2_ERROR_INVALID_PARAMETER, "Illegal image size"); /* Key Block Verification Failure */ ResetMocks(); key_block_verify_fail = 1; TEST_EQ(VbVerifyMemoryBootImage(&ctx, shared, &kparams, kernel_buffer, kernel_buffer_size), VBERROR_INVALID_KERNEL_FOUND, "Key verify failed"); TEST_EQ(hash_only_check, 0, " hash check"); /* Key Block Hash Failure */ ResetMocks(); shared->flags = VBSD_BOOT_DEV_SWITCH_ON; gbb.flags = VB2_GBB_FLAG_FORCE_DEV_BOOT_FASTBOOT_FULL_CAP; key_block_verify_fail = 1; TEST_EQ(VbVerifyMemoryBootImage(&ctx, shared, &kparams, kernel_buffer, kernel_buffer_size), VBERROR_INVALID_KERNEL_FOUND, "Key verify failed"); TEST_EQ(hash_only_check, 1, " hash check"); /* Key Block Hash Failure -- VBNV */ ResetMocks(); shared->flags = VBSD_BOOT_DEV_SWITCH_ON; key_block_verify_fail = 1; vb2_nv_set(&ctx_nvram_backend, VB2_NV_DEV_BOOT_FASTBOOT_FULL_CAP, 1); TEST_EQ(VbVerifyMemoryBootImage(&ctx, shared, &kparams, kernel_buffer, kernel_buffer_size), VBERROR_INVALID_KERNEL_FOUND, "Key verify failed"); TEST_EQ(hash_only_check, 1, " hash check -- VBNV flag"); /* Developer flag mismatch - dev switch on */ ResetMocks(); kbh.key_block_flags = KEY_BLOCK_FLAG_DEVELOPER_0 | KEY_BLOCK_FLAG_RECOVERY_1; copy_kbh(); shared->flags = VBSD_BOOT_DEV_SWITCH_ON; TEST_EQ(VbVerifyMemoryBootImage(&ctx, shared, &kparams, kernel_buffer, kernel_buffer_size), VBERROR_INVALID_KERNEL_FOUND, "Developer flag mismatch - dev switch on"); /* Developer flag mismatch - dev switch on with GBB override */ ResetMocks(); kbh.key_block_flags = KEY_BLOCK_FLAG_DEVELOPER_0 | KEY_BLOCK_FLAG_RECOVERY_1; copy_kbh(); gbb.flags = VB2_GBB_FLAG_FORCE_DEV_BOOT_FASTBOOT_FULL_CAP; shared->flags = VBSD_BOOT_DEV_SWITCH_ON; TEST_EQ(VbVerifyMemoryBootImage(&ctx, shared, &kparams, kernel_buffer, kernel_buffer_size), VB2_SUCCESS, "Developer flag mismatch - dev switch on(gbb override)"); /* Recovery flag mismatch - dev switch on with GBB override */ ResetMocks(); kbh.key_block_flags = KEY_BLOCK_FLAG_DEVELOPER_0 | KEY_BLOCK_FLAG_RECOVERY_0; copy_kbh(); shared->flags = VBSD_BOOT_DEV_SWITCH_ON; gbb.flags = VB2_GBB_FLAG_FORCE_DEV_BOOT_FASTBOOT_FULL_CAP; TEST_EQ(VbVerifyMemoryBootImage(&ctx, shared, &kparams, kernel_buffer, kernel_buffer_size), VB2_SUCCESS, "Recovery flag mismatch - dev switch on(gbb override)"); /* Developer flag mismatch - dev switch off */ ResetMocks(); kbh.key_block_flags = KEY_BLOCK_FLAG_DEVELOPER_1 | KEY_BLOCK_FLAG_RECOVERY_1; copy_kbh(); TEST_EQ(VbVerifyMemoryBootImage(&ctx, shared, &kparams, kernel_buffer, kernel_buffer_size), VBERROR_INVALID_KERNEL_FOUND, "Developer flag mismatch - dev switch off"); /* Recovery flag mismatch */ ResetMocks(); kbh.key_block_flags = KEY_BLOCK_FLAG_DEVELOPER_0 | KEY_BLOCK_FLAG_RECOVERY_0; shared->flags = 0; copy_kbh(); TEST_EQ(VbVerifyMemoryBootImage(&ctx, shared, &kparams, kernel_buffer, kernel_buffer_size), VBERROR_INVALID_KERNEL_FOUND, "Recovery flag mismatch"); /* Preamble verification */ ResetMocks(); preamble_verify_fail = 1; TEST_EQ(VbVerifyMemoryBootImage(&ctx, shared, &kparams, kernel_buffer, kernel_buffer_size), VBERROR_INVALID_KERNEL_FOUND, "Preamble verification"); /* Data verification */ ResetMocks(); verify_data_fail = 1; TEST_EQ(VbVerifyMemoryBootImage(&ctx, shared, &kparams, kernel_buffer, kernel_buffer_size), VBERROR_INVALID_KERNEL_FOUND, "Data verification"); } int main(void) { VerifyMemoryBootImageTest(); return gTestSuccess ? 0 : 255; }