1 /*
2  * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include <CppUTest/TestHarness.h>
8 #include <service/uefi/smm_variable/backend/variable_index.h>
9 #include <service/uefi/smm_variable/backend/variable_index_iterator.h>
10 #include <string>
11 #include <vector>
12 
TEST_GROUP(UefiVariableIndexTests)13 TEST_GROUP(UefiVariableIndexTests)
14 {
15 	void setup()
16 	{
17 		efi_status_t status = variable_index_init(&m_variable_index, MAX_VARIABLES);
18 		UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
19 
20 		guid_1.Data1 = 0x12341234;
21 		guid_1.Data2 = 0x1234;
22 		guid_1.Data3 = 0x1234;
23 		guid_1.Data4[0] = 0x00;
24 		guid_1.Data4[1] = 0x01;
25 		guid_1.Data4[2] = 0x02;
26 		guid_1.Data4[3] = 0x03;
27 		guid_1.Data4[4] = 0x04;
28 		guid_1.Data4[5] = 0x05;
29 		guid_1.Data4[6] = 0x06;
30 		guid_1.Data4[7] = 0x07;
31 
32 		guid_2.Data1 = 0x55443322;
33 		guid_2.Data2 = 0x2345;
34 		guid_2.Data3 = 0x2345;
35 		guid_2.Data4[0] = 0x10;
36 		guid_2.Data4[1] = 0x11;
37 		guid_2.Data4[2] = 0x12;
38 		guid_2.Data4[3] = 0x13;
39 		guid_2.Data4[4] = 0x14;
40 		guid_2.Data4[5] = 0x15;
41 		guid_2.Data4[6] = 0x16;
42 		guid_2.Data4[7] = 0x17;
43 
44 		name_1 = to_variable_name(u"var1");
45 		name_2 = to_variable_name(u"var2_nv");
46 		name_3 = to_variable_name(u"var3_nv");
47 		null_name = to_variable_name(u"");
48 	}
49 
50 	void teardown()
51 	{
52 		variable_index_deinit(&m_variable_index);
53 	}
54 
55 	std::u16string to_variable_name(const char16_t *string)
56 	{
57 		std::u16string var_name(string);
58 		var_name.push_back(0);
59 
60 		return var_name;
61 	}
62 
63 	size_t string_get_size_in_bytes(const std::u16string &string)
64 	{
65 		return string.size() * sizeof(typename std::u16string::value_type);
66 	}
67 
68 	void create_variables()
69 	{
70 		struct variable_info *info = NULL;
71 
72 		info = variable_index_add_entry(&m_variable_index, &guid_1,
73 						string_get_size_in_bytes(name_1), (int16_t *) name_1.data());
74 		CHECK_TRUE(info);
75 		variable_index_set_variable(info, EFI_VARIABLE_BOOTSERVICE_ACCESS);
76 
77 		info = variable_index_add_entry(&m_variable_index, &guid_2,
78 						string_get_size_in_bytes(name_2), (int16_t *)  name_2.data());
79 		CHECK_TRUE(info);
80 		variable_index_set_variable(info, EFI_VARIABLE_NON_VOLATILE |
81 							  EFI_VARIABLE_BOOTSERVICE_ACCESS);
82 
83 		info = variable_index_add_entry(&m_variable_index, &guid_1,
84 						string_get_size_in_bytes(name_3), (int16_t *)  name_3.data());
85 		CHECK_TRUE(info);
86 		variable_index_set_variable(info, EFI_VARIABLE_NON_VOLATILE |
87 							  EFI_VARIABLE_RUNTIME_ACCESS |
88 							  EFI_VARIABLE_BOOTSERVICE_ACCESS);
89 	}
90 
91 	static const size_t MAX_VARIABLES = 10;
92 
93 	struct variable_index m_variable_index;
94 	EFI_GUID guid_1;
95 	EFI_GUID guid_2;
96 	std::u16string name_1;
97 	std::u16string name_2;
98 	std::u16string name_3;
99 	std::u16string null_name;
100 };
101 
TEST(UefiVariableIndexTests,emptyIndexOperations)102 TEST(UefiVariableIndexTests, emptyIndexOperations)
103 {
104 	efi_status_t status = EFI_SUCCESS;
105 	struct variable_info *info = NULL;
106 
107 	/* Expect not to find a variable */
108 	info = variable_index_find(&m_variable_index, &guid_1, string_get_size_in_bytes(name_1),
109 				   (const int16_t *) name_1.data());
110 	POINTERS_EQUAL(NULL, info);
111 
112 	/* Expect also find next to be rejected */
113 	info = variable_index_find_next(&m_variable_index, &guid_1, string_get_size_in_bytes(name_1),
114 					(const int16_t *) name_1.data(), &status);
115 	POINTERS_EQUAL(NULL, info);
116 	UNSIGNED_LONGLONGS_EQUAL(EFI_INVALID_PARAMETER, status);
117 
118 	/* Remove should silently return */
119 	variable_index_clear_variable(&m_variable_index, info);
120 }
121 
TEST(UefiVariableIndexTests,addWithOversizedName)122 TEST(UefiVariableIndexTests, addWithOversizedName)
123 {
124 	struct variable_info *info = NULL;
125 	std::u16string name;
126 
127 	name = to_variable_name(
128 		u"a long variable name that exceeds the length limit with a few chars");
129 
130 	info = variable_index_add_entry(&m_variable_index, &guid_1, string_get_size_in_bytes(name),
131 					(int16_t *) name.data());
132 
133 	/* Expect the add to fail because of an oversized name */
134 	POINTERS_EQUAL(NULL, info);
135 
136 	name = to_variable_name(u"a long variable name that fits!");
137 
138 	info = variable_index_add_entry(&m_variable_index, &guid_1, string_get_size_in_bytes(name),
139 					(int16_t *) name.data());
140 
141 	/* Expect the add succeed */
142 	CHECK_TRUE(info);
143 }
144 
TEST(UefiVariableIndexTests,variableIndexFull)145 TEST(UefiVariableIndexTests, variableIndexFull)
146 {
147 	struct variable_info *info = NULL;
148 	EFI_GUID guid = guid_1;
149 
150 	/* Expect to be able to fill the index */
151 	for (size_t i = 0; i < MAX_VARIABLES; ++i) {
152 		info = variable_index_add_entry(&m_variable_index, &guid,
153 						string_get_size_in_bytes(name_1), (int16_t *) name_1.data());
154 
155 		CHECK_TRUE(info);
156 
157 		/* Modify the guid for the next add */
158 		guid.Data1 += 1;
159 	}
160 
161 	/* Variable index should now be full */
162 	info = variable_index_add_entry(&m_variable_index, &guid, string_get_size_in_bytes(name_1),
163 					(int16_t *) name_1.data());
164 
165 	POINTERS_EQUAL(NULL, info);
166 }
167 
TEST(UefiVariableIndexTests,enumerateStore)168 TEST(UefiVariableIndexTests, enumerateStore)
169 {
170 	const struct variable_info *info = NULL;
171 	efi_status_t status = EFI_NOT_FOUND;
172 
173 	create_variables();
174 
175 	info = variable_index_find_next(&m_variable_index, &guid_1,
176 					string_get_size_in_bytes(null_name), (const int16_t *) null_name.data(),
177 					&status);
178 	CHECK_TRUE(info);
179 	UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
180 	LONGS_EQUAL(EFI_VARIABLE_BOOTSERVICE_ACCESS, info->metadata.attributes);
181 	MEMCMP_EQUAL(&guid_1, &info->metadata.guid, sizeof(EFI_GUID));
182 	MEMCMP_EQUAL(name_1.data(), info->metadata.name, name_1.size());
183 
184 	info = variable_index_find_next(&m_variable_index, &info->metadata.guid,
185 					info->metadata.name_size, info->metadata.name, &status);
186 	CHECK_TRUE(info);
187 	UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
188 	LONGS_EQUAL(EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
189 		    info->metadata.attributes);
190 	MEMCMP_EQUAL(&guid_2, &info->metadata.guid, sizeof(EFI_GUID));
191 	MEMCMP_EQUAL(name_2.data(), info->metadata.name, name_2.size());
192 
193 	info = variable_index_find_next(&m_variable_index, &info->metadata.guid,
194 					info->metadata.name_size, info->metadata.name, &status);
195 	CHECK_TRUE(info);
196 	UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
197 	LONGS_EQUAL(EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS |
198 			    EFI_VARIABLE_BOOTSERVICE_ACCESS,
199 		    info->metadata.attributes);
200 	MEMCMP_EQUAL(&guid_1, &info->metadata.guid, sizeof(EFI_GUID));
201 	MEMCMP_EQUAL(name_3.data(), info->metadata.name, name_3.size());
202 
203 	info = variable_index_find_next(&m_variable_index, &info->metadata.guid,
204 					info->metadata.name_size, info->metadata.name, &status);
205 	POINTERS_EQUAL(NULL, info);
206 	UNSIGNED_LONGLONGS_EQUAL(EFI_NOT_FOUND, status);
207 }
208 
TEST(UefiVariableIndexTests,dumpLoadRoadtrip)209 TEST(UefiVariableIndexTests, dumpLoadRoadtrip)
210 {
211 	uint8_t buffer[sizeof(uint32_t) +
212 		       MAX_VARIABLES * (sizeof(struct variable_metadata) + sizeof(bool))];
213 
214 	create_variables();
215 
216 	/* Expect the info for two NV variables to have been dumped */
217 	size_t dump_len = 0;
218 	bool is_dirty = false;
219 	efi_status_t status = EFI_SUCCESS;
220 
221 	status = variable_index_dump(&m_variable_index, sizeof(buffer), buffer, &dump_len,
222 				     &is_dirty);
223 
224 	CHECK_TRUE(is_dirty);
225 	UNSIGNED_LONGS_EQUAL(EFI_SUCCESS, status);
226 	/*
227 	 * Variable index counter is at the beginning, which is followed by metadata and
228 	 * constraint status byte of both NV variables
229 	 */
230 	UNSIGNED_LONGS_EQUAL(sizeof(uint32_t) +
231 				     ((sizeof(struct variable_metadata) + sizeof(bool)) * 2),
232 			     dump_len);
233 
234 	/* Expect no records to be dirty when the dump is repeated */
235 	dump_len = 0;
236 	status = variable_index_dump(&m_variable_index, sizeof(buffer), buffer, &dump_len,
237 				     &is_dirty);
238 
239 	UNSIGNED_LONGS_EQUAL(EFI_SUCCESS, status);
240 	CHECK_FALSE(is_dirty);
241 	UNSIGNED_LONGS_EQUAL(sizeof(uint32_t) +
242 				     ((sizeof(struct variable_metadata) + sizeof(bool)) * 2),
243 			     dump_len);
244 
245 	/* Tear down and reinitialize to simulate a reboot */
246 	variable_index_deinit(&m_variable_index);
247 	status = variable_index_init(&m_variable_index, MAX_VARIABLES);
248 	UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
249 
250 	/* Load the dumped contents */
251 	size_t load_len = variable_index_restore(&m_variable_index, dump_len, buffer);
252 	UNSIGNED_LONGS_EQUAL(dump_len, load_len);
253 
254 	/* Enumerate and now expect only NV variables to be present */
255 	status = EFI_NOT_FOUND;
256 	const struct variable_info *info = NULL;
257 
258 	info = variable_index_find_next(&m_variable_index, &guid_1,
259 					string_get_size_in_bytes(null_name),  (const int16_t *) null_name.data(),
260 					&status);
261 	CHECK_TRUE(info);
262 	UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
263 	UNSIGNED_LONGLONGS_EQUAL(EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
264 				 info->metadata.attributes);
265 
266 	info = variable_index_find_next(&m_variable_index, &info->metadata.guid,
267 					info->metadata.name_size, info->metadata.name, &status);
268 	CHECK_TRUE(info);
269 	UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
270 	UNSIGNED_LONGLONGS_EQUAL(EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS |
271 					 EFI_VARIABLE_BOOTSERVICE_ACCESS,
272 				 info->metadata.attributes);
273 
274 	info = variable_index_find_next(&m_variable_index, &info->metadata.guid,
275 					info->metadata.name_size, info->metadata.name, &status);
276 	POINTERS_EQUAL(NULL, info);
277 	UNSIGNED_LONGLONGS_EQUAL(EFI_NOT_FOUND, status);
278 }
279 
TEST(UefiVariableIndexTests,dumpLoadConstrainedVariable)280 TEST(UefiVariableIndexTests, dumpLoadConstrainedVariable)
281 {
282 	uint8_t buffer[sizeof(uint32_t) +
283 		       MAX_VARIABLES * (sizeof(struct variable_metadata) + sizeof(bool))];
284 
285 	create_variables();
286 
287 	struct variable_constraints constraints;
288 	constraints.revision = 10;
289 	constraints.property = VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY;
290 	constraints.attributes = 0;
291 	constraints.min_size = 1;
292 	constraints.max_size = 100;
293 
294 	/* Set check constraints on one of the variables */
295 	struct variable_info *info = variable_index_find(&m_variable_index, &guid_2,
296 							 string_get_size_in_bytes(name_2),
297 							 (const int16_t *)name_2.data());
298 
299 	CHECK_TRUE(info);
300 	CHECK_TRUE(info->is_variable_set);
301 	CHECK_FALSE(info->is_constraints_set);
302 
303 	variable_index_set_constraints(info, &constraints);
304 
305 	CHECK_TRUE(info->is_constraints_set);
306 	CHECK_TRUE(info->is_variable_set);
307 
308 	size_t dump_len = 0;
309 	bool is_dirty = false;
310 	efi_status_t status = EFI_SUCCESS;
311 	status = variable_index_dump(&m_variable_index, sizeof(buffer), buffer, &dump_len,
312 				     &is_dirty);
313 
314 	UNSIGNED_LONGS_EQUAL(EFI_SUCCESS, status);
315 	CHECK_TRUE(is_dirty);
316 
317 	/*
318 	 * Variable index counter is at the beginning, which is followed by metadata and
319 	 * constraint status byte of both NV variables, but only one of them has
320 	 * constraints
321 	 */
322 	UNSIGNED_LONGS_EQUAL(sizeof(uint32_t) +
323 				     (sizeof(struct variable_metadata) + sizeof(bool)) * 2 +
324 				     sizeof(struct variable_constraints),
325 			     dump_len);
326 
327 	/* Load the dumped contents */
328 	size_t load_len = variable_index_restore(&m_variable_index, dump_len, buffer);
329 	UNSIGNED_LONGS_EQUAL(dump_len, load_len);
330 }
331 
TEST(UefiVariableIndexTests,dumpBufferTooSmall)332 TEST(UefiVariableIndexTests, dumpBufferTooSmall)
333 {
334 	/*
335 	 * Enough to fit the variable index counter and the metadata and constraint
336 	 * status of a single variable
337 	 */
338 	uint8_t buffer[sizeof(uint32_t) + sizeof(struct variable_metadata) + sizeof(bool)];
339 
340 	create_variables();
341 
342 	/* There should be two NV variables whose info needs saving. The buffer provided
343 	 * however is only big enough for one. Expect the dumped data length to not
344 	 * exceed the length of the buffer.
345 	 */
346 	size_t dump_len = 0;
347 	bool is_dirty = false;
348 	efi_status_t status = EFI_SUCCESS;
349 
350 	status = variable_index_dump(&m_variable_index, sizeof(buffer), buffer, &dump_len,
351 				     &is_dirty);
352 
353 	CHECK_TRUE(is_dirty);
354 	UNSIGNED_LONGS_EQUAL(EFI_BUFFER_TOO_SMALL, status);
355 	UNSIGNED_LONGS_EQUAL(0, dump_len);
356 }
357 
TEST(UefiVariableIndexTests,removeVariable)358 TEST(UefiVariableIndexTests, removeVariable)
359 {
360 	uint8_t buffer[sizeof(uint32_t) +
361 		       MAX_VARIABLES * (sizeof(struct variable_metadata) + sizeof(bool))];
362 	struct variable_info *info = NULL;
363 
364 	create_variables();
365 
366 	/* Remove one of the NV variables */
367 	info = variable_index_find(&m_variable_index, &guid_2, string_get_size_in_bytes(name_2),
368 				   (const int16_t *) name_2.data());
369 
370 	variable_index_clear_variable(&m_variable_index, info);
371 
372 	/* Expect index to be dirty and for only one NV variable to be left */
373 	size_t dump_len = 0;
374 	bool is_dirty = false;
375 	efi_status_t status = EFI_SUCCESS;
376 	status = variable_index_dump(&m_variable_index, sizeof(buffer), buffer, &dump_len,
377 				     &is_dirty);
378 
379 	CHECK_TRUE(is_dirty);
380 	UNSIGNED_LONGS_EQUAL(EFI_SUCCESS, status);
381 	/*
382 	 * Dump to now contains the variable index counter and metadata,
383 	 * constraint status data of a variable
384 	 */
385 	UNSIGNED_LONGS_EQUAL(sizeof(uint32_t) + sizeof(struct variable_metadata) + sizeof(bool),
386 			     dump_len);
387 
388 	/* Remove the volatile variable */
389 	info = variable_index_find(&m_variable_index, &guid_1, string_get_size_in_bytes(name_1),
390 				   (const int16_t *) name_1.data());
391 
392 	variable_index_clear_variable(&m_variable_index, info);
393 
394 	/* Expect index not to be dirty because there was no change to any NV variable */
395 	dump_len = 0;
396 	status = variable_index_dump(&m_variable_index, sizeof(buffer), buffer, &dump_len,
397 				     &is_dirty);
398 
399 	CHECK_FALSE(is_dirty);
400 	UNSIGNED_LONGS_EQUAL(EFI_SUCCESS, status);
401 	UNSIGNED_LONGS_EQUAL(sizeof(uint32_t) + sizeof(struct variable_metadata) + sizeof(bool),
402 			     dump_len);
403 
404 	/* Remove the remaining NV variable */
405 	info = variable_index_find(&m_variable_index, &guid_1, string_get_size_in_bytes(name_3),
406 				   (const int16_t *) name_3.data());
407 
408 	variable_index_clear_variable(&m_variable_index, info);
409 
410 	/* Expect index to be dirty and dump to now contains only the variable index counter */
411 	dump_len = 0;
412 	status = variable_index_dump(&m_variable_index, sizeof(buffer), buffer, &dump_len,
413 				     &is_dirty);
414 
415 	CHECK_TRUE(is_dirty);
416 	UNSIGNED_LONGS_EQUAL(EFI_SUCCESS, status);
417 	UNSIGNED_LONGS_EQUAL(sizeof(uint32_t), dump_len);
418 
419 	/* Enumerate and now expect an empty index */
420 	info = NULL;
421 
422 	info = variable_index_find_next(&m_variable_index, &guid_1,
423 					string_get_size_in_bytes(null_name),  (const int16_t *) null_name.data(),
424 					&status);
425 	POINTERS_EQUAL(NULL, info);
426 	UNSIGNED_LONGLONGS_EQUAL(EFI_NOT_FOUND, status);
427 }
428 
TEST(UefiVariableIndexTests,checkIterator)429 TEST(UefiVariableIndexTests, checkIterator)
430 {
431 	struct variable_info *info = NULL;
432 
433 	create_variables();
434 
435 	struct variable_index_iterator iter;
436 
437 	variable_index_iterator_first(&iter, &m_variable_index);
438 	CHECK_FALSE(variable_index_iterator_is_done(&iter));
439 
440 	/* Check first entry is as expected */
441 	info = variable_index_iterator_current(&iter);
442 	CHECK_TRUE(info);
443 	UNSIGNED_LONGS_EQUAL(string_get_size_in_bytes(name_1), info->metadata.name_size);
444 	MEMCMP_EQUAL(name_1.data(), info->metadata.name, info->metadata.name_size);
445 
446 	variable_index_iterator_next(&iter);
447 	CHECK_FALSE(variable_index_iterator_is_done(&iter));
448 
449 	/* Check next is as expected */
450 	info = variable_index_iterator_current(&iter);
451 	CHECK_TRUE(info);
452 	UNSIGNED_LONGS_EQUAL(string_get_size_in_bytes(name_2), info->metadata.name_size);
453 	MEMCMP_EQUAL(name_2.data(), info->metadata.name, info->metadata.name_size);
454 
455 	struct variable_info *info_to_remove = info;
456 
457 	variable_index_iterator_next(&iter);
458 	CHECK_FALSE(variable_index_iterator_is_done(&iter));
459 
460 	/* Check next is as expected */
461 	info = variable_index_iterator_current(&iter);
462 	CHECK_TRUE(info);
463 	UNSIGNED_LONGS_EQUAL(string_get_size_in_bytes(name_3), info->metadata.name_size);
464 	MEMCMP_EQUAL(name_3.data(), info->metadata.name, info->metadata.name_size);
465 
466 	/* Expect iterating to be done */
467 	variable_index_iterator_next(&iter);
468 	CHECK_TRUE(variable_index_iterator_is_done(&iter));
469 
470 	/* Now remove the middle entry */
471 	variable_index_clear_variable(&m_variable_index, info_to_remove);
472 	variable_index_remove_unused_entry(&m_variable_index, info_to_remove);
473 
474 	/* Iterate again but this time there should only be two entries */
475 	variable_index_iterator_first(&iter, &m_variable_index);
476 	CHECK_FALSE(variable_index_iterator_is_done(&iter));
477 
478 	/* Check first entry is as expected */
479 	info = variable_index_iterator_current(&iter);
480 	CHECK_TRUE(info);
481 	UNSIGNED_LONGS_EQUAL(string_get_size_in_bytes(name_1), info->metadata.name_size);
482 	MEMCMP_EQUAL(name_1.data(), info->metadata.name, info->metadata.name_size);
483 
484 	variable_index_iterator_next(&iter);
485 	CHECK_FALSE(variable_index_iterator_is_done(&iter));
486 
487 	/* Check next entry is as expected */
488 	info = variable_index_iterator_current(&iter);
489 	CHECK_TRUE(info);
490 	UNSIGNED_LONGS_EQUAL(string_get_size_in_bytes(name_3), info->metadata.name_size);
491 	MEMCMP_EQUAL(name_3.data(), info->metadata.name, info->metadata.name_size);
492 
493 	/* Expect iterating to be done */
494 	variable_index_iterator_next(&iter);
495 	CHECK_TRUE(variable_index_iterator_is_done(&iter));
496 }
497 
TEST(UefiVariableIndexTests,setCheckConstraintsExistingVar)498 TEST(UefiVariableIndexTests, setCheckConstraintsExistingVar)
499 {
500 	/* Variable check constraints are set using an independent SMM
501 	 * function from setting a variable. A client may set constraints
502 	 * for an existing variable or a non-existing one. This test case
503 	 * covers setting check constraints for an existing variable.
504 	 */
505 	create_variables();
506 
507 	struct variable_constraints constraints;
508 	constraints.revision = 10;
509 	constraints.property = VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY;
510 	constraints.attributes = 0;
511 	constraints.min_size = 1;
512 	constraints.max_size = 100;
513 
514 	/* Set check constraints on one of the variables */
515 	struct variable_info *info = variable_index_find(
516 		&m_variable_index, &guid_2, string_get_size_in_bytes(name_2), (const int16_t *) name_2.data());
517 
518 	CHECK_TRUE(info);
519 	CHECK_TRUE(info->is_variable_set);
520 	CHECK_FALSE(info->is_constraints_set);
521 
522 	variable_index_set_constraints(info, &constraints);
523 
524 	CHECK_TRUE(info->is_constraints_set);
525 	CHECK_TRUE(info->is_variable_set);
526 
527 	/* Remove the variable but still expect the variable to be indexed
528 	 * because of the set constraints.
529 	 */
530 	variable_index_clear_variable(&m_variable_index, info);
531 
532 	info = variable_index_find(&m_variable_index, &guid_2, string_get_size_in_bytes(name_2),
533 				   (const int16_t *) name_2.data());
534 
535 	CHECK_TRUE(info);
536 	CHECK_FALSE(info->is_variable_set);
537 	CHECK_TRUE(info->is_constraints_set);
538 
539 	/* Enumerate over variables, only expecting to find the two remaining 'set' variables. */
540 	info = NULL;
541 	efi_status_t status = EFI_NOT_FOUND;
542 
543 	info = variable_index_find_next(&m_variable_index, &guid_1,
544 					string_get_size_in_bytes(null_name),  (const int16_t *) null_name.data(),
545 					&status);
546 	CHECK_TRUE(info);
547 	UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
548 	UNSIGNED_LONGLONGS_EQUAL(EFI_VARIABLE_BOOTSERVICE_ACCESS, info->metadata.attributes);
549 
550 	info = variable_index_find_next(&m_variable_index, &info->metadata.guid,
551 					info->metadata.name_size, info->metadata.name, &status);
552 	CHECK_TRUE(info);
553 	UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
554 	UNSIGNED_LONGLONGS_EQUAL(EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS |
555 					 EFI_VARIABLE_BOOTSERVICE_ACCESS,
556 				 info->metadata.attributes);
557 
558 	info = variable_index_find_next(&m_variable_index, &info->metadata.guid,
559 					info->metadata.name_size, info->metadata.name, &status);
560 	CHECK_FALSE(info);
561 	UNSIGNED_LONGLONGS_EQUAL(EFI_NOT_FOUND, status);
562 
563 	/* Iterating over the index should still return all three because the set constraints
564 	 * for variable 2 still persist.
565 	 */
566 	struct variable_index_iterator iter;
567 
568 	variable_index_iterator_first(&iter, &m_variable_index);
569 	CHECK_FALSE(variable_index_iterator_is_done(&iter));
570 
571 	/* Check first entry is as expected */
572 	info = variable_index_iterator_current(&iter);
573 	CHECK_TRUE(info);
574 	UNSIGNED_LONGS_EQUAL(string_get_size_in_bytes(name_1), info->metadata.name_size);
575 	MEMCMP_EQUAL(name_1.data(), info->metadata.name, info->metadata.name_size);
576 
577 	variable_index_iterator_next(&iter);
578 	CHECK_FALSE(variable_index_iterator_is_done(&iter));
579 
580 	/* Check next is as expected */
581 	info = variable_index_iterator_current(&iter);
582 	CHECK_TRUE(info);
583 	UNSIGNED_LONGS_EQUAL(string_get_size_in_bytes(name_2), info->metadata.name_size);
584 	MEMCMP_EQUAL(name_2.data(), info->metadata.name, info->metadata.name_size);
585 
586 	variable_index_iterator_next(&iter);
587 	CHECK_FALSE(variable_index_iterator_is_done(&iter));
588 
589 	/* Check next is as expected */
590 	info = variable_index_iterator_current(&iter);
591 	CHECK_TRUE(info);
592 	UNSIGNED_LONGS_EQUAL(string_get_size_in_bytes(name_3), info->metadata.name_size);
593 	MEMCMP_EQUAL(name_3.data(), info->metadata.name, info->metadata.name_size);
594 
595 	/* Expect iterating to be done */
596 	variable_index_iterator_next(&iter);
597 	CHECK_TRUE(variable_index_iterator_is_done(&iter));
598 }
599 
TEST(UefiVariableIndexTests,setCheckConstraintsNonExistingVar)600 TEST(UefiVariableIndexTests, setCheckConstraintsNonExistingVar)
601 {
602 	/* This test case covers setting check constraints for a variable
603 	 * that hasn't been set yet.
604 	 */
605 	struct variable_constraints constraints;
606 	constraints.revision = 10;
607 	constraints.property = VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY;
608 	constraints.attributes = 0;
609 	constraints.min_size = 1;
610 	constraints.max_size = 100;
611 
612 	/* Initially expect no variable_info */
613 	struct variable_info *info = variable_index_find(
614 		&m_variable_index, &guid_2, string_get_size_in_bytes(name_2),
615 		(const int16_t *) name_2.data());
616 
617 	CHECK_FALSE(info);
618 
619 	/* Adding the check constraints should result in an entry being added */
620 	info = variable_index_add_entry(
621 		&m_variable_index, &guid_2, string_get_size_in_bytes(name_2),
622 		(const int16_t *) name_2.data());
623 	CHECK_TRUE(info);
624 
625 	variable_index_set_constraints(info, &constraints);
626 	CHECK_FALSE(info->is_variable_set);
627 	CHECK_TRUE(info->is_constraints_set);
628 
629 	/* Updating the variable should cause the variable to be marked as set */
630 	variable_index_set_variable(info,
631 				    EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS);
632 
633 	CHECK_TRUE(info->is_variable_set);
634 	CHECK_TRUE(info->is_constraints_set);
635 
636 	/* Check the constraints are as expected */
637 	UNSIGNED_LONGS_EQUAL(constraints.revision, info->check_constraints.revision);
638 	UNSIGNED_LONGS_EQUAL(constraints.property, info->check_constraints.property);
639 	UNSIGNED_LONGS_EQUAL(constraints.attributes, info->check_constraints.attributes);
640 	UNSIGNED_LONGS_EQUAL(constraints.min_size, info->check_constraints.min_size);
641 	UNSIGNED_LONGS_EQUAL(constraints.max_size, info->check_constraints.max_size);
642 }
643