/ tests / drivers / efivars.c
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  }