Home | History | Annotate | Download | only in tests
      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 */
     25 static VbCommonParams cparams;
     26 static VbSelectFirmwareParams fparams;
     27 static GoogleBinaryBlockHeader gbb;
     28 static VbNvContext vnc;
     29 static uint8_t shared_data[VB_SHARED_DATA_MIN_SIZE];
     30 static VbSharedDataHeader* shared = (VbSharedDataHeader*)shared_data;
     31 static uint64_t mock_timer;
     32 static int nv_write_called;
     33 /* Mock TPM versions */
     34 static uint32_t mock_tpm_version;
     35 static uint32_t mock_lf_tpm_version;  /* TPM version set by LoadFirmware() */
     36 /* Variables for tracking params passed to mock functions */
     37 static uint32_t mock_stbms_got_flags;
     38 static uint64_t mock_stbms_got_fw_flags;
     39 static int mock_rfl_called;
     40 /* Mock return values, so we can simulate errors */
     41 static VbError_t mock_rfw_retval;
     42 static VbError_t mock_rfl_retval;
     43 static VbError_t mock_lf_retval;
     44 static VbError_t mock_stbms_retval;
     45 
     46 /* Reset mock data (for use before each test) */
     47 static 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 
     82 VbError_t VbExNvStorageRead(uint8_t* buf) {
     83   Memcpy(buf, vnc.raw, sizeof(vnc.raw));
     84   return VBERROR_SUCCESS;
     85 }
     86 
     87 VbError_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 
     93 uint64_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 
    102 uint32_t RollbackFirmwareWrite(uint32_t version) {
    103   mock_tpm_version = version;
    104   return mock_rfw_retval;
    105 }
    106 
    107 uint32_t RollbackFirmwareLock(void) {
    108   mock_rfl_called = 1;
    109   return mock_rfl_retval;
    110 }
    111 
    112 uint32_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 
    125 int 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 */
    135 static 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 
    146 static 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 
    248 int 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