/* 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 VbTryLoadKernel() */ #include <stddef.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> #include "gbb_header.h" #include "load_kernel_fw.h" #include "rollback_index.h" #include "test_common.h" #include "utility.h" #include "vboot_api.h" #include "vboot_kernel.h" #define MAX_TEST_DISKS 10 #define DEFAULT_COUNT -1 typedef struct { uint64_t bytes_per_lba; uint64_t lba_count; uint32_t flags; const char *diskname; } disk_desc_t; typedef struct { char *name; /* inputs for test case */ uint32_t want_flags; VbError_t diskgetinfo_return_val; disk_desc_t disks_to_provide[MAX_TEST_DISKS]; int disk_count_to_return; VbError_t loadkernel_return_val[MAX_TEST_DISKS]; uint8_t external_expected[MAX_TEST_DISKS]; /* outputs from test */ uint32_t expected_recovery_request_val; const char *expected_to_find_disk; const char *expected_to_load_disk; uint32_t expected_return_val; } test_case_t; /****************************************************************************/ /* Test cases */ static const char pickme[] = "correct choice"; #define DONT_CARE ((const char *)42) test_case_t test[] = { { .name = "first removable drive", .want_flags = VB_DISK_FLAG_REMOVABLE, .disks_to_provide = { /* too small */ {512, 10, VB_DISK_FLAG_REMOVABLE, 0}, /* wrong LBA */ {2048, 100, VB_DISK_FLAG_REMOVABLE, 0}, /* wrong type */ {512, 100, VB_DISK_FLAG_FIXED, 0}, /* wrong flags */ {512, 100, 0, 0}, /* still wrong flags */ {512, 100, -1, 0}, {512, 100, VB_DISK_FLAG_REMOVABLE | VB_DISK_FLAG_EXTERNAL_GPT, pickme}, /* already got one */ {512, 100, VB_DISK_FLAG_REMOVABLE, "holygrail"}, }, .disk_count_to_return = DEFAULT_COUNT, .diskgetinfo_return_val = VBERROR_SUCCESS, .loadkernel_return_val = {0, 1, 1, 1, 1, 1, 1, 1, 1, 1,}, .external_expected = {1, 0, 0, 0, 0, 0, 0, 0, 0, 0,}, .expected_recovery_request_val = VBNV_RECOVERY_NOT_REQUESTED, .expected_to_find_disk = pickme, .expected_to_load_disk = pickme, .expected_return_val = VBERROR_SUCCESS }, { .name = "second removable drive", .want_flags = VB_DISK_FLAG_REMOVABLE, .disks_to_provide = { /* wrong flags */ {512, 100, 0, 0}, {512, 100, VB_DISK_FLAG_REMOVABLE, "not yet"}, {512, 100, VB_DISK_FLAG_REMOVABLE, pickme}, }, .disk_count_to_return = DEFAULT_COUNT, .diskgetinfo_return_val = VBERROR_SUCCESS, .loadkernel_return_val = {1, 0, 1, 1, 1, 1, 1, 1, 1, 1,}, .expected_recovery_request_val = VBNV_RECOVERY_NOT_REQUESTED, .expected_to_find_disk = pickme, .expected_to_load_disk = pickme, .expected_return_val = VBERROR_SUCCESS }, { .name = "first fixed drive", .want_flags = VB_DISK_FLAG_FIXED, .disks_to_provide = { /* too small */ {512, 10, VB_DISK_FLAG_FIXED, 0}, /* wrong LBA */ {2048, 100, VB_DISK_FLAG_FIXED, 0}, /* wrong type */ {512, 100, VB_DISK_FLAG_REMOVABLE, 0}, /* wrong flags */ {512, 100, 0, 0}, /* still wrong flags */ {512, 100, -1, 0}, /* flags */ {512, 100, VB_DISK_FLAG_REMOVABLE|VB_DISK_FLAG_FIXED, 0}, {512, 100, VB_DISK_FLAG_FIXED, pickme}, /* already got one */ {512, 100, VB_DISK_FLAG_FIXED, "holygrail"}, }, .disk_count_to_return = DEFAULT_COUNT, .diskgetinfo_return_val = VBERROR_SUCCESS, .loadkernel_return_val = {0, 1, 1, 1, 1, 1, 1, 1, 1, 1,}, .expected_recovery_request_val = VBNV_RECOVERY_NOT_REQUESTED, .expected_to_find_disk = pickme, .expected_to_load_disk = pickme, .expected_return_val = VBERROR_SUCCESS }, { .name = "no drives at all", .want_flags = VB_DISK_FLAG_FIXED, .disks_to_provide = {}, .disk_count_to_return = DEFAULT_COUNT, .diskgetinfo_return_val = VBERROR_SUCCESS, .loadkernel_return_val = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1,}, .expected_recovery_request_val = VBNV_RECOVERY_RW_NO_DISK, .expected_to_find_disk = 0, .expected_to_load_disk = 0, .expected_return_val = VBERROR_NO_DISK_FOUND }, { .name = "no valid drives", .want_flags = VB_DISK_FLAG_FIXED, .disks_to_provide = { /* too small */ {512, 10, VB_DISK_FLAG_FIXED, 0}, /* wrong LBA */ {2048, 100, VB_DISK_FLAG_FIXED, 0}, /* wrong type */ {512, 100, VB_DISK_FLAG_REMOVABLE, 0}, /* wrong flags */ {512, 100, 0, 0}, /* still wrong flags */ {512, 100, -1, 0}, /* doesn't load */ {512, 100, VB_DISK_FLAG_FIXED, "bad1"}, /* doesn't load */ {512, 100, VB_DISK_FLAG_FIXED, "bad2"}, }, .disk_count_to_return = DEFAULT_COUNT, .diskgetinfo_return_val = VBERROR_SUCCESS, .loadkernel_return_val = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1,}, .expected_recovery_request_val = VBNV_RECOVERY_RW_NO_KERNEL, .expected_to_find_disk = DONT_CARE, .expected_to_load_disk = 0, .expected_return_val = 1 }, }; /****************************************************************************/ /* Mock data */ static LoadKernelParams lkparams; static VbDiskInfo mock_disks[MAX_TEST_DISKS]; static test_case_t *t; static int load_kernel_calls; static uint32_t got_recovery_request_val; static const char *got_find_disk; static const char *got_load_disk; static uint32_t got_return_val; static uint32_t got_external_mismatch; /** * Reset mock data (for use before each test) */ static void ResetMocks(int i) { Memset(&lkparams, 0, sizeof(lkparams)); Memset(&mock_disks, 0, sizeof(mock_disks)); load_kernel_calls = 0; got_recovery_request_val = VBNV_RECOVERY_NOT_REQUESTED; got_find_disk = 0; got_load_disk = 0; got_return_val = 0xdeadbeef; t = test + i; } int is_nonzero(const void *vptr, size_t count) { const char *p = (const char *)vptr; while (count--) if (*p++) return 1; return 0; } /****************************************************************************/ /* Mocked verification functions */ VbError_t VbExDiskGetInfo(VbDiskInfo **infos_ptr, uint32_t *count, uint32_t disk_flags) { int i; int num_disks = 0; VBDEBUG(("My %s\n", __FUNCTION__)); *infos_ptr = mock_disks; for(i = 0; i < MAX_TEST_DISKS; i++) { if (is_nonzero(&t->disks_to_provide[i], sizeof(t->disks_to_provide[i]))) { mock_disks[num_disks].bytes_per_lba = t->disks_to_provide[i].bytes_per_lba; mock_disks[num_disks].lba_count = mock_disks[num_disks].streaming_lba_count = t->disks_to_provide[i].lba_count; mock_disks[num_disks].flags = t->disks_to_provide[i].flags; mock_disks[num_disks].handle = (VbExDiskHandle_t) t->disks_to_provide[i].diskname; VBDEBUG((" mock_disk[%d] %" PRIu64 " %" PRIu64 " 0x%x %s\n", i, mock_disks[num_disks].bytes_per_lba, mock_disks[num_disks].lba_count, mock_disks[num_disks].flags, (mock_disks[num_disks].handle ? (char *)mock_disks[num_disks].handle : "0"))); num_disks++; } else { mock_disks[num_disks].handle = (VbExDiskHandle_t)"INVALID"; } } if (t->disk_count_to_return >= 0) *count = t->disk_count_to_return; else *count = num_disks; VBDEBUG((" *count=%" PRIu32 "\n", *count)); VBDEBUG((" return 0x%x\n", t->diskgetinfo_return_val)); return t->diskgetinfo_return_val; } VbError_t VbExDiskFreeInfo(VbDiskInfo *infos, VbExDiskHandle_t preserve_handle) { got_load_disk = (const char *)preserve_handle; VBDEBUG(("%s(): got_load_disk = %s\n", __FUNCTION__, got_load_disk ? got_load_disk : "0")); return VBERROR_SUCCESS; } VbError_t LoadKernel(LoadKernelParams *params, VbCommonParams *cparams) { got_find_disk = (const char *)params->disk_handle; VBDEBUG(("%s(%d): got_find_disk = %s\n", __FUNCTION__, load_kernel_calls, got_find_disk ? got_find_disk : "0")); if (t->external_expected[load_kernel_calls] != !!(params->boot_flags & BOOT_FLAG_EXTERNAL_GPT)) got_external_mismatch++; return t->loadkernel_return_val[load_kernel_calls++]; } int VbNvSet(VbNvContext *context, VbNvParam param, uint32_t value) { VBDEBUG(("%s(): got_recovery_request_val = %d (0x%x)\n", __FUNCTION__, value, value)); got_recovery_request_val = value; return 0; } /****************************************************************************/ static void VbTryLoadKernelTest(void) { int i; int num_tests = sizeof(test) / sizeof(test[0]); for (i = 0; i < num_tests; i++) { printf("Test case: %s ...\n", test[i].name); ResetMocks(i); TEST_EQ(VbTryLoadKernel(0, &lkparams, test[i].want_flags), t->expected_return_val, " return value"); TEST_EQ(got_recovery_request_val, t->expected_recovery_request_val, " recovery_request"); if (t->expected_to_find_disk != DONT_CARE) { TEST_PTR_EQ(got_find_disk, t->expected_to_find_disk, " find disk"); TEST_PTR_EQ(got_load_disk, t->expected_to_load_disk, " load disk"); } TEST_EQ(got_external_mismatch, 0, " external GPT errors"); } } int main(void) { VbTryLoadKernelTest(); if (vboot_api_stub_check_memory()) return 255; return gTestSuccess ? 0 : 255; }