1 /** @file -- VariablePolicyLib.c
2 Business logic for Variable Policy enforcement.
4 Copyright (c) Microsoft Corporation.
5 SPDX-License-Identifier: BSD-2-Clause-Patent
11 #include <Library/SafeIntLib.h>
12 #include <Library/MemoryAllocationLib.h>
13 #include <Library/BaseMemoryLib.h>
14 #include <Library/DebugLib.h>
15 #include <Library/PcdLib.h>
17 #include <Protocol/VariablePolicy.h>
18 #include <Library/VariablePolicyLib.h>
20 // IMPORTANT NOTE: This library is currently rife with multiple return statements
21 // for error handling. A refactor should remove these at some point.
24 // This library was designed with advanced unit-test features.
25 // This define handles the configuration.
26 #ifdef INTERNAL_UNIT_TEST
28 #define STATIC // Nothing...
31 // An abstracted GetVariable interface that enables configuration regardless of the environment.
32 EFI_GET_VARIABLE mGetVariableHelper
= NULL
;
34 // Master switch to lock this entire interface. Does not stop enforcement,
35 // just prevents the configuration from being changed for the rest of the boot.
36 STATIC BOOLEAN mInterfaceLocked
= FALSE
;
38 // Master switch to disable the entire interface for a single boot.
39 // This will disable all policy enforcement for the duration of the boot.
40 STATIC BOOLEAN mProtectionDisabled
= FALSE
;
42 // Table to hold all the current policies.
43 UINT8
*mPolicyTable
= NULL
;
44 STATIC UINT32 mCurrentTableSize
= 0;
45 STATIC UINT32 mCurrentTableUsage
= 0;
46 STATIC UINT32 mCurrentTableCount
= 0;
48 #define POLICY_TABLE_STEP_SIZE 0x1000
50 // NOTE: DO NOT USE THESE MACROS on any structure that has not been validated.
51 // Current table data has already been sanitized.
52 #define GET_NEXT_POLICY(CurPolicy) (VARIABLE_POLICY_ENTRY*)((UINT8*)CurPolicy + CurPolicy->Size)
53 #define GET_POLICY_NAME(CurPolicy) (CHAR16*)((UINTN)CurPolicy + CurPolicy->OffsetToName)
55 #define MATCH_PRIORITY_EXACT 0
56 #define MATCH_PRIORITY_MAX MATCH_PRIORITY_EXACT
57 #define MATCH_PRIORITY_MIN MAX_UINT8
60 An extra init hook that enables the RuntimeDxe library instance to
61 register VirtualAddress change callbacks. Among other things.
63 @retval EFI_SUCCESS Everything is good. Continue with init.
64 @retval Others Uh... don't continue.
68 VariablePolicyExtraInit (
73 An extra deinit hook that enables the RuntimeDxe library instance to
74 register VirtualAddress change callbacks. Among other things.
76 @retval EFI_SUCCESS Everything is good. Continue with deinit.
77 @retval Others Uh... don't continue.
81 VariablePolicyExtraDeinit (
86 This helper function determines whether the structure of an incoming policy
87 is valid and internally consistent.
89 @param[in] NewPolicy Pointer to the incoming policy structure.
92 @retval FALSE Pointer is NULL, size is wrong, strings are empty, or
93 substructures overlap.
98 IsValidVariablePolicyStructure (
99 IN CONST VARIABLE_POLICY_ENTRY
*NewPolicy
107 // Sanitize some quick values.
108 if ((NewPolicy
== NULL
) || (NewPolicy
->Size
== 0) ||
109 // Structure size should be at least as long as the minumum structure and a NULL string.
110 (NewPolicy
->Size
< sizeof (VARIABLE_POLICY_ENTRY
)) ||
111 // Check for the known revision.
112 (NewPolicy
->Version
!= VARIABLE_POLICY_ENTRY_REVISION
))
117 // Calculate the theoretical end of the structure and make sure
118 // that the structure can fit in memory.
119 Status
= SafeUintnAdd ((UINTN
)NewPolicy
, NewPolicy
->Size
, &EntryEnd
);
120 if (EFI_ERROR (Status
)) {
124 // Check for a valid Max Size.
125 if (NewPolicy
->MaxSize
== 0) {
129 // Check for the valid list of lock policies.
130 if ((NewPolicy
->LockPolicyType
!= VARIABLE_POLICY_TYPE_NO_LOCK
) &&
131 (NewPolicy
->LockPolicyType
!= VARIABLE_POLICY_TYPE_LOCK_NOW
) &&
132 (NewPolicy
->LockPolicyType
!= VARIABLE_POLICY_TYPE_LOCK_ON_CREATE
) &&
133 (NewPolicy
->LockPolicyType
!= VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE
))
138 // If the policy type is VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE, make sure that the matching state variable Name
139 // terminates before the OffsetToName for the matching policy variable Name.
140 if (NewPolicy
->LockPolicyType
== VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE
) {
141 // Adjust CheckChar to the offset of the LockPolicy->Name.
142 Status
= SafeUintnAdd (
143 (UINTN
)NewPolicy
+ sizeof (VARIABLE_POLICY_ENTRY
),
144 sizeof (VARIABLE_LOCK_ON_VAR_STATE_POLICY
),
147 if (EFI_ERROR (Status
) || (EntryEnd
<= (UINTN
)CheckChar
)) {
151 while (*CheckChar
!= CHAR_NULL
) {
152 if (EntryEnd
<= (UINTN
)CheckChar
) {
159 // At this point we should have either exeeded the structure or be pointing at the last char in LockPolicy->Name.
160 // We should check to make sure that the policy Name comes immediately after this charcter.
161 if ((UINTN
)++ CheckChar
!= (UINTN
)NewPolicy
+ NewPolicy
->OffsetToName
) {
165 // If the policy type is any other value, make sure that the LockPolicy structure has a zero length.
167 if (NewPolicy
->OffsetToName
!= sizeof (VARIABLE_POLICY_ENTRY
)) {
172 // Check to make sure that the name has a terminating character
173 // before the end of the structure.
174 // We've already checked that the name is within the bounds of the structure.
175 if (NewPolicy
->Size
!= NewPolicy
->OffsetToName
) {
176 CheckChar
= (CHAR16
*)((UINTN
)NewPolicy
+ NewPolicy
->OffsetToName
);
178 while (*CheckChar
!= CHAR_NULL
) {
179 // Make sure there aren't excessive wildcards.
180 if (*CheckChar
== '#') {
182 if (WildcardCount
> MATCH_PRIORITY_MIN
) {
187 // Make sure you're still within the bounds of the policy structure.
188 if (EntryEnd
<= (UINTN
)CheckChar
) {
195 // Finally, we should be pointed at the very last character in Name, so we should be right
196 // up against the end of the structure.
197 if ((UINTN
)++ CheckChar
!= EntryEnd
) {
206 This helper function evaluates a policy and determines whether it matches the target
207 variable. If matched, will also return a value corresponding to the priority of the match.
209 The rules for "best match" are listed in the Variable Policy Spec.
210 Perfect name matches will return 0.
211 Single wildcard characters will return the number of wildcard characters.
212 Full namespaces will return MAX_UINT8.
214 @param[in] EvalEntry Pointer to the policy entry being evaluated.
215 @param[in] VariableName Same as EFI_SET_VARIABLE.
216 @param[in] VendorGuid Same as EFI_SET_VARIABLE.
217 @param[out] MatchPriority [Optional] On finding a match, this value contains the priority of the match.
218 Lower number == higher priority. Only valid if a match found.
220 @retval TRUE Current entry matches the target variable.
221 @retval FALSE Current entry does not match at all.
226 EvaluatePolicyMatch (
227 IN CONST VARIABLE_POLICY_ENTRY
*EvalEntry
,
228 IN CONST CHAR16
*VariableName
,
229 IN CONST EFI_GUID
*VendorGuid
,
230 OUT UINT8
*MatchPriority OPTIONAL
235 UINT8 CalculatedPriority
;
239 CalculatedPriority
= MATCH_PRIORITY_EXACT
;
241 // Step 1: If the GUID doesn't match, we're done. No need to evaluate anything else.
242 if (!CompareGuid (&EvalEntry
->Namespace
, VendorGuid
)) {
246 // If the GUID matches, check to see whether there is a Name associated
247 // with the policy. If not, this policy matches the entire namespace.
248 // Missing Name is indicated by size being equal to name.
249 if (EvalEntry
->Size
== EvalEntry
->OffsetToName
) {
250 CalculatedPriority
= MATCH_PRIORITY_MIN
;
255 // Now that we know the name exists, get it.
256 PolicyName
= GET_POLICY_NAME (EvalEntry
);
258 // Evaluate the name against the policy name and check for a match.
259 // Account for any wildcards.
262 // Keep going until the end of both strings.
263 while (PolicyName
[Index
] != CHAR_NULL
|| VariableName
[Index
] != CHAR_NULL
) {
264 // If we don't have a match...
265 if ((PolicyName
[Index
] != VariableName
[Index
]) || (PolicyName
[Index
] == '#')) {
266 // If this is a numerical wildcard, we can consider
267 // it a match if we alter the priority.
268 if ((PolicyName
[Index
] == L
'#') &&
269 (((L
'0' <= VariableName
[Index
]) && (VariableName
[Index
] <= L
'9')) ||
270 ((L
'A' <= VariableName
[Index
]) && (VariableName
[Index
] <= L
'F')) ||
271 ((L
'a' <= VariableName
[Index
]) && (VariableName
[Index
] <= L
'f'))))
273 if (CalculatedPriority
< MATCH_PRIORITY_MIN
) {
274 CalculatedPriority
++;
277 // Otherwise, not a match.
288 if (Result
&& (MatchPriority
!= NULL
)) {
289 *MatchPriority
= CalculatedPriority
;
296 This helper function walks the current policy table and returns a pointer
297 to the best match, if any are found. Leverages EvaluatePolicyMatch() to
300 @param[in] VariableName Same as EFI_SET_VARIABLE.
301 @param[in] VendorGuid Same as EFI_SET_VARIABLE.
302 @param[out] ReturnPriority [Optional] If pointer is provided, return the
303 priority of the match. Same as EvaluatePolicyMatch().
304 Only valid if a match is returned.
306 @retval VARIABLE_POLICY_ENTRY* Best match that was found.
307 @retval NULL No match was found.
311 VARIABLE_POLICY_ENTRY
*
313 IN CONST CHAR16
*VariableName
,
314 IN CONST EFI_GUID
*VendorGuid
,
315 OUT UINT8
*ReturnPriority OPTIONAL
318 VARIABLE_POLICY_ENTRY
*BestResult
;
319 VARIABLE_POLICY_ENTRY
*CurrentEntry
;
321 UINT8 CurrentPriority
;
325 MatchPriority
= MATCH_PRIORITY_EXACT
;
327 // Walk all entries in the table, looking for matches.
328 CurrentEntry
= (VARIABLE_POLICY_ENTRY
*)mPolicyTable
;
329 for (Index
= 0; Index
< mCurrentTableCount
; Index
++) {
330 // Check for a match.
331 if (EvaluatePolicyMatch (CurrentEntry
, VariableName
, VendorGuid
, &CurrentPriority
)) {
332 // If match is better, take it.
333 if ((BestResult
== NULL
) || (CurrentPriority
< MatchPriority
)) {
334 BestResult
= CurrentEntry
;
335 MatchPriority
= CurrentPriority
;
338 // If you've hit the highest-priority match, can exit now.
339 if (MatchPriority
== 0) {
344 // If we're still in the loop, move to the next entry.
345 CurrentEntry
= GET_NEXT_POLICY (CurrentEntry
);
348 // If a return priority was requested, return it.
349 if (ReturnPriority
!= NULL
) {
350 *ReturnPriority
= MatchPriority
;
357 This API function validates and registers a new policy with
358 the policy enforcement engine.
360 @param[in] NewPolicy Pointer to the incoming policy structure.
363 @retval EFI_INVALID_PARAMETER NewPolicy is NULL or is internally inconsistent.
364 @retval EFI_ALREADY_STARTED An identical matching policy already exists.
365 @retval EFI_WRITE_PROTECTED The interface has been locked until the next reboot.
366 @retval EFI_UNSUPPORTED Policy enforcement has been disabled. No reason to add more policies.
367 @retval EFI_ABORTED A calculation error has prevented this function from completing.
368 @retval EFI_OUT_OF_RESOURCES Cannot grow the table to hold any more policies.
369 @retval EFI_NOT_READY Library has not yet been initialized.
374 RegisterVariablePolicy (
375 IN CONST VARIABLE_POLICY_ENTRY
*NewPolicy
379 VARIABLE_POLICY_ENTRY
*MatchPolicy
;
384 if (!IsVariablePolicyLibInitialized ()) {
385 return EFI_NOT_READY
;
388 if (mInterfaceLocked
) {
389 return EFI_WRITE_PROTECTED
;
392 if (!IsValidVariablePolicyStructure (NewPolicy
)) {
393 return EFI_INVALID_PARAMETER
;
396 // Check to see whether an exact matching policy already exists.
397 MatchPolicy
= GetBestPolicyMatch (
398 GET_POLICY_NAME (NewPolicy
),
399 &NewPolicy
->Namespace
,
402 if ((MatchPolicy
!= NULL
) && (MatchPriority
== MATCH_PRIORITY_EXACT
)) {
403 return EFI_ALREADY_STARTED
;
406 // If none exists, create it.
407 // If we need more space, allocate that now.
408 Status
= SafeUint32Add (mCurrentTableUsage
, NewPolicy
->Size
, &NewSize
);
409 if (EFI_ERROR (Status
)) {
413 if (NewSize
> mCurrentTableSize
) {
414 // Use NewSize to calculate the new table size in units of POLICY_TABLE_STEP_SIZE.
415 NewSize
= (NewSize
% POLICY_TABLE_STEP_SIZE
) > 0 ?
416 (NewSize
/ POLICY_TABLE_STEP_SIZE
) + 1 :
417 (NewSize
/ POLICY_TABLE_STEP_SIZE
);
418 // Calculate the new table size in absolute bytes.
419 Status
= SafeUint32Mult (NewSize
, POLICY_TABLE_STEP_SIZE
, &NewSize
);
420 if (EFI_ERROR (Status
)) {
424 // Reallocate and copy the table.
425 NewTable
= AllocateRuntimePool (NewSize
);
426 if (NewTable
== NULL
) {
427 return EFI_OUT_OF_RESOURCES
;
430 CopyMem (NewTable
, mPolicyTable
, mCurrentTableUsage
);
431 mCurrentTableSize
= NewSize
;
432 if (mPolicyTable
!= NULL
) {
433 FreePool (mPolicyTable
);
436 mPolicyTable
= NewTable
;
439 // Copy the policy into the table.
440 CopyMem (mPolicyTable
+ mCurrentTableUsage
, NewPolicy
, NewPolicy
->Size
);
441 mCurrentTableUsage
+= NewPolicy
->Size
;
442 mCurrentTableCount
+= 1;
450 This API function checks to see whether the parameters to SetVariable would
451 be allowed according to the current variable policies.
453 @param[in] VariableName Same as EFI_SET_VARIABLE.
454 @param[in] VendorGuid Same as EFI_SET_VARIABLE.
455 @param[in] Attributes Same as EFI_SET_VARIABLE.
456 @param[in] DataSize Same as EFI_SET_VARIABLE.
457 @param[in] Data Same as EFI_SET_VARIABLE.
459 @retval EFI_SUCCESS A matching policy allows this update.
460 @retval EFI_SUCCESS There are currently no policies that restrict this update.
461 @retval EFI_SUCCESS The protections have been disable until the next reboot.
462 @retval EFI_WRITE_PROTECTED Variable is currently locked.
463 @retval EFI_INVALID_PARAMETER Attributes or size are invalid.
464 @retval EFI_ABORTED A lock policy exists, but an error prevented evaluation.
465 @retval EFI_NOT_READY Library has not been initialized.
470 ValidateSetVariable (
471 IN CHAR16
*VariableName
,
472 IN EFI_GUID
*VendorGuid
,
473 IN UINT32 Attributes
,
479 VARIABLE_POLICY_ENTRY
*ActivePolicy
;
481 EFI_STATUS ReturnStatus
;
482 VARIABLE_LOCK_ON_VAR_STATE_POLICY
*StateVarPolicy
;
483 CHAR16
*StateVarName
;
487 ReturnStatus
= EFI_SUCCESS
;
489 if (!IsVariablePolicyLibInitialized ()) {
490 ReturnStatus
= EFI_NOT_READY
;
494 // Bail if the protections are currently disabled.
495 if (mProtectionDisabled
) {
496 ReturnStatus
= EFI_SUCCESS
;
500 // Determine whether this is a delete operation.
501 // If so, it will affect which tests are applied.
502 if ((DataSize
== 0) && ((Attributes
& EFI_VARIABLE_APPEND_WRITE
) == 0)) {
508 // Find an active policy if one exists.
509 ActivePolicy
= GetBestPolicyMatch (VariableName
, VendorGuid
, NULL
);
511 // If we have an active policy, check it against the incoming data.
512 if (ActivePolicy
!= NULL
) {
514 // Only enforce size and attribute constraints when updating data, not deleting.
516 // Check for size constraints.
517 if (((ActivePolicy
->MinSize
> 0) && (DataSize
< ActivePolicy
->MinSize
)) ||
518 ((ActivePolicy
->MaxSize
> 0) && (DataSize
> ActivePolicy
->MaxSize
)))
520 ReturnStatus
= EFI_INVALID_PARAMETER
;
523 "%a - Bad Size. 0x%X <> 0x%X-0x%X\n",
526 ActivePolicy
->MinSize
,
527 ActivePolicy
->MaxSize
532 // Check for attribute constraints.
533 if (((ActivePolicy
->AttributesMustHave
& Attributes
) != ActivePolicy
->AttributesMustHave
) ||
534 ((ActivePolicy
->AttributesCantHave
& Attributes
) != 0))
536 ReturnStatus
= EFI_INVALID_PARAMETER
;
539 "%a - Bad Attributes. 0x%X <> 0x%X:0x%X\n",
542 ActivePolicy
->AttributesMustHave
,
543 ActivePolicy
->AttributesCantHave
550 // Lock policy check.
552 // Check for immediate lock.
553 if (ActivePolicy
->LockPolicyType
== VARIABLE_POLICY_TYPE_LOCK_NOW
) {
554 ReturnStatus
= EFI_WRITE_PROTECTED
;
556 // Check for lock on create.
557 } else if (ActivePolicy
->LockPolicyType
== VARIABLE_POLICY_TYPE_LOCK_ON_CREATE
) {
559 Status
= mGetVariableHelper (
566 if (Status
== EFI_BUFFER_TOO_SMALL
) {
567 ReturnStatus
= EFI_WRITE_PROTECTED
;
571 // Check for lock on state variable.
572 } else if (ActivePolicy
->LockPolicyType
== VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE
) {
573 StateVarPolicy
= (VARIABLE_LOCK_ON_VAR_STATE_POLICY
*)((UINT8
*)ActivePolicy
+ sizeof (VARIABLE_POLICY_ENTRY
));
574 StateVarName
= (CHAR16
*)((UINT8
*)StateVarPolicy
+ sizeof (VARIABLE_LOCK_ON_VAR_STATE_POLICY
));
575 StateVarSize
= sizeof (StateVar
);
576 Status
= mGetVariableHelper (
578 &StateVarPolicy
->Namespace
,
584 // If the variable was found, check the state. If matched, this variable is locked.
585 if (!EFI_ERROR (Status
)) {
586 if (StateVar
== StateVarPolicy
->Value
) {
587 ReturnStatus
= EFI_WRITE_PROTECTED
;
591 // EFI_NOT_FOUND and EFI_BUFFER_TOO_SMALL indicate that the state doesn't match.
592 } else if ((Status
!= EFI_NOT_FOUND
) && (Status
!= EFI_BUFFER_TOO_SMALL
)) {
593 // We don't know what happened, but it isn't good.
594 ReturnStatus
= EFI_ABORTED
;
601 DEBUG ((DEBUG_VERBOSE
, "%a - Variable (%g:%s) returning %r.\n", __FUNCTION__
, VendorGuid
, VariableName
, ReturnStatus
));
606 This API function disables the variable policy enforcement. If it's
607 already been called once, will return EFI_ALREADY_STARTED.
610 @retval EFI_ALREADY_STARTED Has already been called once this boot.
611 @retval EFI_WRITE_PROTECTED Interface has been locked until reboot.
612 @retval EFI_WRITE_PROTECTED Interface option is disabled by platform PCD.
613 @retval EFI_NOT_READY Library has not yet been initialized.
618 DisableVariablePolicy (
622 if (!IsVariablePolicyLibInitialized ()) {
623 return EFI_NOT_READY
;
626 if (mProtectionDisabled
) {
627 return EFI_ALREADY_STARTED
;
630 if (mInterfaceLocked
) {
631 return EFI_WRITE_PROTECTED
;
634 if (!PcdGetBool (PcdAllowVariablePolicyEnforcementDisable
)) {
635 return EFI_WRITE_PROTECTED
;
638 mProtectionDisabled
= TRUE
;
643 This API function will dump the entire contents of the variable policy table.
645 Similar to GetVariable, the first call can be made with a 0 size and it will return
646 the size of the buffer required to hold the entire table.
648 @param[out] Policy Pointer to the policy buffer. Can be NULL if Size is 0.
649 @param[in,out] Size On input, the size of the output buffer. On output, the size
650 of the data returned.
652 @retval EFI_SUCCESS Policy data is in the output buffer and Size has been updated.
653 @retval EFI_INVALID_PARAMETER Size is NULL, or Size is non-zero and Policy is NULL.
654 @retval EFI_BUFFER_TOO_SMALL Size is insufficient to hold policy. Size updated with required size.
655 @retval EFI_NOT_READY Library has not yet been initialized.
665 if (!IsVariablePolicyLibInitialized ()) {
666 return EFI_NOT_READY
;
669 // Check the parameters.
670 if ((Size
== NULL
) || ((*Size
> 0) && (Policy
== NULL
))) {
671 return EFI_INVALID_PARAMETER
;
674 // Make sure the size is sufficient to hold the policy table.
675 if (*Size
< mCurrentTableUsage
) {
676 *Size
= mCurrentTableUsage
;
677 return EFI_BUFFER_TOO_SMALL
;
680 // If we're still here, copy the table and bounce.
681 CopyMem (Policy
, mPolicyTable
, mCurrentTableUsage
);
682 *Size
= mCurrentTableUsage
;
688 This API function returns whether or not the policy engine is
689 currently being enforced.
693 @retval FALSE Library has not yet been initialized.
698 IsVariablePolicyEnabled (
702 if (!IsVariablePolicyLibInitialized ()) {
706 return !mProtectionDisabled
;
710 This API function locks the interface so that no more policy updates
711 can be performed or changes made to the enforcement until the next boot.
714 @retval EFI_NOT_READY Library has not yet been initialized.
723 if (!IsVariablePolicyLibInitialized ()) {
724 return EFI_NOT_READY
;
727 if (mInterfaceLocked
) {
728 return EFI_WRITE_PROTECTED
;
731 mInterfaceLocked
= TRUE
;
736 This API function returns whether or not the policy interface is locked
737 for the remainder of the boot.
741 @retval FALSE Library has not yet been initialized.
746 IsVariablePolicyInterfaceLocked (
750 if (!IsVariablePolicyLibInitialized ()) {
754 return mInterfaceLocked
;
758 This helper function initializes the library and sets
759 up any required internal structures or handlers.
761 Also registers the internal pointer for the GetVariable helper.
763 @param[in] GetVariableHelper A function pointer matching the EFI_GET_VARIABLE prototype that will be used to
764 check policy criteria that involve the existence of other variables.
767 @retval EFI_ALREADY_STARTED The initialize function has been called more than once without a call to
773 InitVariablePolicyLib (
774 IN EFI_GET_VARIABLE GetVariableHelper
779 Status
= EFI_SUCCESS
;
781 if (mGetVariableHelper
!= NULL
) {
782 return EFI_ALREADY_STARTED
;
785 if (!EFI_ERROR (Status
)) {
786 Status
= VariablePolicyExtraInit ();
789 if (!EFI_ERROR (Status
)) {
790 // Save an internal pointer to the GetVariableHelper.
791 mGetVariableHelper
= GetVariableHelper
;
793 // Initialize the global state.
794 mInterfaceLocked
= FALSE
;
795 mProtectionDisabled
= FALSE
;
797 mCurrentTableSize
= 0;
798 mCurrentTableUsage
= 0;
799 mCurrentTableCount
= 0;
806 This helper function returns whether or not the library is currently initialized.
814 IsVariablePolicyLibInitialized (
818 return (mGetVariableHelper
!= NULL
);
822 This helper function tears down the library.
824 Should generally only be used for test harnesses.
827 @retval EFI_NOT_READY Deinitialize was called without first calling initialize.
832 DeinitVariablePolicyLib (
838 Status
= EFI_SUCCESS
;
840 if (mGetVariableHelper
== NULL
) {
841 return EFI_NOT_READY
;
844 if (!EFI_ERROR (Status
)) {
845 Status
= VariablePolicyExtraDeinit ();
848 if (!EFI_ERROR (Status
)) {
849 mGetVariableHelper
= NULL
;
850 mInterfaceLocked
= FALSE
;
851 mProtectionDisabled
= FALSE
;
852 mCurrentTableSize
= 0;
853 mCurrentTableUsage
= 0;
854 mCurrentTableCount
= 0;
856 if (mPolicyTable
!= NULL
) {
857 FreePool (mPolicyTable
);