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) */
ResetMocks(void)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 
VbExNvStorageRead(uint8_t * buf)82 VbError_t VbExNvStorageRead(uint8_t* buf) {
83   Memcpy(buf, vnc.raw, sizeof(vnc.raw));
84   return VBERROR_SUCCESS;
85 }
86 
VbExNvStorageWrite(const uint8_t * buf)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 
VbExGetTimer(void)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 
RollbackFirmwareWrite(uint32_t version)102 uint32_t RollbackFirmwareWrite(uint32_t version) {
103   mock_tpm_version = version;
104   return mock_rfw_retval;
105 }
106 
RollbackFirmwareLock(void)107 uint32_t RollbackFirmwareLock(void) {
108   mock_rfl_called = 1;
109   return mock_rfl_retval;
110 }
111 
SetTPMBootModeState(int developer_mode,int recovery_mode,uint64_t fw_keyblock_flags,GoogleBinaryBlockHeader * gbb)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 
LoadFirmware(VbCommonParams * cparams,VbSelectFirmwareParams * fparams,VbNvContext * vnc)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 */
TestVbSf(VbError_t expected_retval,uint8_t expected_recovery,const char * desc)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 
VbSelectFirmwareTest(void)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 
main(int argc,char * argv[])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