efivars.c
1 /* SPDX-License-Identifier: GPL-2.0-only */ 2 3 #include <drivers/efi/efivars.h> 4 #include <vendorcode/intel/edk2/UDK2017/MdePkg/Include/Pi/PiFirmwareVolume.h> 5 #include <vendorcode/intel/edk2/UDK2017/MdeModulePkg/Include/Guid/VariableFormat.h> 6 #include <string.h> 7 #include <tests/test.h> 8 #include <types.h> 9 10 /* Dummy firmware volume header for a 0x30000 byte partition with a single entry 11 * in a formatted variable store. 12 */ 13 static const uint8_t FVH[] = { 14 /* EFI_FIRMWARE_VOLUME_HEADER */ 15 /* UINT8 ZeroVector[16] */ 16 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 17 0x00, 0x00, 18 /* EFI_GUID FileSystemGuid */ 19 0x8d, 0x2b, 0xf1, 0xff, 0x96, 0x76, 0x8b, 0x4c, 0xa9, 0x85, 0x27, 0x47, 0x07, 0x5b, 20 0x4f, 0x50, 21 /* UINT64 FvLength */ 22 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 23 /* UINT32 Signature */ 24 0x5f, 0x46, 0x56, 0x48, 25 /* EFI_FVB_ATTRIBUTES_2 Attributes */ 26 0x36, 0x0e, 0x00, 0x00, 27 /* UINT16 HeaderLength */ 28 0x48, 0x00, 29 /* UINT16 Checksum */ 30 0x00, 0xfa, 31 /* UINT16 ExtHeaderOffset */ 32 0x00, 0x00, 33 /* UINT8 Reserved[1] */ 34 0x00, 35 /* UINT8 Revision */ 36 0x02, 37 /* EFI_FV_BLOCK_MAP_ENTRY BlockMap[2] */ 38 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 39 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 40 41 /* Variable Info Header */ 42 /* EFI_GUID Signature */ 43 0x78, 0x2c, 0xf3, 0xaa, 0x7b, 0x94, 0x9a, 0x43, 0xa1, 0x80, 0x2e, 0x14, 0x4e, 0xc3, 44 0x77, 0x92, 45 /* UINT32 Size */ 46 0xb8, 0xff, 0x00, 0x00, 47 /* UINT8 Format */ 48 0x5a, 49 /* UINT8 State */ 50 0xfe, 51 /* UINT16 Reserved */ 52 0x00, 0x00, 53 /* UINT32 Reserved1 */ 54 0x00, 0x00, 0x00, 0x00, 55 /* AUTHENTICATED_VARIABLE_HEADER */ 56 /* UINT16 StartId */ 57 0xaa, 0x55, 58 /* UINT8 State */ 59 0x3f, 60 /* UINT8 Reserved */ 61 0xff, 62 /* UINT32 Attributes */ 63 0x07, 0x00, 0x00, 0x00, 64 /* UINT64 MonotonicCount */ 65 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 66 /* EFI_TIME TimeStamp */ 67 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 68 0xff, 0xff, 0xff, 0xff, 69 /* UINT32 PubKeyIndex */ 70 0xff, 0xff, 0xff, 0xff, 71 /* UINT32 NameSize */ 72 0x12, 0x00, 0x00, 0x00, 73 /* UINT32 DataSize */ 74 0x09, 0x00, 0x00, 0x00, 75 /* EFI_GUID VendorGuid */ 76 0x1d, 0x4c, 0xae, 0xce, 0x5b, 0x33, 0x85, 0x46, 0xa4, 0xa0, 0xfc, 0x4a, 77 0x94, 0xee, 0xa0, 0x85, 78 /* L"coreboot" */ 79 0x63, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x65, 0x00, 0x62, 0x00, 80 0x6f, 0x00, 0x6f, 0x00, 0x74, 0x00, 0x00, 0x00, 81 /* "is great" */ 82 0x69, 0x73, 0x20, 0x67, 0x72, 0x65, 0x61, 0x74, 0x00, 83 }; 84 85 #define FVH_CHECKSUMMED_SIZE (sizeof(EFI_FIRMWARE_VOLUME_HEADER) + 8 + sizeof(EFI_GUID)) 86 87 static struct region_device flash_rdev_rw; 88 static uint8_t flash_buffer[0x30000]; 89 90 static const char *name = "coreboot"; 91 92 static void mock_rdev(bool init) 93 { 94 if (init) { 95 /* Emulate NOR flash by setting all bits to 1 */ 96 memset(flash_buffer, 0xff, sizeof(flash_buffer)); 97 /* Place _FVH and VIH headers, as well as test data */ 98 memcpy(flash_buffer, FVH, sizeof(FVH)); 99 } 100 101 rdev_chain_mem_rw(&flash_rdev_rw, flash_buffer, sizeof(flash_buffer)); 102 } 103 104 static const EFI_GUID EficorebootNvDataGuid = { 105 0xceae4c1d, 0x335b, 0x4685, { 0xa4, 0xa0, 0xfc, 0x4a, 0x94, 0xee, 0xa0, 0x85 } }; 106 107 /* Test valid and corrupted FVH header */ 108 static void efi_test_header(void **state) 109 { 110 enum cb_err ret; 111 uint8_t buf[16]; 112 uint32_t size; 113 int i; 114 115 mock_rdev(true); 116 117 /* Test variable lookup with intact header */ 118 size = sizeof(buf); 119 ret = efi_fv_get_option(&flash_rdev_rw, &EficorebootNvDataGuid, name, buf, &size); 120 assert_int_equal(ret, CB_SUCCESS); 121 assert_int_equal(size, strlen("is great")+1); 122 assert_string_equal((const char *)buf, "is great"); 123 124 for (i = 0; i < FVH_CHECKSUMMED_SIZE; i++) { 125 mock_rdev(true); 126 127 /* Flip some bits */ 128 flash_buffer[i] ^= 0xff; 129 130 size = sizeof(buf); 131 ret = efi_fv_get_option(&flash_rdev_rw, &EficorebootNvDataGuid, name, buf, 132 &size); 133 assert_int_not_equal(ret, CB_SUCCESS); 134 } 135 } 136 137 /* Write with the same key and value should not modify the store */ 138 static void efi_test_noop_existing_write(void **state) 139 { 140 enum cb_err ret; 141 int i; 142 143 mock_rdev(true); 144 145 ret = efi_fv_set_option(&flash_rdev_rw, 146 &EficorebootNvDataGuid, 147 name, 148 "is great", 149 strlen("is great") + 1); 150 151 assert_int_equal(ret, CB_SUCCESS); 152 153 for (i = sizeof(FVH); i < sizeof(flash_buffer); i++) 154 assert_int_equal(flash_buffer[i], 0xff); 155 } 156 157 static void efi_test_new_write(void **state) 158 { 159 enum cb_err ret; 160 uint8_t buf[16]; 161 uint32_t size; 162 int i; 163 164 mock_rdev(true); 165 166 ret = efi_fv_set_option(&flash_rdev_rw, &EficorebootNvDataGuid, 167 name, "is awesome", strlen("is awesome") + 1); 168 assert_int_equal(ret, CB_SUCCESS); 169 170 /* New variable has been written */ 171 assert_int_equal(flash_buffer[ALIGN_UP(sizeof(FVH), 4)], 0xaa); 172 assert_int_equal(flash_buffer[ALIGN_UP(sizeof(FVH), 4) + 1], 0x55); 173 174 /* Remaining space is blank */ 175 for (i = ALIGN_UP(sizeof(FVH), 4) + 89; i < sizeof(flash_buffer); i++) 176 assert_int_equal(flash_buffer[i], 0xff); 177 178 mock_rdev(false); 179 180 memset(buf, 0, sizeof(buf)); 181 size = sizeof(buf); 182 ret = efi_fv_get_option(&flash_rdev_rw, &EficorebootNvDataGuid, name, buf, 183 &size); 184 assert_int_equal(ret, CB_SUCCESS); 185 assert_int_equal(size, strlen("is awesome")+1); 186 187 assert_int_equal(flash_buffer[ALIGN_UP(sizeof(FVH), 4) + 1], 0x55); 188 assert_string_equal((const char *)buf, "is awesome"); 189 } 190 191 int main(void) 192 { 193 const struct CMUnitTest tests[] = { 194 cmocka_unit_test(efi_test_header), 195 cmocka_unit_test(efi_test_noop_existing_write), 196 cmocka_unit_test(efi_test_new_write) 197 }; 198 199 return cb_run_group_tests(tests, NULL, NULL); 200 }