1/* Copyright (c) 2011 The Chromium OS Authors. All rights reserved. 2 * Use of this source code is governed by a BSD-style license that can be 3 * found in the LICENSE file. 4 * 5 * Tests for vboot_api_firmware 6 */ 7 8#include <stdint.h> 9#include <stdio.h> 10#include <stdlib.h> 11 12#include "gbb_header.h" 13#include "host_common.h" 14#include "rollback_index.h" 15#include "test_common.h" 16#include "vboot_common.h" 17#include "vboot_nvstorage.h" 18#include "vboot_struct.h" 19 20/* Flags for mock_*_got_flags variables */ 21#define MOCK_DEV_FLAG 0x01 /* Developer parameter non-zero */ 22#define MOCK_REC_FLAG 0x02 /* Recovery parameter non-zero */ 23 24/* Mock data */ 25static VbCommonParams cparams; 26static VbSelectFirmwareParams fparams; 27static GoogleBinaryBlockHeader gbb; 28static VbNvContext vnc; 29static uint8_t shared_data[VB_SHARED_DATA_MIN_SIZE]; 30static VbSharedDataHeader* shared = (VbSharedDataHeader*)shared_data; 31static uint64_t mock_timer; 32static int nv_write_called; 33/* Mock TPM versions */ 34static uint32_t mock_tpm_version; 35static uint32_t mock_lf_tpm_version; /* TPM version set by LoadFirmware() */ 36/* Variables for tracking params passed to mock functions */ 37static uint32_t mock_stbms_got_flags; 38static uint64_t mock_stbms_got_fw_flags; 39static int mock_rfl_called; 40/* Mock return values, so we can simulate errors */ 41static VbError_t mock_rfw_retval; 42static VbError_t mock_rfl_retval; 43static VbError_t mock_lf_retval; 44static VbError_t mock_stbms_retval; 45 46/* Reset mock data (for use before each test) */ 47static void ResetMocks(void) { 48 Memset(&cparams, 0, sizeof(cparams)); 49 cparams.shared_data_size = sizeof(shared_data); 50 cparams.shared_data_blob = shared_data; 51 52 Memset(&fparams, 0, sizeof(fparams)); 53 54 Memset(&gbb, 0, sizeof(gbb)); 55 cparams.gbb_data = &gbb; 56 cparams.gbb_size = sizeof(gbb); 57 cparams.gbb = &gbb; 58 59 Memset(&vnc, 0, sizeof(vnc)); 60 VbNvSetup(&vnc); 61 VbNvTeardown(&vnc); /* So CRC gets generated */ 62 63 Memset(&shared_data, 0, sizeof(shared_data)); 64 VbSharedDataInit(shared, sizeof(shared_data)); 65 shared->fw_keyblock_flags = 0xABCDE0; 66 67 mock_timer = 10; 68 nv_write_called = mock_rfl_called = 0; 69 70 mock_stbms_got_flags = 0; 71 mock_stbms_got_fw_flags = 0; 72 73 mock_tpm_version = mock_lf_tpm_version = 0x20004; 74 shared->fw_version_tpm_start = mock_tpm_version; 75 mock_rfw_retval = mock_rfl_retval = 0; 76 mock_lf_retval = mock_stbms_retval = 0; 77} 78 79/****************************************************************************/ 80/* Mocked verification functions */ 81 82VbError_t VbExNvStorageRead(uint8_t* buf) { 83 Memcpy(buf, vnc.raw, sizeof(vnc.raw)); 84 return VBERROR_SUCCESS; 85} 86 87VbError_t VbExNvStorageWrite(const uint8_t* buf) { 88 nv_write_called = 1; 89 Memcpy(vnc.raw, buf, sizeof(vnc.raw)); 90 return VBERROR_SUCCESS; 91} 92 93uint64_t VbExGetTimer(void) { 94 /* Exponential-ish rather than linear time, so that subtracting any 95 * two mock values will yield a unique result. */ 96 uint64_t new_timer = mock_timer * 2 + 1; 97 VbAssert(new_timer > mock_timer); /* Make sure we don't overflow */ 98 mock_timer = new_timer; 99 return mock_timer; 100} 101 102uint32_t RollbackFirmwareWrite(uint32_t version) { 103 mock_tpm_version = version; 104 return mock_rfw_retval; 105} 106 107uint32_t RollbackFirmwareLock(void) { 108 mock_rfl_called = 1; 109 return mock_rfl_retval; 110} 111 112uint32_t SetTPMBootModeState(int developer_mode, int recovery_mode, 113 uint64_t fw_keyblock_flags, 114 GoogleBinaryBlockHeader *gbb) { 115 if (recovery_mode) 116 mock_stbms_got_flags |= MOCK_REC_FLAG; 117 if (developer_mode) 118 mock_stbms_got_flags |= MOCK_DEV_FLAG; 119 120 mock_stbms_got_fw_flags = fw_keyblock_flags; 121 122 return mock_stbms_retval; 123} 124 125int LoadFirmware(VbCommonParams* cparams, VbSelectFirmwareParams* fparams, 126 VbNvContext* vnc) { 127 shared->fw_version_tpm = mock_lf_tpm_version; 128 return mock_lf_retval; 129} 130 131 132/****************************************************************************/ 133/* Test VbSelectFirmware() and check expected return value and 134 * recovery reason */ 135static void TestVbSf(VbError_t expected_retval, 136 uint8_t expected_recovery, const char* desc) { 137 uint32_t rr = 256; 138 139 TEST_EQ(VbSelectFirmware(&cparams, &fparams), expected_retval, desc); 140 VbNvGet(&vnc, VBNV_RECOVERY_REQUEST, &rr); 141 TEST_EQ(rr, expected_recovery, " recovery request"); 142} 143 144/****************************************************************************/ 145 146static void VbSelectFirmwareTest(void) { 147 /* Normal call */ 148 ResetMocks(); 149 TestVbSf(0, 0, "Normal call"); 150 TEST_EQ(shared->timer_vb_select_firmware_enter, 21, " time enter"); 151 TEST_EQ(shared->timer_vb_select_firmware_exit, 43, " time exit"); 152 TEST_EQ(nv_write_called, 0, " NV write not called since nothing changed"); 153 TEST_EQ(mock_stbms_got_flags, 0, " SetTPMBootModeState() flags"); 154 TEST_EQ(mock_stbms_got_fw_flags, 0xABCDE0, " fw keyblock flags"); 155 TEST_EQ(mock_rfl_called, 1, " RollbackFirmwareLock() called"); 156 157 /* Developer mode call */ 158 ResetMocks(); 159 shared->flags |= VBSD_BOOT_DEV_SWITCH_ON; 160 TestVbSf(0, 0, "Developer mode"); 161 TEST_EQ(mock_stbms_got_flags, MOCK_DEV_FLAG, " SetTPMBootModeState() flags"); 162 TEST_EQ(mock_rfl_called, 1, " RollbackFirmwareLock() called"); 163 164 /* Recovery mode doesn't call LoadFirmware(), 165 * RollbackFirmwareWrite(), or RollbackFirmwareLock(). */ 166 ResetMocks(); 167 shared->recovery_reason = VBNV_RECOVERY_US_TEST; 168 mock_lf_retval = VBERROR_UNKNOWN; 169 mock_rfw_retval = mock_rfl_retval = TPM_E_IOERROR; 170 TestVbSf(0, 0, "Recovery mode"); 171 TEST_EQ(fparams.selected_firmware, VB_SELECT_FIRMWARE_RECOVERY, 172 " select recovery"); 173 TEST_EQ(mock_stbms_got_flags, MOCK_REC_FLAG, " SetTPMBootModeState() flags"); 174 TEST_EQ(mock_rfl_called, 0, " RollbackFirmwareLock() not called"); 175 176 /* Dev + recovery */ 177 ResetMocks(); 178 shared->recovery_reason = VBNV_RECOVERY_US_TEST; 179 shared->flags |= VBSD_BOOT_DEV_SWITCH_ON; 180 TestVbSf(0, 0, "Recovery+developer mode"); 181 TEST_EQ(fparams.selected_firmware, VB_SELECT_FIRMWARE_RECOVERY, 182 " select recovery"); 183 TEST_EQ(mock_stbms_got_flags, MOCK_DEV_FLAG|MOCK_REC_FLAG, 184 " SetTPMBootModeState() flags"); 185 TEST_EQ(mock_rfl_called, 0, " RollbackFirmwareLock() not called"); 186 187 /* LoadFirmware() error code passed through */ 188 ResetMocks(); 189 mock_lf_retval = 0x12345; 190 TestVbSf(0x12345, 0, "LoadFirmware() error"); 191 192 /* Select different firmware paths based on LoadFirmware() result */ 193 ResetMocks(); 194 shared->flags |= VBSD_LF_USE_RO_NORMAL; 195 TestVbSf(0, 0, "LoadFirmware() RO-normal"); 196 TEST_EQ(fparams.selected_firmware, VB_SELECT_FIRMWARE_READONLY, 197 " select RO normal"); 198 ResetMocks(); 199 shared->firmware_index = 0; 200 TestVbSf(0, 0, "LoadFirmware() A"); 201 TEST_EQ(fparams.selected_firmware, VB_SELECT_FIRMWARE_A, " select A"); 202 ResetMocks(); 203 shared->firmware_index = 1; 204 TestVbSf(0, 0, "LoadFirmware() B"); 205 TEST_EQ(fparams.selected_firmware, VB_SELECT_FIRMWARE_B, " select B"); 206 207 /* Handle TPM version updates */ 208 ResetMocks(); 209 mock_lf_tpm_version = 0x30005; 210 TestVbSf(0, 0, "TPM version update"); 211 TEST_EQ(shared->fw_version_tpm_start, 0x20004, " TPM version start"); 212 TEST_EQ(shared->fw_version_tpm, 0x30005, " TPM version"); 213 TEST_EQ(mock_tpm_version, 0x30005, " TPM version written back"); 214 215 /* Check error writing TPM version */ 216 ResetMocks(); 217 mock_lf_tpm_version = 0x30005; 218 mock_rfw_retval = TPM_E_IOERROR; 219 TestVbSf(VBERROR_TPM_WRITE_FIRMWARE, VBNV_RECOVERY_RO_TPM_W_ERROR, 220 "TPM version update failure"); 221 222 /* If no change to TPM version, RollbackFirmwareWrite() not called */ 223 ResetMocks(); 224 mock_rfw_retval = TPM_E_IOERROR; 225 TestVbSf(0, 0, "LoadFirmware() TPM version not updated"); 226 TEST_EQ(shared->fw_version_tpm_start, 0x20004, " TPM version start"); 227 TEST_EQ(shared->fw_version_tpm, 0x20004, " TPM version"); 228 TEST_EQ(mock_tpm_version, 0x20004, " TPM version (not) written back"); 229 230 /* Check errors from SetTPMBootModeState() */ 231 ResetMocks(); 232 mock_stbms_retval = TPM_E_IOERROR; 233 TestVbSf(VBERROR_TPM_SET_BOOT_MODE_STATE, VBNV_RECOVERY_RO_TPM_U_ERROR, 234 "TPM set boot mode state failure"); 235 ResetMocks(); 236 mock_stbms_retval = TPM_E_IOERROR; 237 shared->recovery_reason = VBNV_RECOVERY_US_TEST; 238 TestVbSf(0, 0, "TPM set boot mode state failure ignored in recovery"); 239 240 /* Handle RollbackFirmwareLock() errors */ 241 ResetMocks(); 242 mock_rfl_retval = TPM_E_IOERROR; 243 TestVbSf(VBERROR_TPM_LOCK_FIRMWARE, VBNV_RECOVERY_RO_TPM_L_ERROR, 244 "TPM lock firmware failure"); 245} 246 247 248int main(int argc, char* argv[]) { 249 int error_code = 0; 250 251 VbSelectFirmwareTest(); 252 253 if (vboot_api_stub_check_memory()) 254 error_code = 255; 255 if (!gTestSuccess) 256 error_code = 255; 257 258 return error_code; 259} 260