]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Variable/RuntimeDxe/RuntimeDxeUnitTest/VariableLockRequestToLockUnitTest.c
MdeModulePkg: Change OPTIONAL keyword usage style
[mirror_edk2.git] / MdeModulePkg / Universal / Variable / RuntimeDxe / RuntimeDxeUnitTest / VariableLockRequestToLockUnitTest.c
1 /** @file
2 This is a host-based unit test for the VariableLockRequestToLock shim.
3
4 Copyright (c) Microsoft Corporation.
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6
7 **/
8
9 #include <stdio.h>
10 #include <string.h>
11 #include <stdarg.h>
12 #include <stddef.h>
13 #include <setjmp.h>
14 #include <cmocka.h>
15
16 #include <Uefi.h>
17 #include <Library/DebugLib.h>
18 #include <Library/BaseMemoryLib.h>
19 #include <Library/MemoryAllocationLib.h>
20 #include <Library/UnitTestLib.h>
21 #include <Library/VariablePolicyLib.h>
22 #include <Library/VariablePolicyHelperLib.h>
23
24 #include <Protocol/VariableLock.h>
25
26 #define UNIT_TEST_NAME "VarPol/VarLock Shim Unit Test"
27 #define UNIT_TEST_VERSION "1.0"
28
29 ///=== CODE UNDER TEST ===========================================================================
30
31 EFI_STATUS
32 EFIAPI
33 VariableLockRequestToLock (
34 IN CONST EDKII_VARIABLE_LOCK_PROTOCOL *This,
35 IN CHAR16 *VariableName,
36 IN EFI_GUID *VendorGuid
37 );
38
39 ///=== TEST DATA ==================================================================================
40
41 //
42 // Test GUID 1 {F955BA2D-4A2C-480C-BFD1-3CC522610592}
43 //
44 EFI_GUID mTestGuid1 = {
45 0xf955ba2d, 0x4a2c, 0x480c, {0xbf, 0xd1, 0x3c, 0xc5, 0x22, 0x61, 0x5, 0x92}
46 };
47
48 //
49 // Test GUID 2 {2DEA799E-5E73-43B9-870E-C945CE82AF3A}
50 //
51 EFI_GUID mTestGuid2 = {
52 0x2dea799e, 0x5e73, 0x43b9, {0x87, 0xe, 0xc9, 0x45, 0xce, 0x82, 0xaf, 0x3a}
53 };
54
55 //
56 // Test GUID 3 {698A2BFD-A616-482D-B88C-7100BD6682A9}
57 //
58 EFI_GUID mTestGuid3 = {
59 0x698a2bfd, 0xa616, 0x482d, {0xb8, 0x8c, 0x71, 0x0, 0xbd, 0x66, 0x82, 0xa9}
60 };
61
62 #define TEST_VAR_1_NAME L"TestVar1"
63 #define TEST_VAR_2_NAME L"TestVar2"
64 #define TEST_VAR_3_NAME L"TestVar3"
65
66 #define TEST_POLICY_ATTRIBUTES_NULL 0
67 #define TEST_POLICY_MIN_SIZE_NULL 0
68 #define TEST_POLICY_MAX_SIZE_NULL MAX_UINT32
69
70 #define TEST_POLICY_MIN_SIZE_10 10
71 #define TEST_POLICY_MAX_SIZE_200 200
72
73 ///=== HELPER FUNCTIONS ===========================================================================
74
75 /**
76 Mocked version of GetVariable, for testing.
77
78 @param VariableName
79 @param VendorGuid
80 @param Attributes
81 @param DataSize
82 @param Data
83 **/
84 EFI_STATUS
85 EFIAPI
86 StubGetVariableNull (
87 IN CHAR16 *VariableName,
88 IN EFI_GUID *VendorGuid,
89 OUT UINT32 *Attributes OPTIONAL,
90 IN OUT UINTN *DataSize,
91 OUT VOID *Data OPTIONAL
92 )
93 {
94 UINT32 MockedAttr;
95 UINTN MockedDataSize;
96 VOID *MockedData;
97 EFI_STATUS MockedReturn;
98
99 check_expected_ptr (VariableName);
100 check_expected_ptr (VendorGuid);
101 check_expected_ptr (DataSize);
102
103 MockedAttr = (UINT32)mock();
104 MockedDataSize = (UINTN)mock();
105 MockedData = (VOID*)(UINTN)mock();
106 MockedReturn = (EFI_STATUS)mock();
107
108 if (Attributes != NULL) {
109 *Attributes = MockedAttr;
110 }
111 if (Data != NULL && !EFI_ERROR (MockedReturn)) {
112 CopyMem (Data, MockedData, MockedDataSize);
113 }
114
115 *DataSize = MockedDataSize;
116
117 return MockedReturn;
118 }
119
120 //
121 // Anything you think might be helpful that isn't a test itself.
122 //
123
124 /**
125 This is a common setup function that will ensure the library is always
126 initialized with the stubbed GetVariable.
127
128 Not used by all test cases, but by most.
129
130 @param[in] Context Unit test case context
131 **/
132 STATIC
133 UNIT_TEST_STATUS
134 EFIAPI
135 LibInitMocked (
136 IN UNIT_TEST_CONTEXT Context
137 )
138 {
139 return EFI_ERROR (InitVariablePolicyLib (StubGetVariableNull)) ? UNIT_TEST_ERROR_PREREQUISITE_NOT_MET : UNIT_TEST_PASSED;
140 }
141
142 /**
143 Common cleanup function to make sure that the library is always de-initialized
144 prior to the next test case.
145
146 @param[in] Context Unit test case context
147 **/
148 STATIC
149 VOID
150 EFIAPI
151 LibCleanup (
152 IN UNIT_TEST_CONTEXT Context
153 )
154 {
155 DeinitVariablePolicyLib();
156 }
157
158 ///=== TEST CASES =================================================================================
159
160 ///===== SHIM SUITE ===========================================================
161
162 /**
163 Test Case that locks a single variable using the Variable Lock Protocol.
164 The call is expected to succeed.
165
166 @param[in] Context Unit test case context
167 **/
168 UNIT_TEST_STATUS
169 EFIAPI
170 LockingWithoutAnyPoliciesShouldSucceed (
171 IN UNIT_TEST_CONTEXT Context
172 )
173 {
174 EFI_STATUS Status;
175
176 Status = VariableLockRequestToLock (NULL, TEST_VAR_1_NAME, &mTestGuid1);
177 UT_ASSERT_NOT_EFI_ERROR (Status);
178
179 return UNIT_TEST_PASSED;
180 }
181
182 /**
183 Test Case that locks the same variable twice using the Variable Lock Protocol.
184 Both calls are expected to succeed.
185
186 @param[in] Context Unit test case context
187 **/
188 UNIT_TEST_STATUS
189 EFIAPI
190 LockingTwiceShouldSucceed (
191 IN UNIT_TEST_CONTEXT Context
192 )
193 {
194 EFI_STATUS Status;
195
196 Status = VariableLockRequestToLock (NULL, TEST_VAR_1_NAME, &mTestGuid1);
197 UT_ASSERT_NOT_EFI_ERROR (Status);
198
199 Status = VariableLockRequestToLock (NULL, TEST_VAR_1_NAME, &mTestGuid1);
200 UT_ASSERT_NOT_EFI_ERROR (Status);
201
202 return UNIT_TEST_PASSED;
203 }
204
205 /**
206 Test Case that locks a variable using the Variable Policy Protocol then locks
207 the same variable using the Variable Lock Protocol.
208 Both calls are expected to succeed.
209
210 @param[in] Context Unit test case context
211 **/
212 UNIT_TEST_STATUS
213 EFIAPI
214 LockingALockedVariableShouldSucceed (
215 IN UNIT_TEST_CONTEXT Context
216 )
217 {
218 EFI_STATUS Status;
219 VARIABLE_POLICY_ENTRY *NewEntry;
220
221 //
222 // Create a variable policy that locks the variable.
223 //
224 Status = CreateBasicVariablePolicy (
225 &mTestGuid1,
226 TEST_VAR_1_NAME,
227 TEST_POLICY_MIN_SIZE_NULL,
228 TEST_POLICY_MAX_SIZE_200,
229 TEST_POLICY_ATTRIBUTES_NULL,
230 TEST_POLICY_ATTRIBUTES_NULL,
231 VARIABLE_POLICY_TYPE_LOCK_NOW,
232 &NewEntry
233 );
234 UT_ASSERT_NOT_EFI_ERROR (Status);
235
236 //
237 // Register the new policy.
238 //
239 Status = RegisterVariablePolicy (NewEntry);
240
241 Status = VariableLockRequestToLock (NULL, TEST_VAR_1_NAME, &mTestGuid1);
242 UT_ASSERT_NOT_EFI_ERROR (Status);
243
244 FreePool (NewEntry);
245
246 return UNIT_TEST_PASSED;
247 }
248
249 /**
250 Test Case that locks a variable using the Variable Policy Protocol with a
251 policy other than LOCK_NOW then attempts to lock the same variable using the
252 Variable Lock Protocol. The call to Variable Policy is expected to succeed
253 and the call to Variable Lock is expected to fail.
254
255 @param[in] Context Unit test case context
256 **/
257 UNIT_TEST_STATUS
258 EFIAPI
259 LockingAnUnlockedVariableShouldFail (
260 IN UNIT_TEST_CONTEXT Context
261 )
262 {
263 EFI_STATUS Status;
264 VARIABLE_POLICY_ENTRY *NewEntry;
265
266 // Create a variable policy that locks the variable.
267 Status = CreateVarStateVariablePolicy (&mTestGuid1,
268 TEST_VAR_1_NAME,
269 TEST_POLICY_MIN_SIZE_NULL,
270 TEST_POLICY_MAX_SIZE_200,
271 TEST_POLICY_ATTRIBUTES_NULL,
272 TEST_POLICY_ATTRIBUTES_NULL,
273 &mTestGuid2,
274 1,
275 TEST_VAR_2_NAME,
276 &NewEntry);
277 UT_ASSERT_NOT_EFI_ERROR (Status);
278
279 // Register the new policy.
280 Status = RegisterVariablePolicy (NewEntry);
281
282 // Configure the stub to not care about parameters. We're testing errors.
283 expect_any_always( StubGetVariableNull, VariableName );
284 expect_any_always( StubGetVariableNull, VendorGuid );
285 expect_any_always( StubGetVariableNull, DataSize );
286
287 // With a policy, make sure that writes still work, since the variable doesn't exist.
288 will_return( StubGetVariableNull, TEST_POLICY_ATTRIBUTES_NULL ); // Attributes
289 will_return( StubGetVariableNull, 0 ); // Size
290 will_return( StubGetVariableNull, (UINTN)NULL ); // DataPtr
291 will_return( StubGetVariableNull, EFI_NOT_FOUND); // Status
292
293 Status = VariableLockRequestToLock (NULL, TEST_VAR_1_NAME, &mTestGuid1);
294 UT_ASSERT_TRUE (EFI_ERROR (Status));
295
296 FreePool (NewEntry);
297
298 return UNIT_TEST_PASSED;
299 }
300
301 /**
302 Test Case that locks a variable using the Variable Policy Protocol with a
303 policy other than LOCK_NOW, but is currently locked. Then attempts to lock
304 the same variable using the Variable Lock Protocol. The call to Variable
305 Policy is expected to succeed and the call to Variable Lock also expected to
306 succeed.
307
308 @param[in] Context Unit test case context
309 **/
310 UNIT_TEST_STATUS
311 EFIAPI
312 LockingALockedVariableWithMatchingDataShouldSucceed (
313 IN UNIT_TEST_CONTEXT Context
314 )
315 {
316 EFI_STATUS Status;
317 VARIABLE_POLICY_ENTRY *NewEntry;
318 UINT8 Data;
319
320 // Create a variable policy that locks the variable.
321 Status = CreateVarStateVariablePolicy (&mTestGuid1,
322 TEST_VAR_1_NAME,
323 TEST_POLICY_MIN_SIZE_NULL,
324 TEST_POLICY_MAX_SIZE_200,
325 TEST_POLICY_ATTRIBUTES_NULL,
326 TEST_POLICY_ATTRIBUTES_NULL,
327 &mTestGuid2,
328 1,
329 TEST_VAR_2_NAME,
330 &NewEntry);
331 UT_ASSERT_NOT_EFI_ERROR (Status);
332
333 // Register the new policy.
334 Status = RegisterVariablePolicy (NewEntry);
335
336 // Configure the stub to not care about parameters. We're testing errors.
337 expect_any_always( StubGetVariableNull, VariableName );
338 expect_any_always( StubGetVariableNull, VendorGuid );
339 expect_any_always( StubGetVariableNull, DataSize );
340
341 // With a policy, make sure that writes still work, since the variable doesn't exist.
342 Data = 1;
343 will_return( StubGetVariableNull, TEST_POLICY_ATTRIBUTES_NULL ); // Attributes
344 will_return( StubGetVariableNull, sizeof (Data) ); // Size
345 will_return( StubGetVariableNull, (UINTN)&Data ); // DataPtr
346 will_return( StubGetVariableNull, EFI_SUCCESS); // Status
347
348 Status = VariableLockRequestToLock (NULL, TEST_VAR_1_NAME, &mTestGuid1);
349 UT_ASSERT_TRUE (!EFI_ERROR (Status));
350
351 FreePool (NewEntry);
352
353 return UNIT_TEST_PASSED;
354 }
355
356 /**
357 Test Case that locks a variable using the Variable Policy Protocol with a
358 policy other than LOCK_NOW, but variable data does not match. Then attempts
359 to lock the same variable using the Variable Lock Protocol. The call to
360 Variable Policy is expected to succeed and the call to Variable Lock is
361 expected to fail.
362
363 @param[in] Context Unit test case context
364 **/
365 UNIT_TEST_STATUS
366 EFIAPI
367 LockingALockedVariableWithNonMatchingDataShouldFail (
368 IN UNIT_TEST_CONTEXT Context
369 )
370 {
371 EFI_STATUS Status;
372 VARIABLE_POLICY_ENTRY *NewEntry;
373 UINT8 Data;
374
375 // Create a variable policy that locks the variable.
376 Status = CreateVarStateVariablePolicy (&mTestGuid1,
377 TEST_VAR_1_NAME,
378 TEST_POLICY_MIN_SIZE_NULL,
379 TEST_POLICY_MAX_SIZE_200,
380 TEST_POLICY_ATTRIBUTES_NULL,
381 TEST_POLICY_ATTRIBUTES_NULL,
382 &mTestGuid2,
383 1,
384 TEST_VAR_2_NAME,
385 &NewEntry);
386 UT_ASSERT_NOT_EFI_ERROR (Status);
387
388 // Register the new policy.
389 Status = RegisterVariablePolicy (NewEntry);
390
391 // Configure the stub to not care about parameters. We're testing errors.
392 expect_any_always( StubGetVariableNull, VariableName );
393 expect_any_always( StubGetVariableNull, VendorGuid );
394 expect_any_always( StubGetVariableNull, DataSize );
395
396 // With a policy, make sure that writes still work, since the variable doesn't exist.
397 Data = 2;
398 will_return( StubGetVariableNull, TEST_POLICY_ATTRIBUTES_NULL ); // Attributes
399 will_return( StubGetVariableNull, sizeof (Data) ); // Size
400 will_return( StubGetVariableNull, (UINTN)&Data ); // DataPtr
401 will_return( StubGetVariableNull, EFI_SUCCESS); // Status
402
403 Status = VariableLockRequestToLock (NULL, TEST_VAR_1_NAME, &mTestGuid1);
404 UT_ASSERT_TRUE (EFI_ERROR (Status));
405
406 FreePool (NewEntry);
407
408 return UNIT_TEST_PASSED;
409 }
410
411 /**
412 Test Case that locks a variable using Variable Lock Protocol Policy Protocol
413 then and then attempts to lock the same variable using the Variable Policy
414 Protocol. The call to Variable Lock is expected to succeed and the call to
415 Variable Policy is expected to fail.
416
417 @param[in] Context Unit test case context
418 **/
419 UNIT_TEST_STATUS
420 EFIAPI
421 SettingPolicyForALockedVariableShouldFail (
422 IN UNIT_TEST_CONTEXT Context
423 )
424 {
425 EFI_STATUS Status;
426 VARIABLE_POLICY_ENTRY *NewEntry;
427
428 // Lock the variable.
429 Status = VariableLockRequestToLock (NULL, TEST_VAR_1_NAME, &mTestGuid1);
430 UT_ASSERT_NOT_EFI_ERROR (Status);
431
432 // Create a variable policy that locks the variable.
433 Status = CreateVarStateVariablePolicy (&mTestGuid1,
434 TEST_VAR_1_NAME,
435 TEST_POLICY_MIN_SIZE_NULL,
436 TEST_POLICY_MAX_SIZE_200,
437 TEST_POLICY_ATTRIBUTES_NULL,
438 TEST_POLICY_ATTRIBUTES_NULL,
439 &mTestGuid2,
440 1,
441 TEST_VAR_2_NAME,
442 &NewEntry);
443 UT_ASSERT_NOT_EFI_ERROR (Status);
444
445 // Register the new policy.
446 Status = RegisterVariablePolicy (NewEntry);
447 UT_ASSERT_TRUE (EFI_ERROR (Status));
448
449 FreePool (NewEntry);
450
451 return UNIT_TEST_PASSED;
452 }
453
454 /**
455 Main entry point to this unit test application.
456
457 Sets up and runs the test suites.
458 **/
459 VOID
460 EFIAPI
461 UnitTestMain (
462 VOID
463 )
464 {
465 EFI_STATUS Status;
466 UNIT_TEST_FRAMEWORK_HANDLE Framework;
467 UNIT_TEST_SUITE_HANDLE ShimTests;
468
469 Framework = NULL;
470
471 DEBUG ((DEBUG_INFO, "%a v%a\n", UNIT_TEST_NAME, UNIT_TEST_VERSION));
472
473 //
474 // Start setting up the test framework for running the tests.
475 //
476 Status = InitUnitTestFramework (&Framework, UNIT_TEST_NAME, gEfiCallerBaseName, UNIT_TEST_VERSION);
477 if (EFI_ERROR (Status)) {
478 DEBUG ((DEBUG_ERROR, "Failed in InitUnitTestFramework. Status = %r\n", Status));
479 goto EXIT;
480 }
481
482 //
483 // Add all test suites and tests.
484 //
485 Status = CreateUnitTestSuite (
486 &ShimTests, Framework,
487 "Variable Lock Shim Tests", "VarPolicy.VarLockShim", NULL, NULL
488 );
489 if (EFI_ERROR (Status)) {
490 DEBUG ((DEBUG_ERROR, "Failed in CreateUnitTestSuite for ShimTests\n"));
491 Status = EFI_OUT_OF_RESOURCES;
492 goto EXIT;
493 }
494 AddTestCase (
495 ShimTests,
496 "Locking a variable with no matching policies should always work", "EmptyPolicies",
497 LockingWithoutAnyPoliciesShouldSucceed, LibInitMocked, LibCleanup, NULL
498 );
499 AddTestCase (
500 ShimTests,
501 "Locking a variable twice should always work", "DoubleLock",
502 LockingTwiceShouldSucceed, LibInitMocked, LibCleanup, NULL
503 );
504 AddTestCase (
505 ShimTests,
506 "Locking a variable that's already locked by another policy should work", "LockAfterPolicy",
507 LockingALockedVariableShouldSucceed, LibInitMocked, LibCleanup, NULL
508 );
509 AddTestCase (
510 ShimTests,
511 "Locking a variable that already has an unlocked policy should fail", "LockAfterUnlockedPolicy",
512 LockingAnUnlockedVariableShouldFail, LibInitMocked, LibCleanup, NULL
513 );
514 AddTestCase (
515 ShimTests,
516 "Locking a variable that already has an locked policy should succeed", "LockAfterLockedPolicyMatchingData",
517 LockingALockedVariableWithMatchingDataShouldSucceed, LibInitMocked, LibCleanup, NULL
518 );
519 AddTestCase (
520 ShimTests,
521 "Locking a variable that already has an locked policy with matching data should succeed", "LockAfterLockedPolicyNonMatchingData",
522 LockingALockedVariableWithNonMatchingDataShouldFail, LibInitMocked, LibCleanup, NULL
523 );
524 AddTestCase (
525 ShimTests,
526 "Adding a policy for a variable that has previously been locked should always fail", "SetPolicyAfterLock",
527 SettingPolicyForALockedVariableShouldFail, LibInitMocked, LibCleanup, NULL
528 );
529
530 //
531 // Execute the tests.
532 //
533 Status = RunAllTestSuites (Framework);
534
535 EXIT:
536 if (Framework != NULL) {
537 FreeUnitTestFramework (Framework);
538 }
539
540 return;
541 }
542
543 ///
544 /// Avoid ECC error for function name that starts with lower case letter
545 ///
546 #define Main main
547
548 /**
549 Standard POSIX C entry point for host based unit test execution.
550
551 @param[in] Argc Number of arguments
552 @param[in] Argv Array of pointers to arguments
553
554 @retval 0 Success
555 @retval other Error
556 **/
557 INT32
558 Main (
559 IN INT32 Argc,
560 IN CHAR8 *Argv[]
561 )
562 {
563 UnitTestMain ();
564 return 0;
565 }