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