Bump. This specific patch needs Reviews.

- Bret


From: devel@edk2.groups.io <devel@edk2.groups.io> on behalf of Bret Barkelew via groups.io <bret=corthon.com@groups.io>
Sent: Tuesday, June 2, 2020 11:57 PM
To: devel@edk2.groups.io <devel@edk2.groups.io>
Cc: Jian J Wang <jian.j.wang@intel.com>; Hao A Wu <hao.a.wu@intel.com>; liming.gao <liming.gao@intel.com>
Subject: [EXTERNAL] [edk2-devel] [PATCH v5 02/14] MdeModulePkg: Define the VariablePolicyLib
 
https://nam06.safelinks.protection.outlook.com/?url=https%3A%2F%2Fbugzilla.tianocore.org%2Fshow_bug.cgi%3Fid%3D2522&amp;data=02%7C01%7Cbret.barkelew%40microsoft.com%7C5f525d9b2e954b4b474d08d807a3da45%7C72f988bf86f141af91ab2d7cd011db47%7C1%7C0%7C637267747622305708&amp;sdata=V3OQlMW5ifVdpn5BJiGAmc8HsjXplYCm%2FdANjL9xbdI%3D&amp;reserved=0

VariablePolicy is an updated interface to
replace VarLock and VarCheckProtocol.

Add the VariablePolicyLib library that implements
the portable business logic for the VariablePolicy
engine.

Also add host-based CI test cases for the lib.

Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Hao A Wu <hao.a.wu@intel.com>
Cc: Liming Gao <liming.gao@intel.com>
Cc: Bret Barkelew <brbarkel@microsoft.com>
Signed-off-by: Bret Barkelew <brbarkel@microsoft.com>
---
 MdeModulePkg/Library/VariablePolicyLib/VariablePolicyExtraInitNull.c                     |   46 +
 MdeModulePkg/Library/VariablePolicyLib/VariablePolicyExtraInitRuntimeDxe.c               |   85 +
 MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.c                               |  813 +++++++
 MdeModulePkg/Library/VariablePolicyLib/VariablePolicyUnitTest/VariablePolicyUnitTest.c   | 2436 ++++++++++++++++++++
 MdeModulePkg/Include/Library/VariablePolicyLib.h                                         |  207 ++
 MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.inf                             |   44 +
 MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.uni                             |   12 +
 MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLibRuntimeDxe.inf                   |   51 +
 MdeModulePkg/Library/VariablePolicyLib/VariablePolicyUnitTest/VariablePolicyUnitTest.inf |   40 +
 MdeModulePkg/MdeModulePkg.dec                                                            |    3 +
 MdeModulePkg/MdeModulePkg.dsc                                                            |    5 +
 MdeModulePkg/Test/MdeModulePkgHostTest.dsc                                               |   11 +
 12 files changed, 3753 insertions(+)

diff --git a/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyExtraInitNull.c b/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyExtraInitNull.c
new file mode 100644
index 000000000000..ad2ee0b2fb8f
--- /dev/null
+++ b/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyExtraInitNull.c
@@ -0,0 +1,46 @@
+/** @file -- VariablePolicyExtraInitNull.c

+This file contains extra init and deinit routines that don't do anything

+extra.

+

+Copyright (c) Microsoft Corporation.

+SPDX-License-Identifier: BSD-2-Clause-Patent

+

+**/

+

+#include <Library/UefiRuntimeServicesTableLib.h>

+

+

+/**

+  An extra init hook that enables the RuntimeDxe library instance to

+  register VirtualAddress change callbacks. Among other things.

+

+  @retval     EFI_SUCCESS   Everything is good. Continue with init.

+  @retval     Others        Uh... don't continue.

+

+**/

+EFI_STATUS

+VariablePolicyExtraInit (

+  VOID

+  )

+{

+  // NULL implementation.

+  return EFI_SUCCESS;

+}

+

+

+/**

+  An extra deinit hook that enables the RuntimeDxe library instance to

+  register VirtualAddress change callbacks. Among other things.

+

+  @retval     EFI_SUCCESS   Everything is good. Continue with deinit.

+  @retval     Others        Uh... don't continue.

+

+**/

+EFI_STATUS

+VariablePolicyExtraDeinit (

+  VOID

+  )

+{

+  // NULL implementation.

+  return EFI_SUCCESS;

+}

diff --git a/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyExtraInitRuntimeDxe.c b/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyExtraInitRuntimeDxe.c
new file mode 100644
index 000000000000..3ca87048b14b
--- /dev/null
+++ b/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyExtraInitRuntimeDxe.c
@@ -0,0 +1,85 @@
+/** @file -- VariablePolicyExtraInitRuntimeDxe.c

+This file contains extra init and deinit routines that register and unregister

+VariableAddressChange callbacks.

+

+Copyright (c) Microsoft Corporation.

+SPDX-License-Identifier: BSD-2-Clause-Patent

+

+**/

+

+#include <Library/UefiBootServicesTableLib.h>

+#include <Library/UefiRuntimeServicesTableLib.h>

+

+extern EFI_GET_VARIABLE   mGetVariableHelper;

+extern UINT8              *mPolicyTable;

+STATIC BOOLEAN            mIsVirtualAddrConverted;

+STATIC EFI_EVENT          mVariablePolicyLibVirtualAddressChangeEvent  = NULL;

+

+/**

+  For the RuntimeDxe version of this lib, convert internal pointer addresses to virtual addresses.

+

+  @param[in] Event      Event whose notification function is being invoked.

+  @param[in] Context    The pointer to the notification function's context, which

+                        is implementation-dependent.

+**/

+STATIC

+VOID

+EFIAPI

+VariablePolicyLibVirtualAddressCallback (

+  IN  EFI_EVENT   Event,

+  IN  VOID        *Context

+  )

+{

+  gRT->ConvertPointer (0, (VOID **)&mPolicyTable);

+  gRT->ConvertPointer (0, (VOID **)&mGetVariableHelper);

+  mIsVirtualAddrConverted = TRUE;

+}

+

+

+/**

+  An extra init hook that enables the RuntimeDxe library instance to

+  register VirtualAddress change callbacks. Among other things.

+

+  @retval     EFI_SUCCESS   Everything is good. Continue with init.

+  @retval     Others        Uh... don't continue.

+

+**/

+EFI_STATUS

+VariablePolicyExtraInit (

+  VOID

+  )

+{

+  return gBS->CreateEventEx (EVT_NOTIFY_SIGNAL,

+                              TPL_NOTIFY,

+                              VariablePolicyLibVirtualAddressCallback,

+                              NULL,

+                              &gEfiEventVirtualAddressChangeGuid,

+                              &mVariablePolicyLibVirtualAddressChangeEvent);

+}

+

+

+/**

+  An extra deinit hook that enables the RuntimeDxe library instance to

+  register VirtualAddress change callbacks. Among other things.

+

+  @retval     EFI_SUCCESS   Everything is good. Continue with deinit.

+  @retval     Others        Uh... don't continue.

+

+**/

+EFI_STATUS

+VariablePolicyExtraDeinit (

+  VOID

+  )

+{

+  EFI_STATUS  Status;

+

+  Status = EFI_SUCCESS;

+  if (mIsVirtualAddrConverted) {

+    Status = gBS->CloseEvent (mVariablePolicyLibVirtualAddressChangeEvent);

+  }

+  else {

+    Status = EFI_SUCCESS;

+  }

+

+  return Status;

+}

diff --git a/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.c b/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.c
new file mode 100644
index 000000000000..c63807ef8531
--- /dev/null
+++ b/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.c
@@ -0,0 +1,813 @@
+/** @file -- VariablePolicyLib.c

+Business logic for Variable Policy enforcement.

+

+Copyright (c) Microsoft Corporation.

+SPDX-License-Identifier: BSD-2-Clause-Patent

+

+**/

+

+#include <Uefi.h>

+

+#include <Library/SafeIntLib.h>

+#include <Library/MemoryAllocationLib.h>

+#include <Library/BaseMemoryLib.h>

+#include <Library/DebugLib.h>

+#include <Library/PcdLib.h>

+

+#include <Protocol/VariablePolicy.h>

+#include <Library/VariablePolicyLib.h>

+

+

+// IMPORTANT NOTE: This library is currently rife with multiple return statements

+//                 for error handling. A refactor should remove these at some point.

+

+//

+// This library was designed with advanced unit-test features.

+// This define handles the configuration.

+#ifdef INTERNAL_UNIT_TEST

+#undef STATIC

+#define STATIC    // Nothing...

+#endif

+

+// An abstracted GetVariable interface that enables configuration regardless of the environment.

+EFI_GET_VARIABLE            mGetVariableHelper = NULL;

+

+// Master switch to lock this entire interface. Does not stop enforcement,

+// just prevents the configuration from being changed for the rest of the boot.

+STATIC  BOOLEAN             mInterfaceLocked = FALSE;

+

+// Master switch to disable the entire interface for a single boot.

+// This will disable all policy enforcement for the duration of the boot.

+STATIC  BOOLEAN             mProtectionDisabled = FALSE;

+

+// Table to hold all the current policies.

+UINT8                       *mPolicyTable = NULL;

+STATIC  UINT32              mCurrentTableSize = 0;

+STATIC  UINT32              mCurrentTableUsage = 0;

+STATIC  UINT32              mCurrentTableCount = 0;

+

+#define POLICY_TABLE_STEP_SIZE        0x1000

+

+// NOTE: DO NOT USE THESE MACROS on any structure that has not been validated.

+//       Current table data has already been sanitized.

+#define GET_NEXT_POLICY(CurPolicy)    (VARIABLE_POLICY_ENTRY*)((UINT8*)CurPolicy + CurPolicy->Size)

+#define GET_POLICY_NAME(CurPolicy)    (CHAR16*)((UINTN)CurPolicy + CurPolicy->OffsetToName)

+

+#define MATCH_PRIORITY_EXACT    0

+#define MATCH_PRIORITY_MAX      MATCH_PRIORITY_EXACT

+#define MATCH_PRIORITY_MIN      MAX_UINT8

+

+// ExtraInit/ExtraDeinit functions allow RuntimeDxe to register VirtualAddress callbacks.

+EFI_STATUS

+VariablePolicyExtraInit (

+  VOID

+  );

+

+EFI_STATUS

+VariablePolicyExtraDeinit (

+  VOID

+  );

+

+

+/**

+  This helper function determines whether the structure of an incoming policy

+  is valid and internally consistent.

+

+  @param[in]  NewPolicy     Pointer to the incoming policy structure.

+

+  @retval     TRUE

+  @retval     FALSE   Pointer is NULL, size is wrong, strings are empty, or

+                      substructures overlap.

+

+**/

+STATIC

+BOOLEAN

+IsValidVariablePolicyStructure (

+  IN CONST VARIABLE_POLICY_ENTRY    *NewPolicy

+  )

+{

+  EFI_STATUS    Status;

+  UINTN         EntryEnd;

+  CHAR16        *CheckChar;

+  UINTN         WildcardCount;

+

+  // Sanitize some quick values.

+  if (NewPolicy == NULL || NewPolicy->Size == 0 ||

+      // Structure size should be at least as long as the minumum structure and a NULL string.

+      NewPolicy->Size < sizeof(VARIABLE_POLICY_ENTRY) ||

+      // Check for the known revision.

+      NewPolicy->Version != VARIABLE_POLICY_ENTRY_REVISION) {

+    return FALSE;

+  }

+

+  // Calculate the theoretical end of the structure and make sure

+  // that the structure can fit in memory.

+  Status = SafeUintnAdd( (UINTN)NewPolicy, NewPolicy->Size, &EntryEnd );

+  if (EFI_ERROR( Status )) {

+    return FALSE;

+  }

+

+  // Check for a valid Max Size.

+  if (NewPolicy->MaxSize == 0) {

+    return FALSE;

+  }

+

+  // Check for the valid list of lock policies.

+  if (NewPolicy->LockPolicyType != VARIABLE_POLICY_TYPE_NO_LOCK &&

+      NewPolicy->LockPolicyType != VARIABLE_POLICY_TYPE_LOCK_NOW &&

+      NewPolicy->LockPolicyType != VARIABLE_POLICY_TYPE_LOCK_ON_CREATE &&

+      NewPolicy->LockPolicyType != VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE)

+  {

+    return FALSE;

+  }

+

+  // If the policy type is VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE, make sure that the matching state variable Name

+  // terminates before the OffsetToName for the matching policy variable Name.

+  if (NewPolicy->LockPolicyType == VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE) {

+    // Adjust CheckChar to the offset of the LockPolicy->Name.

+    Status = SafeUintnAdd( (UINTN)NewPolicy + sizeof(VARIABLE_POLICY_ENTRY),

+                            sizeof(VARIABLE_LOCK_ON_VAR_STATE_POLICY),

+                            (UINTN*)&CheckChar );

+    if (EFI_ERROR( Status ) || EntryEnd <= (UINTN)CheckChar) {

+      return FALSE;

+    }

+    while (*CheckChar != CHAR_NULL) {

+      if (EntryEnd <= (UINTN)CheckChar) {

+        return FALSE;

+      }

+      CheckChar++;

+    }

+    // At this point we should have either exeeded the structure or be pointing at the last char in LockPolicy->Name.

+    // We should check to make sure that the policy Name comes immediately after this charcter.

+    if ((UINTN)++CheckChar != (UINTN)NewPolicy + NewPolicy->OffsetToName) {

+      return FALSE;

+    }

+  }

+  // If the policy type is any other value, make sure that the LockPolicy structure has a zero length.

+  else {

+    if (NewPolicy->OffsetToName != sizeof(VARIABLE_POLICY_ENTRY)) {

+      return FALSE;

+    }

+  }

+

+  // Check to make sure that the name has a terminating character

+  // before the end of the structure.

+  // We've already checked that the name is within the bounds of the structure.

+  if (NewPolicy->Size != NewPolicy->OffsetToName) {

+    CheckChar = (CHAR16*)((UINTN)NewPolicy + NewPolicy->OffsetToName);

+    WildcardCount = 0;

+    while (*CheckChar != CHAR_NULL) {

+      // Make sure there aren't excessive wildcards.

+      if (*CheckChar == '#') {

+        WildcardCount++;

+        if (WildcardCount > MATCH_PRIORITY_MIN) {

+          return FALSE;

+        }

+      }

+      // Make sure you're still within the bounds of the policy structure.

+      if (EntryEnd <= (UINTN)CheckChar) {

+        return FALSE;

+      }

+      CheckChar++;

+    }

+

+    // Finally, we should be pointed at the very last character in Name, so we should be right

+    // up against the end of the structure.

+    if ((UINTN)++CheckChar != EntryEnd) {

+      return FALSE;

+    }

+  }

+

+  return TRUE;

+}

+

+

+/**

+  This helper function evaluates a policy and determines whether it matches the target

+  variable. If matched, will also return a value corresponding to the priority of the match.

+

+  The rules for "best match" are listed in the Variable Policy Spec.

+  Perfect name matches will return 0.

+  Single wildcard characters will return the number of wildcard characters.

+  Full namespaces will return MAX_UINT8.

+

+  @param[in]  EvalEntry         Pointer to the policy entry being evaluated.

+  @param[in]  VariableName      Same as EFI_SET_VARIABLE.

+  @param[in]  VendorGuid        Same as EFI_SET_VARIABLE.

+  @param[out] MatchPriority     [Optional] On finding a match, this value contains the priority of the match.

+                                Lower number == higher priority. Only valid if a match found.

+

+  @retval     TRUE          Current entry matches the target variable.

+  @retval     FALSE         Current entry does not match at all.

+

+**/

+STATIC

+BOOLEAN

+EvaluatePolicyMatch (

+  IN CONST  VARIABLE_POLICY_ENTRY   *EvalEntry,

+  IN CONST  CHAR16                  *VariableName,

+  IN CONST  EFI_GUID                *VendorGuid,

+  OUT       UINT8                   *MatchPriority    OPTIONAL

+  )

+{

+  BOOLEAN     Result;

+  CHAR16      *PolicyName;

+  UINT8       CalculatedPriority;

+  UINTN       Index;

+

+  Result = FALSE;

+  CalculatedPriority = MATCH_PRIORITY_EXACT;

+

+  // Step 1: If the GUID doesn't match, we're done. No need to evaluate anything else.

+  if (!CompareGuid( &EvalEntry->Namespace, VendorGuid )) {

+    goto Exit;

+  }

+

+  // If the GUID matches, check to see whether there is a Name associated

+  // with the policy. If not, this policy matches the entire namespace.

+  // Missing Name is indicated by size being equal to name.

+  if (EvalEntry->Size == EvalEntry->OffsetToName) {

+    CalculatedPriority = MATCH_PRIORITY_MIN;

+    Result = TRUE;

+    goto Exit;

+  }

+

+  // Now that we know the name exists, get it.

+  PolicyName = GET_POLICY_NAME( EvalEntry );

+

+  // Evaluate the name against the policy name and check for a match.

+  // Account for any wildcards.

+  Index = 0;

+  Result = TRUE;

+  // Keep going until the end of both strings.

+  while (PolicyName[Index] != CHAR_NULL || VariableName[Index] != CHAR_NULL) {

+    // If we don't have a match...

+    if (PolicyName[Index] != VariableName[Index] || PolicyName[Index] == '#') {

+      // If this is a numerical wildcard, we can consider

+      // it a match if we alter the priority.

+      if (PolicyName[Index] == L'#' &&

+          (L'0' <= VariableName[Index] && VariableName[Index] <= L'9')) {

+        if (CalculatedPriority < MATCH_PRIORITY_MIN) {

+          CalculatedPriority++;

+        }

+      }

+      // Otherwise, not a match.

+      else {

+        Result = FALSE;

+        goto Exit;

+      }

+    }

+    Index++;

+  }

+

+Exit:

+  if (Result && MatchPriority != NULL) {

+    *MatchPriority = CalculatedPriority;

+  }

+  return Result;

+}

+

+

+/**

+  This helper function walks the current policy table and returns a pointer

+  to the best match, if any are found. Leverages EvaluatePolicyMatch() to

+  determine "best".

+

+  @param[in]  VariableName       Same as EFI_SET_VARIABLE.

+  @param[in]  VendorGuid         Same as EFI_SET_VARIABLE.

+  @param[out] ReturnPriority     [Optional] If pointer is provided, return the

+                                 priority of the match. Same as EvaluatePolicyMatch().

+                                 Only valid if a match is returned.

+

+  @retval     VARIABLE_POLICY_ENTRY*    Best match that was found.

+  @retval     NULL                      No match was found.

+

+**/

+STATIC

+VARIABLE_POLICY_ENTRY*

+GetBestPolicyMatch (

+  IN CONST  CHAR16            *VariableName,

+  IN CONST  EFI_GUID          *VendorGuid,

+  OUT       UINT8             *ReturnPriority  OPTIONAL

+  )

+{

+  VARIABLE_POLICY_ENTRY   *BestResult;

+  VARIABLE_POLICY_ENTRY   *CurrentEntry;

+  UINT8                   MatchPriority;

+  UINT8                   CurrentPriority;

+  UINTN                   Index;

+

+  BestResult = NULL;

+

+  // Walk all entries in the table, looking for matches.

+  CurrentEntry = (VARIABLE_POLICY_ENTRY*)mPolicyTable;

+  for (Index = 0; Index < mCurrentTableCount; Index++) {

+    // Check for a match.

+    if (EvaluatePolicyMatch( CurrentEntry, VariableName, VendorGuid, &CurrentPriority )) {

+      // If match is better, take it.

+      if (BestResult == NULL || CurrentPriority < MatchPriority) {

+        BestResult = CurrentEntry;

+        MatchPriority = CurrentPriority;

+      }

+

+      // If you've hit the highest-priority match, can exit now.

+      if (MatchPriority == 0) {

+        break;

+      }

+    }

+

+    // If we're still in the loop, move to the next entry.

+    CurrentEntry = GET_NEXT_POLICY( CurrentEntry );

+  }

+

+  // If a return priority was requested, return it.

+  if (ReturnPriority != NULL) {

+    *ReturnPriority = MatchPriority;

+  }

+

+  return BestResult;

+}

+

+

+/**

+  This API function validates and registers a new policy with

+  the policy enforcement engine.

+

+  @param[in]  NewPolicy     Pointer to the incoming policy structure.

+

+  @retval     EFI_SUCCESS

+  @retval     EFI_INVALID_PARAMETER   NewPolicy is NULL or is internally inconsistent.

+  @retval     EFI_ALREADY_STARTED     An identical matching policy already exists.

+  @retval     EFI_WRITE_PROTECTED     The interface has been locked until the next reboot.

+  @retval     EFI_UNSUPPORTED         Policy enforcement has been disabled. No reason to add more policies.

+  @retval     EFI_ABORTED             A calculation error has prevented this function from completing.

+  @retval     EFI_OUT_OF_RESOURCES    Cannot grow the table to hold any more policies.

+  @retval     EFI_NOT_READY           Library has not yet been initialized.

+

+**/

+EFI_STATUS

+EFIAPI

+RegisterVariablePolicy (

+  IN CONST VARIABLE_POLICY_ENTRY    *NewPolicy

+  )

+{

+  EFI_STATUS                Status;

+  VARIABLE_POLICY_ENTRY     *MatchPolicy;

+  UINT8                     MatchPriority;

+  UINT32                    NewSize;

+  UINT8                     *NewTable;

+

+  if (!IsVariablePolicyLibInitialized()) {

+    return EFI_NOT_READY;

+  }

+  if (mInterfaceLocked) {

+    return EFI_WRITE_PROTECTED;

+  }

+

+  if (!IsValidVariablePolicyStructure( NewPolicy )) {

+    return EFI_INVALID_PARAMETER;

+  }

+

+  // Check to see whether an exact matching policy already exists.

+  MatchPolicy = GetBestPolicyMatch( GET_POLICY_NAME( NewPolicy ),

+                                    &NewPolicy->Namespace,

+                                    &MatchPriority );

+  if (MatchPolicy != NULL && MatchPriority == MATCH_PRIORITY_EXACT) {

+    return EFI_ALREADY_STARTED;

+  }

+

+  // If none exists, create it.

+  // If we need more space, allocate that now.

+  Status = SafeUint32Add( mCurrentTableUsage, NewPolicy->Size, &NewSize );

+  if (EFI_ERROR( Status )) {

+    return EFI_ABORTED;

+  }

+  if (NewSize > mCurrentTableSize) {

+    // Use NewSize to calculate the new table size in units of POLICY_TABLE_STEP_SIZE.

+    NewSize = (NewSize % POLICY_TABLE_STEP_SIZE) > 0 ?

+                (NewSize / POLICY_TABLE_STEP_SIZE) + 1 :

+                (NewSize / POLICY_TABLE_STEP_SIZE);

+    // Calculate the new table size in absolute bytes.

+    Status = SafeUint32Mult( NewSize, POLICY_TABLE_STEP_SIZE, &NewSize );

+    if (EFI_ERROR( Status )) {

+      return EFI_ABORTED;

+    }

+

+    // Reallocate and copy the table.

+    NewTable = AllocatePool( NewSize );

+    if (NewTable == NULL) {

+      return EFI_OUT_OF_RESOURCES;

+    }

+    CopyMem( NewTable, mPolicyTable, mCurrentTableUsage );

+    mCurrentTableSize = NewSize;

+    if (mPolicyTable != NULL) {

+      FreePool( mPolicyTable );

+    }

+    mPolicyTable = NewTable;

+  }

+  // Copy the policy into the table.

+  CopyMem( mPolicyTable + mCurrentTableUsage, NewPolicy, NewPolicy->Size );

+  mCurrentTableUsage += NewPolicy->Size;

+  mCurrentTableCount += 1;

+

+  // We're done here.

+

+  return EFI_SUCCESS;

+}

+

+

+/**

+  This API function checks to see whether the parameters to SetVariable would

+  be allowed according to the current variable policies.

+

+  @param[in]  VariableName       Same as EFI_SET_VARIABLE.

+  @param[in]  VendorGuid         Same as EFI_SET_VARIABLE.

+  @param[in]  Attributes         Same as EFI_SET_VARIABLE.

+  @param[in]  DataSize           Same as EFI_SET_VARIABLE.

+  @param[in]  Data               Same as EFI_SET_VARIABLE.

+

+  @retval     EFI_SUCCESS             A matching policy allows this update.

+  @retval     EFI_SUCCESS             There are currently no policies that restrict this update.

+  @retval     EFI_SUCCESS             The protections have been disable until the next reboot.

+  @retval     EFI_WRITE_PROTECTED     Variable is currently locked.

+  @retval     EFI_INVALID_PARAMETER   Attributes or size are invalid.

+  @retval     EFI_ABORTED             A lock policy exists, but an error prevented evaluation.

+  @retval     EFI_NOT_READY           Library has not been initialized.

+

+**/

+EFI_STATUS

+EFIAPI

+ValidateSetVariable (

+  IN  CHAR16                       *VariableName,

+  IN  EFI_GUID                     *VendorGuid,

+  IN  UINT32                       Attributes,

+  IN  UINTN                        DataSize,

+  IN  VOID                         *Data

+  )

+{

+  BOOLEAN                             IsDel;

+  VARIABLE_POLICY_ENTRY               *ActivePolicy;

+  EFI_STATUS                          Status;

+  EFI_STATUS                          ReturnStatus;

+  VARIABLE_LOCK_ON_VAR_STATE_POLICY   *StateVarPolicy;

+  CHAR16                              *StateVarName;

+  UINTN                               StateVarSize;

+  UINT8                               StateVar;

+

+  ReturnStatus = EFI_SUCCESS;

+

+  if (!IsVariablePolicyLibInitialized()) {

+    ReturnStatus = EFI_NOT_READY;

+    goto Exit;

+  }

+

+  // Bail if the protections are currently disabled.

+  if (mProtectionDisabled) {

+    ReturnStatus = EFI_SUCCESS;

+    goto Exit;

+  }

+

+  // Determine whether this is a delete operation.

+  // If so, it will affect which tests are applied.

+  if ((DataSize == 0) && ((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0)) {

+    IsDel = TRUE;

+  }

+  else {

+    IsDel = FALSE;

+  }

+

+  // Find an active policy if one exists.

+  ActivePolicy = GetBestPolicyMatch( VariableName, VendorGuid, NULL );

+

+  // If we have an active policy, check it against the incoming data.

+  if (ActivePolicy != NULL) {

+    //

+    // Only enforce size and attribute constraints when updating data, not deleting.

+    if (!IsDel) {

+      // Check for size constraints.

+      if ((ActivePolicy->MinSize > 0 && DataSize < ActivePolicy->MinSize) ||

+          (ActivePolicy->MaxSize > 0 && DataSize > ActivePolicy->MaxSize)) {

+        ReturnStatus = EFI_INVALID_PARAMETER;

+        DEBUG(( DEBUG_VERBOSE, "%a - Bad Size. 0x%X <> 0x%X-0x%X\n", __FUNCTION__,

+                DataSize, ActivePolicy->MinSize, ActivePolicy->MaxSize ));

+        goto Exit;

+      }

+

+      // Check for attribute constraints.

+      if ((ActivePolicy->AttributesMustHave & Attributes) != ActivePolicy->AttributesMustHave ||

+          (ActivePolicy->AttributesCantHave & Attributes) != 0) {

+        ReturnStatus = EFI_INVALID_PARAMETER;

+        DEBUG(( DEBUG_VERBOSE, "%a - Bad Attributes. 0x%X <> 0x%X:0x%X\n", __FUNCTION__,

+                Attributes, ActivePolicy->AttributesMustHave, ActivePolicy->AttributesCantHave ));

+        goto Exit;

+      }

+    }

+

+    //

+    // Lock policy check.

+    //

+    // Check for immediate lock.

+    if (ActivePolicy->LockPolicyType == VARIABLE_POLICY_TYPE_LOCK_NOW) {

+      ReturnStatus = EFI_WRITE_PROTECTED;

+      goto Exit;

+    }

+    // Check for lock on create.

+    else if (ActivePolicy->LockPolicyType == VARIABLE_POLICY_TYPE_LOCK_ON_CREATE) {

+      StateVarSize = 0;

+      Status = mGetVariableHelper( VariableName,

+                                   VendorGuid,

+                                   NULL,

+                                   &StateVarSize,

+                                   NULL );

+      if (Status == EFI_BUFFER_TOO_SMALL) {

+        ReturnStatus = EFI_WRITE_PROTECTED;

+        goto Exit;

+      }

+    }

+    // Check for lock on state variable.

+    else if (ActivePolicy->LockPolicyType == VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE) {

+      StateVarPolicy = (VARIABLE_LOCK_ON_VAR_STATE_POLICY*)((UINT8*)ActivePolicy + sizeof(VARIABLE_POLICY_ENTRY));

+      StateVarName = (CHAR16*)((UINT8*)StateVarPolicy + sizeof(VARIABLE_LOCK_ON_VAR_STATE_POLICY));

+      StateVarSize = sizeof(StateVar);

+      Status = mGetVariableHelper( StateVarName,

+                                   &StateVarPolicy->Namespace,

+                                   NULL,

+                                   &StateVarSize,

+                                   &StateVar );

+

+      // If the variable was found, check the state. If matched, this variable is locked.

+      if (!EFI_ERROR( Status )) {

+        if (StateVar == StateVarPolicy->Value) {

+          ReturnStatus = EFI_WRITE_PROTECTED;

+          goto Exit;

+        }

+      }

+      // EFI_NOT_FOUND and EFI_BUFFER_TOO_SMALL indicate that the state doesn't match.

+      else if (Status != EFI_NOT_FOUND && Status != EFI_BUFFER_TOO_SMALL) {

+        // We don't know what happened, but it isn't good.

+        ReturnStatus = EFI_ABORTED;

+        goto Exit;

+      }

+    }

+  }

+

+Exit:

+  DEBUG(( DEBUG_VERBOSE, "%a - Variable (%g:%s) returning %r.\n", __FUNCTION__, VendorGuid, VariableName, ReturnStatus ));

+  return ReturnStatus;

+}

+

+

+/**

+  This API function disables the variable policy enforcement. If it's

+  already been called once, will return EFI_ALREADY_STARTED.

+

+  @retval     EFI_SUCCESS

+  @retval     EFI_ALREADY_STARTED   Has already been called once this boot.

+  @retval     EFI_WRITE_PROTECTED   Interface has been locked until reboot.

+  @retval     EFI_WRITE_PROTECTED   Interface option is disabled by platform PCD.

+  @retval     EFI_NOT_READY         Library has not yet been initialized.

+

+**/

+EFI_STATUS

+EFIAPI

+DisableVariablePolicy (

+  VOID

+  )

+{

+  if (!IsVariablePolicyLibInitialized()) {

+    return EFI_NOT_READY;

+  }

+  if (mProtectionDisabled) {

+    return EFI_ALREADY_STARTED;

+  }

+  if (mInterfaceLocked) {

+    return EFI_WRITE_PROTECTED;

+  }

+  if (!PcdGetBool (PcdAllowVariablePolicyEnforcementDisable)) {

+    return EFI_WRITE_PROTECTED;

+  }

+  mProtectionDisabled = TRUE;

+  return EFI_SUCCESS;

+}

+

+

+/**

+  This API function will dump the entire contents of the variable policy table.

+

+  Similar to GetVariable, the first call can be made with a 0 size and it will return

+  the size of the buffer required to hold the entire table.

+

+  @param[out]     Policy  Pointer to the policy buffer. Can be NULL if Size is 0.

+  @param[in,out]  Size    On input, the size of the output buffer. On output, the size

+                          of the data returned.

+

+  @retval     EFI_SUCCESS             Policy data is in the output buffer and Size has been updated.

+  @retval     EFI_INVALID_PARAMETER   Size is NULL, or Size is non-zero and Policy is NULL.

+  @retval     EFI_BUFFER_TOO_SMALL    Size is insufficient to hold policy. Size updated with required size.

+  @retval     EFI_NOT_READY           Library has not yet been initialized.

+

+**/

+EFI_STATUS

+EFIAPI

+DumpVariablePolicy (

+  OUT     UINT8         *Policy,

+  IN OUT  UINT32        *Size

+  )

+{

+  if (!IsVariablePolicyLibInitialized()) {

+    return EFI_NOT_READY;

+  }

+

+  // Check the parameters.

+  if (Size == NULL || (*Size > 0 && Policy == NULL)) {

+    return EFI_INVALID_PARAMETER;

+  }

+

+  // Make sure the size is sufficient to hold the policy table.

+  if (*Size < mCurrentTableUsage) {

+    *Size = mCurrentTableUsage;

+    return EFI_BUFFER_TOO_SMALL;

+  }

+

+  // If we're still here, copy the table and bounce.

+  CopyMem( Policy, mPolicyTable, mCurrentTableUsage );

+  *Size = mCurrentTableUsage;

+

+  return EFI_SUCCESS;

+}

+

+

+/**

+  This API function returns whether or not the policy engine is

+  currently being enforced.

+

+  @retval     TRUE

+  @retval     FALSE

+  @retval     FALSE         Library has not yet been initialized.

+

+**/

+BOOLEAN

+EFIAPI

+IsVariablePolicyEnabled (

+  VOID

+  )

+{

+  if (!IsVariablePolicyLibInitialized()) {

+    return FALSE;

+  }

+  return !mProtectionDisabled;

+}

+

+

+/**

+  This API function locks the interface so that no more policy updates

+  can be performed or changes made to the enforcement until the next boot.

+

+  @retval     EFI_SUCCESS

+  @retval     EFI_NOT_READY   Library has not yet been initialized.

+

+**/

+EFI_STATUS

+EFIAPI

+LockVariablePolicy (

+  VOID

+  )

+{

+  if (!IsVariablePolicyLibInitialized()) {

+    return EFI_NOT_READY;

+  }

+  if (mInterfaceLocked) {

+    return EFI_WRITE_PROTECTED;

+  }

+  mInterfaceLocked = TRUE;

+  return EFI_SUCCESS;

+}

+

+

+/**

+  This API function returns whether or not the policy interface is locked

+  for the remainder of the boot.

+

+  @retval     TRUE

+  @retval     FALSE

+  @retval     FALSE         Library has not yet been initialized.

+

+**/

+BOOLEAN

+EFIAPI

+IsVariablePolicyInterfaceLocked (

+  VOID

+  )

+{

+  if (!IsVariablePolicyLibInitialized()) {

+    return FALSE;

+  }

+  return mInterfaceLocked;

+}

+

+

+/**

+  This helper function initializes the library and sets

+  up any required internal structures or handlers.

+

+  Also registers the internal pointer for the GetVariable helper.

+

+  @param[in]  GetVariableHelper A function pointer matching the EFI_GET_VARIABLE prototype that will be used to

+                  check policy criteria that involve the existence of other variables.

+

+  @retval     EFI_SUCCESS

+  @retval     EFI_ALREADY_STARTED   The initialize function has been called more than once without a call to

+                                    deinitialize.

+

+**/

+EFI_STATUS

+EFIAPI

+InitVariablePolicyLib (

+  IN  EFI_GET_VARIABLE    GetVariableHelper

+  )

+{

+  EFI_STATUS    Status;

+

+  if (mGetVariableHelper != NULL) {

+    Status = EFI_ALREADY_STARTED;

+  }

+

+  if (!EFI_ERROR( Status )) {

+    Status = VariablePolicyExtraInit();

+  }

+

+  if (!EFI_ERROR( Status )) {

+    // Save an internal pointer to the GetVariableHelper.

+    mGetVariableHelper = GetVariableHelper;

+

+    // Initialize the global state.

+    mInterfaceLocked = FALSE;

+    mProtectionDisabled = FALSE;

+    mPolicyTable = NULL;

+    mCurrentTableSize = 0;

+    mCurrentTableUsage = 0;

+    mCurrentTableCount = 0;

+  }

+

+  return Status;

+}

+

+

+/**

+  This helper function returns whether or not the library is currently initialized.

+

+  @retval     TRUE

+  @retval     FALSE

+

+**/

+BOOLEAN

+EFIAPI

+IsVariablePolicyLibInitialized (

+  VOID

+  )

+{

+  return (mGetVariableHelper != NULL);

+}

+

+

+/**

+  This helper function tears down  the library.

+

+  Should generally only be used for test harnesses.

+

+  @retval     EFI_SUCCESS

+  @retval     EFI_NOT_READY     Deinitialize was called without first calling initialize.

+

+**/

+EFI_STATUS

+EFIAPI

+DeinitVariablePolicyLib (

+  VOID

+  )

+{

+  EFI_STATUS    Status;

+

+  if (mGetVariableHelper == NULL) {

+    Status = EFI_NOT_READY;

+  }

+

+  if (!EFI_ERROR( Status )) {

+    Status = VariablePolicyExtraDeinit();

+  }

+

+  if (!EFI_ERROR( Status )) {

+    mGetVariableHelper = NULL;

+    mInterfaceLocked = FALSE;

+    mProtectionDisabled = FALSE;

+    mCurrentTableSize = 0;

+    mCurrentTableUsage = 0;

+    mCurrentTableCount = 0;

+

+    if (mPolicyTable != NULL) {

+      FreePool( mPolicyTable );

+      mPolicyTable = NULL;

+    }

+  }

+

+  return Status;

+}

diff --git a/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyUnitTest/VariablePolicyUnitTest.c b/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyUnitTest/VariablePolicyUnitTest.c
new file mode 100644
index 000000000000..f133f2f30e36
--- /dev/null
+++ b/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyUnitTest/VariablePolicyUnitTest.c
@@ -0,0 +1,2436 @@
+/** @file -- VariablePolicyUnitTest.c

+UnitTest for...

+Business logic for Variable Policy enforcement.

+

+Copyright (c) Microsoft Corporation.

+SPDX-License-Identifier: BSD-2-Clause-Patent

+

+**/

+

+#include <stdio.h>

+#include <string.h>

+#include <stdarg.h>

+#include <stddef.h>

+#include <setjmp.h>

+#include <cmocka.h>

+

+#include <Uefi.h>

+#include <Library/PrintLib.h>

+#include <Library/DebugLib.h>

+#include <Library/UnitTestLib.h>

+#include <Library/BaseMemoryLib.h>

+#include <Library/MemoryAllocationLib.h>

+#include <Library/BaseLib.h>

+

+#include <Guid/VariableFormat.h>

+

+#include <Protocol/VariablePolicy.h>

+#include <Library/VariablePolicyLib.h>

+

+// MU_CHANGE - Turn this off for now. Try to turn it back on with extra build options.

+// #ifndef INTERNAL_UNIT_TEST

+// #error Make sure to build thie with INTERNAL_UNIT_TEST enabled! Otherwise, some important tests may be skipped!

+// #endif

+

+

+#define UNIT_TEST_NAME        "UEFI Variable Policy UnitTest"

+#define UNIT_TEST_VERSION     "0.5"

+

+///=== TEST DATA ==================================================================================

+

+#pragma pack(push, 1)

+typedef struct _SIMPLE_VARIABLE_POLICY_ENTRY {

+  VARIABLE_POLICY_ENTRY     Header;

+  CHAR16                    Name[];

+} SIMPLE_VARIABLE_POLICY_ENTRY;

+#define EXPANDED_VARIABLE_POLICY_ENTRY_VAR_NAME_LENGTH  1001    // 1000 characters + terminator.

+#define EXPANDED_VARIABLE_POLICY_ENTRY_VAR_NAME_SIZE    (EXPANDED_VARIABLE_POLICY_ENTRY_VAR_NAME_LENGTH * sizeof(CHAR16))

+typedef struct _EXPANDED_VARIABLE_POLICY_ENTRY {

+  VARIABLE_POLICY_ENTRY               Header;

+  VARIABLE_LOCK_ON_VAR_STATE_POLICY   StatePolicy;

+  CHAR16                              StateName[EXPANDED_VARIABLE_POLICY_ENTRY_VAR_NAME_LENGTH];

+  CHAR16                              Name[EXPANDED_VARIABLE_POLICY_ENTRY_VAR_NAME_LENGTH];

+} EXPANDED_VARIABLE_POLICY_ENTRY;

+#pragma pack(pop)

+

+// {F955BA2D-4A2C-480C-BFD1-3CC522610592}

+#define TEST_GUID_1 { 0xf955ba2d, 0x4a2c, 0x480c, { 0xbf, 0xd1, 0x3c, 0xc5, 0x22, 0x61, 0x5, 0x92 } }

+EFI_GUID    mTestGuid1 = TEST_GUID_1;

+// {2DEA799E-5E73-43B9-870E-C945CE82AF3A}

+#define TEST_GUID_2 { 0x2dea799e, 0x5e73, 0x43b9, { 0x87, 0xe, 0xc9, 0x45, 0xce, 0x82, 0xaf, 0x3a } }

+EFI_GUID    mTestGuid2 = TEST_GUID_2;

+// {698A2BFD-A616-482D-B88C-7100BD6682A9}

+#define TEST_GUID_3 { 0x698a2bfd, 0xa616, 0x482d, { 0xb8, 0x8c, 0x71, 0x0, 0xbd, 0x66, 0x82, 0xa9 } }

+EFI_GUID    mTestGuid3 = TEST_GUID_3;

+

+#define   TEST_VAR_1_NAME                 L"TestVar1"

+#define   TEST_VAR_2_NAME                 L"TestVar2"

+#define   TEST_VAR_3_NAME                 L"TestVar3"

+

+#define   TEST_POLICY_ATTRIBUTES_NULL     0

+#define   TEST_POLICY_MIN_SIZE_NULL       0

+#define   TEST_POLICY_MAX_SIZE_NULL       MAX_UINT32

+

+#define   TEST_POLICY_MIN_SIZE_10         10

+#define   TEST_POLICY_MAX_SIZE_200        200

+

+#define TEST_300_HASHES_STRING      L"##################################################"\

+                                      "##################################################"\

+                                      "##################################################"\

+                                      "##################################################"\

+                                      "##################################################"\

+                                      "##################################################"

+

+

+///=== HELPER FUNCTIONS ===========================================================================

+

+/**

+  Helper function to initialize a VARIABLE_POLICY_ENTRY structure with a Name and StateName.

+

+  Takes care of all the messy packing.

+

+  @param[in,out]  Entry

+  @param[in]      Name        [Optional]

+  @param[in]      StateName   [Optional]

+

+  @retval     TRUE

+  @retval     FALSE

+

+**/

+STATIC

+BOOLEAN

+InitExpVarPolicyStrings (

+  EXPANDED_VARIABLE_POLICY_ENTRY      *Entry,

+  CHAR16                              *Name,      OPTIONAL

+  CHAR16                              *StateName  OPTIONAL

+  )

+{

+  UINTN     NameSize;

+  UINTN     StateNameSize;

+

+  NameSize = Name == NULL ? 0 : StrSize( Name );

+  StateNameSize = StateName == NULL ? 0 : StrSize( StateName );

+

+  if (NameSize > EXPANDED_VARIABLE_POLICY_ENTRY_VAR_NAME_SIZE || NameSize > MAX_UINT16 ||

+      StateNameSize > EXPANDED_VARIABLE_POLICY_ENTRY_VAR_NAME_SIZE || StateNameSize > MAX_UINT16) {

+    return FALSE;

+  }

+

+  Entry->Header.OffsetToName = sizeof(VARIABLE_POLICY_ENTRY);

+  if (StateName != NULL) {

+    Entry->Header.OffsetToName += (UINT16)sizeof(VARIABLE_LOCK_ON_VAR_STATE_POLICY) + (UINT16)StateNameSize;

+  }

+  Entry->Header.Size = Entry->Header.OffsetToName + (UINT16)NameSize;

+

+  CopyMem( (UINT8*)Entry + Entry->Header.OffsetToName, Name, NameSize );

+  if (StateName != NULL) {

+    CopyMem( (UINT8*)Entry + sizeof(VARIABLE_POLICY_ENTRY) + sizeof(VARIABLE_LOCK_ON_VAR_STATE_POLICY), StateName, StateNameSize );

+  }

+

+  return TRUE;

+}

+

+/**

+  Mocked version of GetVariable, for testing.

+**/

+EFI_STATUS

+EFIAPI

+StubGetVariableNull (

+  IN     CHAR16                      *VariableName,

+  IN     EFI_GUID                    *VendorGuid,

+  OUT    UINT32                      *Attributes,    OPTIONAL

+  IN OUT UINTN                       *DataSize,

+  OUT    VOID                        *Data           OPTIONAL

+  )

+{

+  UINT32      MockedAttr;

+  UINTN       MockedDataSize;

+  VOID        *MockedData;

+  EFI_STATUS  MockedReturn;

+

+  check_expected_ptr( VariableName );

+  check_expected_ptr( VendorGuid );

+  check_expected_ptr( DataSize );

+

+  MockedAttr = (UINT32)mock();

+  MockedDataSize = (UINTN)mock();

+  MockedData = (VOID*)mock();

+  MockedReturn = (EFI_STATUS)mock();

+

+  if (Attributes != NULL) {

+    *Attributes = MockedAttr;

+  }

+  if (Data != NULL && !EFI_ERROR(MockedReturn)) {

+    CopyMem( Data, MockedData, MockedDataSize );

+  }

+

+  *DataSize = MockedDataSize;

+

+  return MockedReturn;

+}

+

+//

+// Anything you think might be helpful that isn't a test itself.

+//

+

+/**

+  This is a common setup function that will ensure the library is always initialized

+  with the stubbed GetVariable.

+

+  Not used by all test cases, but by most.

+**/

+STATIC

+UNIT_TEST_STATUS

+LibInitMocked (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  return EFI_ERROR(InitVariablePolicyLib( StubGetVariableNull )) ? UNIT_TEST_ERROR_PREREQUISITE_NOT_MET : UNIT_TEST_PASSED;

+}

+

+/**

+  Common cleanup function to make sure that the library is always de-initialized prior

+  to the next test case.

+*/

+STATIC

+VOID

+LibCleanup (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  DeinitVariablePolicyLib();

+}

+

+

+///=== TEST CASES =================================================================================

+

+///===== ARCHITECTURAL SUITE ==================================================

+

+/**

+  Test Case

+*/

+UNIT_TEST_STATUS

+EFIAPI

+ShouldBeAbleToInitAndDeinitTheLibrary (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  EFI_STATUS    Status;

+  Status = InitVariablePolicyLib( StubGetVariableNull );

+  UT_ASSERT_NOT_EFI_ERROR( Status );

+

+  UT_ASSERT_TRUE( IsVariablePolicyLibInitialized() );

+

+  Status = DeinitVariablePolicyLib();

+  UT_ASSERT_NOT_EFI_ERROR( Status );

+

+  UT_ASSERT_FALSE( IsVariablePolicyLibInitialized() );

+

+  return UNIT_TEST_PASSED;

+}

+

+/**

+  Test Case

+*/

+UNIT_TEST_STATUS

+EFIAPI

+ShouldNotBeAbleToInitializeTheLibraryTwice (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  EFI_STATUS    Status;

+  Status = InitVariablePolicyLib( StubGetVariableNull );

+  UT_ASSERT_NOT_EFI_ERROR( Status );

+  Status = InitVariablePolicyLib( StubGetVariableNull );

+  UT_ASSERT_TRUE( EFI_ERROR( Status ) );

+  return UNIT_TEST_PASSED;

+}

+

+/**

+  Test Case

+*/

+UNIT_TEST_STATUS

+EFIAPI

+ShouldFailDeinitWithoutInit (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  EFI_STATUS    Status;

+  Status = DeinitVariablePolicyLib();

+  UT_ASSERT_TRUE( EFI_ERROR( Status ) );

+  return UNIT_TEST_PASSED;

+}

+

+/**

+  Test Case

+*/

+UNIT_TEST_STATUS

+EFIAPI

+ApiCommandsShouldNotRespondIfLibIsUninitialized (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  SIMPLE_VARIABLE_POLICY_ENTRY   TestPolicy = {

+    {

+      VARIABLE_POLICY_ENTRY_REVISION,

+      sizeof(VARIABLE_POLICY_ENTRY) + sizeof(TEST_VAR_1_NAME),

+      sizeof(VARIABLE_POLICY_ENTRY),

+      TEST_GUID_1,

+      TEST_POLICY_MIN_SIZE_NULL,

+      TEST_POLICY_MAX_SIZE_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      VARIABLE_POLICY_TYPE_NO_LOCK

+    },

+    TEST_VAR_1_NAME

+  };

+  UINT8     DummyData[8];

+  UINT32    DummyDataSize = sizeof(DummyData);

+

+  // This test should not start with an initialized library.

+

+  // Verify that all API commands fail.

+  UT_ASSERT_TRUE( EFI_ERROR( LockVariablePolicy() ) );

+  UT_ASSERT_TRUE( EFI_ERROR( DisableVariablePolicy() ) );

+  UT_ASSERT_TRUE( EFI_ERROR( RegisterVariablePolicy( &TestPolicy.Header ) ) );

+  UT_ASSERT_TRUE( EFI_ERROR( DumpVariablePolicy( DummyData, &DummyDataSize ) ) );

+  UT_ASSERT_FALSE( IsVariablePolicyInterfaceLocked() );

+  UT_ASSERT_FALSE( IsVariablePolicyEnabled() );

+  UT_ASSERT_TRUE( EFI_ERROR( ValidateSetVariable( TEST_VAR_1_NAME,

+                                                 &mTestGuid1,

+                                                 VARIABLE_ATTRIBUTE_NV_BS,

+                                                 sizeof(DummyData),

+                                                 DummyData ) ) );

+

+  return UNIT_TEST_PASSED;

+}

+

+

+///===== INTERNAL FUNCTION SUITE ==============================================

+

+#ifdef INTERNAL_UNIT_TEST

+

+BOOLEAN

+EvaluatePolicyMatch (

+  IN CONST  VARIABLE_POLICY_ENTRY   *EvalEntry,

+  IN CONST  CHAR16                  *VariableName,

+  IN CONST  EFI_GUID                *VendorGuid,

+  OUT       UINT8                   *MatchPriority    OPTIONAL

+  );

+

+/**

+  Test Case

+*/

+UNIT_TEST_STATUS

+EFIAPI

+PoliciesShouldMatchByNameAndGuid (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  SIMPLE_VARIABLE_POLICY_ENTRY   MatchCheckPolicy = {

+    {

+      VARIABLE_POLICY_ENTRY_REVISION,

+      sizeof(VARIABLE_POLICY_ENTRY) + sizeof(TEST_VAR_1_NAME),

+      sizeof(VARIABLE_POLICY_ENTRY),

+      TEST_GUID_1,

+      TEST_POLICY_MIN_SIZE_NULL,

+      TEST_POLICY_MAX_SIZE_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      VARIABLE_POLICY_TYPE_NO_LOCK

+    },

+    TEST_VAR_1_NAME

+  };

+  CHAR16        *CheckVar1Name = TEST_VAR_1_NAME;

+  CHAR16        *CheckVar2Name = TEST_VAR_2_NAME;

+

+  // Make sure that a different name does not match.

+  UT_ASSERT_FALSE( EvaluatePolicyMatch( &MatchCheckPolicy.Header, CheckVar2Name, &mTestGuid1, NULL ) );

+

+  // Make sure that a different GUID does not match.

+  UT_ASSERT_FALSE( EvaluatePolicyMatch( &MatchCheckPolicy.Header, CheckVar1Name, &mTestGuid2, NULL ) );

+

+  // Make sure that the same name and GUID match.

+  UT_ASSERT_TRUE( EvaluatePolicyMatch( &MatchCheckPolicy.Header, CheckVar1Name, &mTestGuid1, NULL ) );

+

+  return UNIT_TEST_PASSED;

+}

+

+/**

+  Test Case

+*/

+UNIT_TEST_STATUS

+EFIAPI

+WildcardPoliciesShouldMatchDigits (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  SIMPLE_VARIABLE_POLICY_ENTRY   MatchCheckPolicy = {

+    {

+      VARIABLE_POLICY_ENTRY_REVISION,

+      sizeof(VARIABLE_POLICY_ENTRY) + sizeof(L"Wildcard#VarName##"),

+      sizeof(VARIABLE_POLICY_ENTRY),

+      TEST_GUID_1,

+      TEST_POLICY_MIN_SIZE_NULL,

+      TEST_POLICY_MAX_SIZE_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      VARIABLE_POLICY_TYPE_NO_LOCK

+    },

+    L"Wildcard#VarName##"

+  };

+  CHAR16        *CheckVar1Name = L"Wildcard1VarName12";

+  CHAR16        *CheckVar2Name = L"Wildcard2VarName34";

+  CHAR16        *CheckVarBName = L"WildcardBVarName56";

+  CHAR16        *CheckVarHName = L"Wildcard#VarName56";

+

+  // Make sure that two different sets of wildcard numbers match.

+  UT_ASSERT_TRUE( EvaluatePolicyMatch( &MatchCheckPolicy.Header, CheckVar1Name, &mTestGuid1, NULL ) );

+  UT_ASSERT_TRUE( EvaluatePolicyMatch( &MatchCheckPolicy.Header, CheckVar2Name, &mTestGuid1, NULL ) );

+

+  // Make sure that the non-number charaters don't match.

+  UT_ASSERT_FALSE( EvaluatePolicyMatch( &MatchCheckPolicy.Header, CheckVarBName, &mTestGuid1, NULL ) );

+

+  // Make sure that '#' signs don't match.

+  UT_ASSERT_FALSE( EvaluatePolicyMatch( &MatchCheckPolicy.Header, CheckVarHName, &mTestGuid1, NULL ) );

+

+  return UNIT_TEST_PASSED;

+}

+

+/**

+  Test Case

+*/

+UNIT_TEST_STATUS

+EFIAPI

+WildcardPoliciesShouldMatchDigitsAdvanced (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  SIMPLE_VARIABLE_POLICY_ENTRY   MatchCheckPolicy = {

+    {

+      VARIABLE_POLICY_ENTRY_REVISION,

+      sizeof(VARIABLE_POLICY_ENTRY) + sizeof(TEST_300_HASHES_STRING),

+      sizeof(VARIABLE_POLICY_ENTRY),

+      TEST_GUID_1,

+      TEST_POLICY_MIN_SIZE_NULL,

+      TEST_POLICY_MAX_SIZE_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      VARIABLE_POLICY_TYPE_NO_LOCK

+    },

+    TEST_300_HASHES_STRING

+  };

+  CHAR16        *CheckShorterString = L"01234567890123456789012345678901234567890123456789";

+  CHAR16        *CheckValidString = L"01234567890123456789012345678901234567890123456789"\

+                                      "01234567890123456789012345678901234567890123456789"\

+                                      "01234567890123456789012345678901234567890123456789"\

+                                      "01234567890123456789012345678901234567890123456789"\

+                                      "01234567890123456789012345678901234567890123456789"\

+                                      "01234567890123456789012345678901234567890123456789";

+  CHAR16        *CheckLongerString = L"01234567890123456789012345678901234567890123456789"\

+                                      "01234567890123456789012345678901234567890123456789"\

+                                      "01234567890123456789012345678901234567890123456789"\

+                                      "01234567890123456789012345678901234567890123456789"\

+                                      "01234567890123456789012345678901234567890123456789"\

+                                      "01234567890123456789012345678901234567890123456789"\

+                                      "01234567890123456789012345678901234567890123456789";

+  UINT8         MatchPriority;

+

+  // Make sure that the shorter and the longer do not match.

+  UT_ASSERT_FALSE( EvaluatePolicyMatch( &MatchCheckPolicy.Header, CheckShorterString, &mTestGuid1, NULL ) );

+  UT_ASSERT_FALSE( EvaluatePolicyMatch( &MatchCheckPolicy.Header, CheckLongerString, &mTestGuid1, NULL ) );

+

+  // Make sure that the valid one matches and has the expected priority.

+  UT_ASSERT_TRUE( EvaluatePolicyMatch( &MatchCheckPolicy.Header, CheckValidString, &mTestGuid1, &MatchPriority ) );

+  UT_ASSERT_EQUAL( MatchPriority, MAX_UINT8 );

+

+  return UNIT_TEST_PASSED;

+}

+

+/**

+  Test Case

+*/

+UNIT_TEST_STATUS

+EFIAPI

+WildcardPoliciesShouldMatchNamespaces (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  VARIABLE_POLICY_ENTRY   MatchCheckPolicy = {

+    VARIABLE_POLICY_ENTRY_REVISION,

+    sizeof(VARIABLE_POLICY_ENTRY),

+    sizeof(VARIABLE_POLICY_ENTRY),

+    TEST_GUID_1,

+    TEST_POLICY_MIN_SIZE_NULL,

+    TEST_POLICY_MAX_SIZE_NULL,

+    TEST_POLICY_ATTRIBUTES_NULL,

+    TEST_POLICY_ATTRIBUTES_NULL,

+    VARIABLE_POLICY_TYPE_NO_LOCK

+  };

+  CHAR16        *CheckVar1Name = L"Wildcard1VarName12";

+  CHAR16        *CheckVar2Name = L"Wildcard2VarName34";

+  CHAR16        *CheckVarBName = L"WildcardBVarName56";

+  CHAR16        *CheckVarHName = L"Wildcard#VarName56";

+

+  // Make sure that all names in the same namespace match.

+  UT_ASSERT_TRUE( EvaluatePolicyMatch( &MatchCheckPolicy, CheckVar1Name, &mTestGuid1, NULL ) );

+  UT_ASSERT_TRUE( EvaluatePolicyMatch( &MatchCheckPolicy, CheckVar2Name, &mTestGuid1, NULL ) );

+  UT_ASSERT_TRUE( EvaluatePolicyMatch( &MatchCheckPolicy, CheckVarBName, &mTestGuid1, NULL ) );

+  UT_ASSERT_TRUE( EvaluatePolicyMatch( &MatchCheckPolicy, CheckVarHName, &mTestGuid1, NULL ) );

+

+  // Make sure that different namespace doesn't match.

+  UT_ASSERT_FALSE( EvaluatePolicyMatch( &MatchCheckPolicy, CheckVar1Name, &mTestGuid2, NULL ) );

+

+

+  return UNIT_TEST_PASSED;

+}

+

+/**

+  Test Case

+*/

+UNIT_TEST_STATUS

+EFIAPI

+MatchPrioritiesShouldFollowRules (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  SIMPLE_VARIABLE_POLICY_ENTRY   MatchCheckPolicy = {

+    {

+      VARIABLE_POLICY_ENTRY_REVISION,

+      sizeof(VARIABLE_POLICY_ENTRY) + sizeof(L"Wildcard1VarName12"),

+      sizeof(VARIABLE_POLICY_ENTRY),

+      TEST_GUID_1,

+      TEST_POLICY_MIN_SIZE_NULL,

+      TEST_POLICY_MAX_SIZE_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      VARIABLE_POLICY_TYPE_NO_LOCK

+    },

+    L"Wildcard1VarName12"

+  };

+  CHAR16        CheckVar1Name[] = L"Wildcard1VarName12";

+  CHAR16        MatchVar1Name[] = L"Wildcard1VarName12";

+  CHAR16        MatchVar2Name[] = L"Wildcard#VarName12";

+  CHAR16        MatchVar3Name[] = L"Wildcard#VarName#2";

+  CHAR16        MatchVar4Name[] = L"Wildcard#VarName##";

+  UINT8         MatchPriority;

+

+  // Check with a perfect match.

+  CopyMem( &MatchCheckPolicy.Name, MatchVar1Name, sizeof(MatchVar1Name) );

+  UT_ASSERT_TRUE( EvaluatePolicyMatch( &MatchCheckPolicy.Header, CheckVar1Name, &mTestGuid1, &MatchPriority ) );

+  UT_ASSERT_EQUAL( MatchPriority, 0 );

+

+  // Check with progressively lower priority matches.

+  CopyMem( &MatchCheckPolicy.Name, MatchVar2Name, sizeof(MatchVar2Name) );

+  UT_ASSERT_TRUE( EvaluatePolicyMatch( &MatchCheckPolicy.Header, CheckVar1Name, &mTestGuid1, &MatchPriority ) );

+  UT_ASSERT_EQUAL( MatchPriority, 1 );

+  CopyMem( &MatchCheckPolicy.Name, MatchVar3Name, sizeof(MatchVar3Name) );

+  UT_ASSERT_TRUE( EvaluatePolicyMatch( &MatchCheckPolicy.Header, CheckVar1Name, &mTestGuid1, &MatchPriority ) );

+  UT_ASSERT_EQUAL( MatchPriority, 2 );

+  CopyMem( &MatchCheckPolicy.Name, MatchVar4Name, sizeof(MatchVar4Name) );

+  UT_ASSERT_TRUE( EvaluatePolicyMatch( &MatchCheckPolicy.Header, CheckVar1Name, &mTestGuid1, &MatchPriority ) );

+  UT_ASSERT_EQUAL( MatchPriority, 3 );

+

+  // Check against the entire namespace.

+  MatchCheckPolicy.Header.Size = sizeof(VARIABLE_POLICY_ENTRY);

+  UT_ASSERT_TRUE( EvaluatePolicyMatch( &MatchCheckPolicy.Header, CheckVar1Name, &mTestGuid1, &MatchPriority ) );

+  UT_ASSERT_EQUAL( MatchPriority, MAX_UINT8 );

+

+  return UNIT_TEST_PASSED;

+}

+

+#endif // INTERNAL_UNIT_TEST

+

+

+///=== POLICY MANIPULATION SUITE ==============================================

+

+/**

+  Test Case

+*/

+UNIT_TEST_STATUS

+EFIAPI

+RegisterShouldAllowNamespaceWildcards (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  SIMPLE_VARIABLE_POLICY_ENTRY   ValidationPolicy = {

+    {

+      VARIABLE_POLICY_ENTRY_REVISION,

+      sizeof(VARIABLE_POLICY_ENTRY),

+      sizeof(VARIABLE_POLICY_ENTRY),

+      TEST_GUID_1,

+      TEST_POLICY_MIN_SIZE_NULL,

+      TEST_POLICY_MAX_SIZE_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      VARIABLE_POLICY_TYPE_NO_LOCK

+    },

+    L""

+  };

+

+  UT_ASSERT_NOT_EFI_ERROR( RegisterVariablePolicy( &ValidationPolicy.Header ) );

+

+  return UNIT_TEST_PASSED;

+}

+

+/**

+  Test Case

+*/

+UNIT_TEST_STATUS

+EFIAPI

+RegisterShouldAllowStateVarsForNamespaces (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  EXPANDED_VARIABLE_POLICY_ENTRY   ValidationPolicy = {

+    {

+      VARIABLE_POLICY_ENTRY_REVISION,

+      0,    // Will be populated by init helper.

+      0,    // Will be populated by init helper.

+      TEST_GUID_1,

+      TEST_POLICY_MIN_SIZE_NULL,

+      TEST_POLICY_MAX_SIZE_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE

+    },

+    {

+      TEST_GUID_2,

+      1,            // Value

+      0             // Padding

+    },

+    L"",

+    L""

+  };

+  UT_ASSERT_TRUE( InitExpVarPolicyStrings( &ValidationPolicy, NULL, TEST_VAR_2_NAME ) );

+

+  UT_ASSERT_NOT_EFI_ERROR( RegisterVariablePolicy( &ValidationPolicy.Header ) );

+

+  return UNIT_TEST_PASSED;

+}

+

+/**

+  Test Case

+*/

+UNIT_TEST_STATUS

+EFIAPI

+RegisterShouldRejectNullPointers (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  UT_ASSERT_EQUAL( RegisterVariablePolicy( NULL ), EFI_INVALID_PARAMETER );

+  return UNIT_TEST_PASSED;

+}

+

+/**

+  Test Case

+*/

+UNIT_TEST_STATUS

+EFIAPI

+RegisterShouldRejectBadRevisions (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  SIMPLE_VARIABLE_POLICY_ENTRY   ValidationPolicy = {

+    {

+      VARIABLE_POLICY_ENTRY_REVISION,

+      sizeof(VARIABLE_POLICY_ENTRY) + sizeof(TEST_VAR_1_NAME),

+      sizeof(VARIABLE_POLICY_ENTRY),

+      TEST_GUID_1,

+      TEST_POLICY_MIN_SIZE_NULL,

+      TEST_POLICY_MAX_SIZE_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      VARIABLE_POLICY_TYPE_NO_LOCK

+    },

+    TEST_VAR_1_NAME

+  };

+

+  ValidationPolicy.Header.Version = MAX_UINT32;

+  UT_ASSERT_EQUAL( RegisterVariablePolicy( &ValidationPolicy.Header ), EFI_INVALID_PARAMETER );

+

+  return UNIT_TEST_PASSED;

+}

+

+/**

+  Test Case

+*/

+UNIT_TEST_STATUS

+EFIAPI

+RegisterShouldRejectBadSizes (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  SIMPLE_VARIABLE_POLICY_ENTRY   ValidationPolicy = {

+    {

+      VARIABLE_POLICY_ENTRY_REVISION,

+      sizeof(VARIABLE_POLICY_ENTRY) + sizeof(TEST_VAR_1_NAME),

+      sizeof(VARIABLE_POLICY_ENTRY),

+      TEST_GUID_1,

+      TEST_POLICY_MIN_SIZE_NULL,

+      TEST_POLICY_MAX_SIZE_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      VARIABLE_POLICY_TYPE_NO_LOCK

+    },

+    TEST_VAR_1_NAME

+  };

+

+  ValidationPolicy.Header.Size = sizeof(VARIABLE_POLICY_ENTRY) - 2;

+  UT_ASSERT_EQUAL( RegisterVariablePolicy( &ValidationPolicy.Header ), EFI_INVALID_PARAMETER );

+

+  return UNIT_TEST_PASSED;

+}

+

+/**

+  Test Case

+*/

+UNIT_TEST_STATUS

+EFIAPI

+RegisterShouldRejectBadOffsets (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  EXPANDED_VARIABLE_POLICY_ENTRY   ValidationPolicy = {

+    {

+      VARIABLE_POLICY_ENTRY_REVISION,

+      0,    // Will be populated by init helper.

+      0,    // Will be populated by init helper.

+      TEST_GUID_1,

+      TEST_POLICY_MIN_SIZE_NULL,

+      TEST_POLICY_MAX_SIZE_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE

+    },

+    {

+      TEST_GUID_2,

+      1,            // Value

+      0             // Padding

+    },

+    L"",

+    L""

+  };

+  UT_ASSERT_TRUE( InitExpVarPolicyStrings( &ValidationPolicy, TEST_VAR_1_NAME, TEST_VAR_2_NAME ) );

+

+  // Check for an offset outside the size bounds.

+  ValidationPolicy.Header.OffsetToName = ValidationPolicy.Header.Size + 1;

+  UT_ASSERT_EQUAL( RegisterVariablePolicy( &ValidationPolicy.Header ), EFI_INVALID_PARAMETER );

+

+  // Check for an offset inside the policy header.

+  ValidationPolicy.Header.OffsetToName = sizeof(VARIABLE_POLICY_ENTRY) - 2;

+  UT_ASSERT_EQUAL( RegisterVariablePolicy( &ValidationPolicy.Header ), EFI_INVALID_PARAMETER );

+

+  // Check for an offset inside the state policy header.

+  ValidationPolicy.Header.OffsetToName = sizeof(VARIABLE_POLICY_ENTRY) + 2;

+  UT_ASSERT_EQUAL( RegisterVariablePolicy( &ValidationPolicy.Header ), EFI_INVALID_PARAMETER );

+

+  // Check for a ridiculous offset.

+  ValidationPolicy.Header.OffsetToName = MAX_UINT16;

+  UT_ASSERT_EQUAL( RegisterVariablePolicy( &ValidationPolicy.Header ), EFI_INVALID_PARAMETER );

+

+  return UNIT_TEST_PASSED;

+}

+

+/**

+  Test Case

+*/

+UNIT_TEST_STATUS

+EFIAPI

+RegisterShouldRejectMissingStateStrings (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  EXPANDED_VARIABLE_POLICY_ENTRY   ValidationPolicy = {

+    {

+      VARIABLE_POLICY_ENTRY_REVISION,

+      0,    // Will be populated by init helper.

+      0,    // Will be populated by init helper.

+      TEST_GUID_1,

+      TEST_POLICY_MIN_SIZE_NULL,

+      TEST_POLICY_MAX_SIZE_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE

+    },

+    {

+      TEST_GUID_2,

+      1,            // Value

+      0             // Padding

+    },

+    L"",

+    L""

+  };

+  UT_ASSERT_TRUE( InitExpVarPolicyStrings( &ValidationPolicy, TEST_VAR_1_NAME, TEST_VAR_2_NAME ) );

+

+  // Remove the state string and copy the Name into it's place.

+  // Also adjust the offset.

+  ValidationPolicy.Header.Size          = sizeof(VARIABLE_POLICY_ENTRY) + sizeof(VARIABLE_LOCK_ON_VAR_STATE_POLICY) + sizeof(TEST_VAR_1_NAME);

+  ValidationPolicy.Header.OffsetToName  = sizeof(VARIABLE_POLICY_ENTRY) + sizeof(VARIABLE_LOCK_ON_VAR_STATE_POLICY);

+  CopyMem( (UINT8*)&ValidationPolicy + ValidationPolicy.Header.OffsetToName, TEST_VAR_1_NAME, sizeof(TEST_VAR_1_NAME) );

+

+  // Make sure that this structure fails.

+  UT_ASSERT_EQUAL( RegisterVariablePolicy( &ValidationPolicy.Header ), EFI_INVALID_PARAMETER );

+

+  return UNIT_TEST_PASSED;

+}

+

+/**

+  Test Case

+*/

+UNIT_TEST_STATUS

+EFIAPI

+RegisterShouldRejectStringsMissingNull (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  EXPANDED_VARIABLE_POLICY_ENTRY   ValidationPolicy = {

+    {

+      VARIABLE_POLICY_ENTRY_REVISION,

+      0,    // Will be populated by init helper.

+      0,    // Will be populated by init helper.

+      TEST_GUID_1,

+      TEST_POLICY_MIN_SIZE_NULL,

+      TEST_POLICY_MAX_SIZE_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE

+    },

+    {

+      TEST_GUID_2,

+      1,            // Value

+      0             // Padding

+    },

+    L"",

+    L""

+  };

+  UT_ASSERT_TRUE( InitExpVarPolicyStrings( &ValidationPolicy, TEST_VAR_1_NAME, TEST_VAR_2_NAME ) );

+

+  // Removing the NULL from the Name should fail.

+  ValidationPolicy.Header.Size = ValidationPolicy.Header.Size - sizeof(CHAR16);

+  UT_ASSERT_EQUAL( RegisterVariablePolicy( &ValidationPolicy.Header ), EFI_INVALID_PARAMETER );

+

+  // Removing the NULL from the State Name is a little trickier.

+  // Copy the Name up one byte.

+  ValidationPolicy.Header.OffsetToName = ValidationPolicy.Header.OffsetToName - sizeof(CHAR16);

+  CopyMem( (UINT8*)&ValidationPolicy + ValidationPolicy.Header.OffsetToName, TEST_VAR_1_NAME, sizeof(TEST_VAR_1_NAME) );

+  UT_ASSERT_EQUAL( RegisterVariablePolicy( &ValidationPolicy.Header ), EFI_INVALID_PARAMETER );

+

+  return UNIT_TEST_PASSED;

+}

+

+/**

+  Test Case

+*/

+UNIT_TEST_STATUS

+EFIAPI

+RegisterShouldRejectMalformedStrings (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  EXPANDED_VARIABLE_POLICY_ENTRY   ValidationPolicy = {

+    {

+      VARIABLE_POLICY_ENTRY_REVISION,

+      0,    // Will be populated by init helper.

+      0,    // Will be populated by init helper.

+      TEST_GUID_1,

+      TEST_POLICY_MIN_SIZE_NULL,

+      TEST_POLICY_MAX_SIZE_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE

+    },

+    {

+      TEST_GUID_2,

+      1,            // Value

+      0             // Padding

+    },

+    L"",

+    L""

+  };

+  UT_ASSERT_TRUE( InitExpVarPolicyStrings( &ValidationPolicy, TEST_VAR_1_NAME, TEST_VAR_2_NAME ) );

+

+  // Bisecting the NULL from the Name should fail.

+  ValidationPolicy.Header.Size = ValidationPolicy.Header.Size - 1;

+  UT_ASSERT_EQUAL( RegisterVariablePolicy( &ValidationPolicy.Header ), EFI_INVALID_PARAMETER );

+

+  // Bisecting the NULL from the State Name is a little trickier.

+  // Copy the Name up one byte.

+  ValidationPolicy.Header.OffsetToName = ValidationPolicy.Header.OffsetToName - 1;

+  CopyMem( (UINT8*)&ValidationPolicy + ValidationPolicy.Header.OffsetToName, TEST_VAR_1_NAME, sizeof(TEST_VAR_1_NAME) );

+  UT_ASSERT_EQUAL( RegisterVariablePolicy( &ValidationPolicy.Header ), EFI_INVALID_PARAMETER );

+

+  return UNIT_TEST_PASSED;

+}

+

+/**

+  Test Case

+*/

+UNIT_TEST_STATUS

+EFIAPI

+RegisterShouldRejectUnpackedPolicies (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  EXPANDED_VARIABLE_POLICY_ENTRY   ValidationPolicy = {

+    {

+      VARIABLE_POLICY_ENTRY_REVISION,

+      0,    // Will be populated by init helper.

+      0,    // Will be populated by init helper.

+      TEST_GUID_1,

+      TEST_POLICY_MIN_SIZE_NULL,

+      TEST_POLICY_MAX_SIZE_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE

+    },

+    {

+      TEST_GUID_2,

+      1,            // Value

+      0             // Padding

+    },

+    L"",

+    L""

+  };

+  UT_ASSERT_TRUE( InitExpVarPolicyStrings( &ValidationPolicy, TEST_VAR_1_NAME, TEST_VAR_2_NAME ) );

+

+  // Increase the size and move the Name out a bit.

+  ValidationPolicy.Header.Size = ValidationPolicy.Header.Size + sizeof(CHAR16);

+  ValidationPolicy.Header.OffsetToName = ValidationPolicy.Header.OffsetToName + sizeof(CHAR16);

+  CopyMem( (UINT8*)&ValidationPolicy + ValidationPolicy.Header.OffsetToName, TEST_VAR_1_NAME, sizeof(TEST_VAR_1_NAME) );

+  UT_ASSERT_EQUAL( RegisterVariablePolicy( &ValidationPolicy.Header ), EFI_INVALID_PARAMETER );

+

+  // Reintialize without the state policy and try the same test.

+  ValidationPolicy.Header.LockPolicyType = VARIABLE_POLICY_TYPE_NO_LOCK;

+  UT_ASSERT_TRUE( InitExpVarPolicyStrings( &ValidationPolicy, TEST_VAR_1_NAME, NULL ) );

+  ValidationPolicy.Header.Size = ValidationPolicy.Header.Size + sizeof(CHAR16);

+  ValidationPolicy.Header.OffsetToName = ValidationPolicy.Header.OffsetToName + sizeof(CHAR16);

+  CopyMem( (UINT8*)&ValidationPolicy + ValidationPolicy.Header.OffsetToName, TEST_VAR_1_NAME, sizeof(TEST_VAR_1_NAME) );

+  UT_ASSERT_EQUAL( RegisterVariablePolicy( &ValidationPolicy.Header ), EFI_INVALID_PARAMETER );

+

+  return UNIT_TEST_PASSED;

+}

+

+/**

+  Test Case

+*/

+UNIT_TEST_STATUS

+EFIAPI

+RegisterShouldRejectInvalidNameCharacters (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  // EXPANDED_VARIABLE_POLICY_ENTRY   ValidationPolicy = {

+  //   {

+  //     VARIABLE_POLICY_ENTRY_REVISION,

+  //     0,    // Will be populated by init helper.

+  //     0,    // Will be populated by init helper.

+  //     TEST_GUID_1,

+  //     TEST_POLICY_MIN_SIZE_NULL,

+  //     TEST_POLICY_MAX_SIZE_NULL,

+  //     TEST_POLICY_ATTRIBUTES_NULL,

+  //     TEST_POLICY_ATTRIBUTES_NULL,

+  //     VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE

+  //   },

+  //   {

+  //     TEST_GUID_2,

+  //     1,            // Value

+  //     0             // Padding

+  //   },

+  //   L"",

+  //   L""

+  // };

+

+  // Currently, there are no known invalid characters.

+  // '#' in LockPolicy->Name are taken as literal.

+

+  return UNIT_TEST_PASSED;

+}

+

+/**

+  Test Case

+*/

+UNIT_TEST_STATUS

+EFIAPI

+RegisterShouldRejectBadPolicyConstraints (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  SIMPLE_VARIABLE_POLICY_ENTRY   ValidationPolicy = {

+    {

+      VARIABLE_POLICY_ENTRY_REVISION,

+      sizeof(VARIABLE_POLICY_ENTRY) + sizeof(TEST_VAR_1_NAME),

+      sizeof(VARIABLE_POLICY_ENTRY),

+      TEST_GUID_1,

+      TEST_POLICY_MIN_SIZE_NULL,

+      TEST_POLICY_MAX_SIZE_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      VARIABLE_POLICY_TYPE_NO_LOCK

+    },

+    TEST_VAR_1_NAME

+  };

+

+  // Make sure that invalid MAXes are rejected.

+  ValidationPolicy.Header.MaxSize = 0;

+  UT_ASSERT_EQUAL( RegisterVariablePolicy( &ValidationPolicy.Header ), EFI_INVALID_PARAMETER );

+

+  return UNIT_TEST_PASSED;

+}

+

+/**

+  Test Case

+*/

+UNIT_TEST_STATUS

+EFIAPI

+RegisterShouldRejectUnknownLockPolicies (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  SIMPLE_VARIABLE_POLICY_ENTRY   ValidationPolicy = {

+    {

+      VARIABLE_POLICY_ENTRY_REVISION,

+      sizeof(VARIABLE_POLICY_ENTRY) + sizeof(TEST_VAR_1_NAME),

+      sizeof(VARIABLE_POLICY_ENTRY),

+      TEST_GUID_1,

+      TEST_POLICY_MIN_SIZE_NULL,

+      TEST_POLICY_MAX_SIZE_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      VARIABLE_POLICY_TYPE_NO_LOCK

+    },

+    TEST_VAR_1_NAME

+  };

+

+  ValidationPolicy.Header.LockPolicyType = VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE + 1;

+  UT_ASSERT_EQUAL( RegisterVariablePolicy( &ValidationPolicy.Header ), EFI_INVALID_PARAMETER );

+  ValidationPolicy.Header.LockPolicyType = VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE + 1;

+  UT_ASSERT_EQUAL( RegisterVariablePolicy( &ValidationPolicy.Header ), EFI_INVALID_PARAMETER );

+

+  return UNIT_TEST_PASSED;

+}

+

+/**

+  Test Case

+*/

+UNIT_TEST_STATUS

+EFIAPI

+RegisterShouldRejectPolicesWithTooManyWildcards (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  SIMPLE_VARIABLE_POLICY_ENTRY   ValidationPolicy = {

+    {

+      VARIABLE_POLICY_ENTRY_REVISION,

+      sizeof(VARIABLE_POLICY_ENTRY) + sizeof(TEST_300_HASHES_STRING),

+      sizeof(VARIABLE_POLICY_ENTRY),

+      TEST_GUID_1,

+      TEST_POLICY_MIN_SIZE_NULL,

+      TEST_POLICY_MAX_SIZE_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      VARIABLE_POLICY_TYPE_NO_LOCK

+    },

+    TEST_300_HASHES_STRING

+  };

+

+  // 300 Hashes is currently larger than the possible maximum match priority.

+  UT_ASSERT_EQUAL( RegisterVariablePolicy( &ValidationPolicy.Header ), EFI_INVALID_PARAMETER );

+

+  return UNIT_TEST_PASSED;

+}

+

+/**

+  Test Case

+*/

+UNIT_TEST_STATUS

+EFIAPI

+RegisterShouldRejectDuplicatePolicies (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  SIMPLE_VARIABLE_POLICY_ENTRY   ValidationPolicy = {

+    {

+      VARIABLE_POLICY_ENTRY_REVISION,

+      sizeof(VARIABLE_POLICY_ENTRY) + sizeof(TEST_VAR_1_NAME),

+      sizeof(VARIABLE_POLICY_ENTRY),

+      TEST_GUID_1,

+      TEST_POLICY_MIN_SIZE_NULL,

+      TEST_POLICY_MAX_SIZE_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      VARIABLE_POLICY_TYPE_NO_LOCK

+    },

+    TEST_VAR_1_NAME

+  };

+

+  UT_ASSERT_NOT_EFI_ERROR( RegisterVariablePolicy( &ValidationPolicy.Header ) );

+  UT_ASSERT_STATUS_EQUAL( RegisterVariablePolicy( &ValidationPolicy.Header ), EFI_ALREADY_STARTED );

+

+  return UNIT_TEST_PASSED;

+}

+

+/**

+  Test Case

+*/

+UNIT_TEST_STATUS

+EFIAPI

+MinAndMaxSizePoliciesShouldBeHonored (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  SIMPLE_VARIABLE_POLICY_ENTRY   ValidationPolicy = {

+    {

+      VARIABLE_POLICY_ENTRY_REVISION,

+      sizeof(VARIABLE_POLICY_ENTRY) + sizeof(TEST_VAR_1_NAME),

+      sizeof(VARIABLE_POLICY_ENTRY),

+      TEST_GUID_1,

+      TEST_POLICY_MIN_SIZE_10,

+      TEST_POLICY_MAX_SIZE_200,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      VARIABLE_POLICY_TYPE_NO_LOCK

+    },

+    TEST_VAR_1_NAME

+  };

+  EFI_STATUS  PolicyCheck;

+  UINT8       DummyData[TEST_POLICY_MAX_SIZE_200+1];

+

+

+  // Without a policy, there should be no constraints on variable creation.

+  PolicyCheck = ValidateSetVariable( TEST_VAR_1_NAME,

+                                    &mTestGuid1,

+                                    VARIABLE_ATTRIBUTE_NV_BS,

+                                    TEST_POLICY_MAX_SIZE_200+1,

+                                    DummyData );

+  UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );

+

+  // Set a policy to test against.

+  UT_ASSERT_NOT_EFI_ERROR( RegisterVariablePolicy( &ValidationPolicy.Header ) );

+

+  // With a policy, make sure that sizes outsize the target range fail.

+  PolicyCheck = ValidateSetVariable( TEST_VAR_1_NAME,

+                                    &mTestGuid1,

+                                    VARIABLE_ATTRIBUTE_NV_BS,

+                                    TEST_POLICY_MAX_SIZE_200+1,

+                                    DummyData );

+  UT_ASSERT_TRUE( EFI_ERROR( PolicyCheck ) );

+

+  // With a policy, make sure that sizes outsize the target range fail.

+  PolicyCheck = ValidateSetVariable( TEST_VAR_1_NAME,

+                                    &mTestGuid1,

+                                    VARIABLE_ATTRIBUTE_NV_BS,

+                                    TEST_POLICY_MIN_SIZE_10-1,

+                                    DummyData );

+  UT_ASSERT_TRUE( EFI_ERROR( PolicyCheck ) );

+

+  // With a policy, make sure a valid variable is still valid.

+  PolicyCheck = ValidateSetVariable( TEST_VAR_1_NAME,

+                                    &mTestGuid1,

+                                    VARIABLE_ATTRIBUTE_NV_BS,

+                                    TEST_POLICY_MIN_SIZE_10+1,

+                                    DummyData );

+  UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );

+

+  return UNIT_TEST_PASSED;

+}

+

+/**

+  Test Case

+*/

+UNIT_TEST_STATUS

+EFIAPI

+AttributeMustPoliciesShouldBeHonored (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  SIMPLE_VARIABLE_POLICY_ENTRY   ValidationPolicy = {

+    {

+      VARIABLE_POLICY_ENTRY_REVISION,

+      sizeof(VARIABLE_POLICY_ENTRY) + sizeof(TEST_VAR_1_NAME),

+      sizeof(VARIABLE_POLICY_ENTRY),

+      TEST_GUID_1,

+      TEST_POLICY_MIN_SIZE_NULL,

+      TEST_POLICY_MAX_SIZE_NULL,

+      VARIABLE_ATTRIBUTE_NV_BS_RT,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      VARIABLE_POLICY_TYPE_NO_LOCK

+    },

+    TEST_VAR_1_NAME

+  };

+  EFI_STATUS  PolicyCheck;

+  UINT8       DummyData[12];

+

+

+  // Without a policy, there should be no constraints on variable creation.

+  PolicyCheck = ValidateSetVariable( TEST_VAR_1_NAME,

+                                    &mTestGuid1,

+                                    TEST_POLICY_ATTRIBUTES_NULL,

+                                    sizeof(DummyData),

+                                    DummyData );

+  UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );

+

+  // Set a policy to test against.

+  UT_ASSERT_NOT_EFI_ERROR( RegisterVariablePolicy( &ValidationPolicy.Header ) );

+

+  // With a policy, make sure that no attributes fail.

+  PolicyCheck = ValidateSetVariable( TEST_VAR_1_NAME,

+                                    &mTestGuid1,

+                                    TEST_POLICY_ATTRIBUTES_NULL,

+                                    sizeof(DummyData),

+                                    DummyData );

+  UT_ASSERT_TRUE( EFI_ERROR( PolicyCheck ) );

+

+  // With a policy, make sure that some -- but not all -- attributes fail.

+  PolicyCheck = ValidateSetVariable( TEST_VAR_1_NAME,

+                                    &mTestGuid1,

+                                    VARIABLE_ATTRIBUTE_BS_RT_AT,

+                                    sizeof(DummyData),

+                                    DummyData );

+  UT_ASSERT_TRUE( EFI_ERROR( PolicyCheck ) );

+

+  // With a policy, make sure that all attributes pass.

+  PolicyCheck = ValidateSetVariable( TEST_VAR_1_NAME,

+                                    &mTestGuid1,

+                                    VARIABLE_ATTRIBUTE_NV_BS_RT,

+                                    sizeof(DummyData),

+                                    DummyData );

+  UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );

+

+  // With a policy, make sure that all attributes -- plus some -- pass.

+  PolicyCheck = ValidateSetVariable( TEST_VAR_1_NAME,

+                                    &mTestGuid1,

+                                    VARIABLE_ATTRIBUTE_NV_BS_RT_AT,

+                                    sizeof(DummyData),

+                                    DummyData );

+  UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );

+

+  return UNIT_TEST_PASSED;

+}

+

+/**

+  Test Case

+*/

+UNIT_TEST_STATUS

+EFIAPI

+AttributeCantPoliciesShouldBeHonored (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  SIMPLE_VARIABLE_POLICY_ENTRY   ValidationPolicy = {

+    {

+      VARIABLE_POLICY_ENTRY_REVISION,

+      sizeof(VARIABLE_POLICY_ENTRY) + sizeof(TEST_VAR_1_NAME),

+      sizeof(VARIABLE_POLICY_ENTRY),

+      TEST_GUID_1,

+      TEST_POLICY_MIN_SIZE_NULL,

+      TEST_POLICY_MAX_SIZE_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS,

+      VARIABLE_POLICY_TYPE_NO_LOCK

+    },

+    TEST_VAR_1_NAME

+  };

+  EFI_STATUS  PolicyCheck;

+  UINT8       DummyData[12];

+

+

+  // Without a policy, there should be no constraints on variable creation.

+  PolicyCheck = ValidateSetVariable( TEST_VAR_1_NAME,

+                                    &mTestGuid1,

+                                    VARIABLE_ATTRIBUTE_BS_RT_AT,

+                                    sizeof(DummyData),

+                                    DummyData );

+  UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );

+

+  // Set a policy to test against.

+  UT_ASSERT_NOT_EFI_ERROR( RegisterVariablePolicy( &ValidationPolicy.Header ) );

+

+  // With a policy, make sure that forbidden attributes fail.

+  PolicyCheck = ValidateSetVariable( TEST_VAR_1_NAME,

+                                    &mTestGuid1,

+                                    EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS,

+                                    sizeof(DummyData),

+                                    DummyData );

+  UT_ASSERT_TRUE( EFI_ERROR( PolicyCheck ) );

+

+  // With a policy, make sure that a mixture of attributes -- including the forbidden -- fail.

+  PolicyCheck = ValidateSetVariable( TEST_VAR_1_NAME,

+                                    &mTestGuid1,

+                                    VARIABLE_ATTRIBUTE_BS_RT_AT,

+                                    sizeof(DummyData),

+                                    DummyData );

+  UT_ASSERT_TRUE( EFI_ERROR( PolicyCheck ) );

+

+  // With a policy, make sure that attributes without the forbidden pass.

+  PolicyCheck = ValidateSetVariable( TEST_VAR_1_NAME,

+                                    &mTestGuid1,

+                                    VARIABLE_ATTRIBUTE_NV_BS_RT,

+                                    sizeof(DummyData),

+                                    DummyData );

+  UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );

+

+  return UNIT_TEST_PASSED;

+}

+

+/**

+  Test Case

+*/

+UNIT_TEST_STATUS

+EFIAPI

+VariablesShouldBeDeletableRegardlessOfSize (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  SIMPLE_VARIABLE_POLICY_ENTRY   ValidationPolicy = {

+    {

+      VARIABLE_POLICY_ENTRY_REVISION,

+      sizeof(VARIABLE_POLICY_ENTRY) + sizeof(TEST_VAR_1_NAME),

+      sizeof(VARIABLE_POLICY_ENTRY),

+      TEST_GUID_1,

+      TEST_POLICY_MIN_SIZE_10,

+      TEST_POLICY_MAX_SIZE_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS,

+      VARIABLE_POLICY_TYPE_NO_LOCK

+    },

+    TEST_VAR_1_NAME

+  };

+  EFI_STATUS  PolicyCheck;

+  UINT8       DummyData[TEST_POLICY_MAX_SIZE_200+1];

+

+  // Create a policy enforcing a minimum variable size.

+  UT_ASSERT_NOT_EFI_ERROR( RegisterVariablePolicy( &ValidationPolicy.Header ) );

+

+  // Make sure that a normal set would fail.

+  PolicyCheck = ValidateSetVariable( TEST_VAR_1_NAME,

+                                    &mTestGuid1,

+                                    VARIABLE_ATTRIBUTE_NV_BS,

+                                    TEST_POLICY_MIN_SIZE_10-1,

+                                    DummyData );

+  UT_ASSERT_STATUS_EQUAL( PolicyCheck, EFI_INVALID_PARAMETER );

+

+  // Now make sure that a delete would succeed.

+  PolicyCheck = ValidateSetVariable( TEST_VAR_1_NAME,

+                                    &mTestGuid1,

+                                    VARIABLE_ATTRIBUTE_NV_BS,

+                                    0,

+                                    NULL );

+  UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );

+

+  return UNIT_TEST_PASSED;

+}

+

+/**

+  Test Case

+*/

+UNIT_TEST_STATUS

+EFIAPI

+LockNowPoliciesShouldBeHonored (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  SIMPLE_VARIABLE_POLICY_ENTRY   ValidationPolicy = {

+    {

+      VARIABLE_POLICY_ENTRY_REVISION,

+      sizeof(VARIABLE_POLICY_ENTRY) + sizeof(TEST_VAR_1_NAME),

+      sizeof(VARIABLE_POLICY_ENTRY),

+      TEST_GUID_1,

+      TEST_POLICY_MIN_SIZE_NULL,

+      TEST_POLICY_MAX_SIZE_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      VARIABLE_POLICY_TYPE_LOCK_NOW

+    },

+    TEST_VAR_1_NAME

+  };

+  EFI_STATUS  PolicyCheck;

+  UINT8       DummyData[12];

+

+

+  // Without a policy, there should be no constraints on variable creation.

+  PolicyCheck = ValidateSetVariable( TEST_VAR_1_NAME,

+                                    &mTestGuid1,

+                                    VARIABLE_ATTRIBUTE_BS_RT_AT,

+                                    sizeof(DummyData),

+                                    DummyData );

+  UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );

+

+  // Set a policy to test against.

+  UT_ASSERT_NOT_EFI_ERROR( RegisterVariablePolicy( &ValidationPolicy.Header ) );

+

+  // With a policy, make sure that writes immediately fail.

+  PolicyCheck = ValidateSetVariable( TEST_VAR_1_NAME,

+                                    &mTestGuid1,

+                                    VARIABLE_ATTRIBUTE_BS_RT_AT,

+                                    sizeof(DummyData),

+                                    DummyData );

+  UT_ASSERT_TRUE( EFI_ERROR( PolicyCheck ) );

+

+  return UNIT_TEST_PASSED;

+}

+

+/**

+  Test Case

+*/

+UNIT_TEST_STATUS

+EFIAPI

+LockOnCreatePoliciesShouldBeHonored (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  SIMPLE_VARIABLE_POLICY_ENTRY   ValidationPolicy = {

+    {

+      VARIABLE_POLICY_ENTRY_REVISION,

+      sizeof(VARIABLE_POLICY_ENTRY) + sizeof(TEST_VAR_1_NAME),

+      sizeof(VARIABLE_POLICY_ENTRY),

+      TEST_GUID_1,

+      TEST_POLICY_MIN_SIZE_NULL,

+      TEST_POLICY_MAX_SIZE_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      VARIABLE_POLICY_TYPE_LOCK_ON_CREATE

+    },

+    TEST_VAR_1_NAME

+  };

+  EFI_STATUS  PolicyCheck;

+  UINT8       DummyData[12];

+  UINTN       ExpectedDataSize;

+

+

+  // Without a policy, there should be no constraints on variable creation.

+  PolicyCheck = ValidateSetVariable( TEST_VAR_1_NAME,

+                                    &mTestGuid1,

+                                    VARIABLE_ATTRIBUTE_BS_RT_AT,

+                                    sizeof(DummyData),

+                                    DummyData );

+  UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );

+

+  // Set a policy to test against.

+  UT_ASSERT_NOT_EFI_ERROR( RegisterVariablePolicy( &ValidationPolicy.Header ) );

+

+  // Set consistent expectations on what the calls are looking for.

+  expect_memory_count( StubGetVariableNull, VariableName, TEST_VAR_1_NAME, sizeof(TEST_VAR_1_NAME), 2 );

+  expect_memory_count( StubGetVariableNull, VendorGuid, &mTestGuid1, sizeof(mTestGuid1), 2 );

+  ExpectedDataSize = 0;

+  expect_memory_count( StubGetVariableNull, DataSize, &ExpectedDataSize, sizeof(ExpectedDataSize), 2 );

+

+  // With a policy, make sure that writes still work, since the variable doesn't exist.

+  will_return( StubGetVariableNull, TEST_POLICY_ATTRIBUTES_NULL );    // Attributes

+  will_return( StubGetVariableNull, 0 );                              // Size

+  will_return( StubGetVariableNull, NULL );                           // DataPtr

+  will_return( StubGetVariableNull, EFI_NOT_FOUND );                  // Status

+  PolicyCheck = ValidateSetVariable( TEST_VAR_1_NAME,

+                                    &mTestGuid1,

+                                    VARIABLE_ATTRIBUTE_BS_RT_AT,

+                                    sizeof(DummyData),

+                                    DummyData );

+  UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );

+

+  // With a policy, make sure that a call with an "existing" variable fails.

+  will_return( StubGetVariableNull, TEST_POLICY_ATTRIBUTES_NULL );    // Attributes

+  will_return( StubGetVariableNull, 10 );                             // Size

+  will_return( StubGetVariableNull, NULL );                           // DataPtr

+  will_return( StubGetVariableNull, EFI_BUFFER_TOO_SMALL );           // Status

+  PolicyCheck = ValidateSetVariable( TEST_VAR_1_NAME,

+                                    &mTestGuid1,

+                                    VARIABLE_ATTRIBUTE_BS_RT_AT,

+                                    sizeof(DummyData),

+                                    DummyData );

+  UT_ASSERT_TRUE( EFI_ERROR( PolicyCheck ) );

+

+  return UNIT_TEST_PASSED;

+}

+

+/**

+  Test Case

+*/

+UNIT_TEST_STATUS

+EFIAPI

+LockOnStatePoliciesShouldBeHonored (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  EXPANDED_VARIABLE_POLICY_ENTRY   ValidationPolicy = {

+    {

+      VARIABLE_POLICY_ENTRY_REVISION,

+      0,    // Will be populated by init helper.

+      0,    // Will be populated by init helper.

+      TEST_GUID_1,

+      TEST_POLICY_MIN_SIZE_NULL,

+      TEST_POLICY_MAX_SIZE_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE

+    },

+    {

+      TEST_GUID_2,

+      20,           // Value

+      0             // Padding

+    },

+    L"",

+    L""

+  };

+  EFI_STATUS  PolicyCheck;

+  UINT8       DummyData[12];

+  UINT8       ValidationStateVar;

+  UINTN       ExpectedDataSize;

+  UT_ASSERT_TRUE( InitExpVarPolicyStrings( &ValidationPolicy, TEST_VAR_1_NAME, TEST_VAR_2_NAME ) );

+

+

+  // Without a policy, there should be no constraints on variable creation.

+  PolicyCheck = ValidateSetVariable( TEST_VAR_1_NAME,

+                                    &mTestGuid1,

+                                    VARIABLE_ATTRIBUTE_BS_RT_AT,

+                                    sizeof(DummyData),

+                                    DummyData );

+  UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );

+

+  // Set a policy to test against.

+  UT_ASSERT_NOT_EFI_ERROR( RegisterVariablePolicy( &ValidationPolicy.Header ) );

+

+  // Set consistent expectations on what the calls are looking for.

+  expect_memory_count( StubGetVariableNull, VariableName, TEST_VAR_2_NAME, sizeof(TEST_VAR_2_NAME), 5 );

+  expect_memory_count( StubGetVariableNull, VendorGuid, &mTestGuid2, sizeof(mTestGuid2), 5 );

+  ExpectedDataSize = 1;

+  expect_memory_count( StubGetVariableNull, DataSize, &ExpectedDataSize, sizeof(ExpectedDataSize), 5 );

+

+  // With a policy, make sure that writes still work, since the variable doesn't exist.

+  will_return( StubGetVariableNull, TEST_POLICY_ATTRIBUTES_NULL );    // Attributes

+  will_return( StubGetVariableNull, 0 );                              // Size

+  will_return( StubGetVariableNull, NULL );                           // DataPtr

+  will_return( StubGetVariableNull, EFI_NOT_FOUND );                  // Status

+  PolicyCheck = ValidateSetVariable( TEST_VAR_1_NAME,

+                                    &mTestGuid1,

+                                    VARIABLE_ATTRIBUTE_BS_RT_AT,

+                                    sizeof(DummyData),

+                                    DummyData );

+  UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );

+

+  // With a policy, make sure that a state variable that's too large doesn't lock the variable.

+  will_return( StubGetVariableNull, TEST_POLICY_ATTRIBUTES_NULL );    // Attributes

+  will_return( StubGetVariableNull, 10 );                             // Size

+  will_return( StubGetVariableNull, NULL );                           // DataPtr

+  will_return( StubGetVariableNull, EFI_BUFFER_TOO_SMALL );           // Status

+  PolicyCheck = ValidateSetVariable( TEST_VAR_1_NAME,

+                                    &mTestGuid1,

+                                    VARIABLE_ATTRIBUTE_BS_RT_AT,

+                                    sizeof(DummyData),

+                                    DummyData );

+  UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );

+

+  // With a policy, check a state variable with the wrong value.

+  ValidationStateVar = 0;

+  will_return( StubGetVariableNull, TEST_POLICY_ATTRIBUTES_NULL );    // Attributes

+  will_return( StubGetVariableNull, sizeof(ValidationStateVar) );     // Size

+  will_return( StubGetVariableNull, &ValidationStateVar );            // DataPtr

+  will_return( StubGetVariableNull, EFI_SUCCESS );                    // Status

+  PolicyCheck = ValidateSetVariable( TEST_VAR_1_NAME,

+                                    &mTestGuid1,

+                                    VARIABLE_ATTRIBUTE_BS_RT_AT,

+                                    sizeof(DummyData),

+                                    DummyData );

+  UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );

+

+  // With a policy, check a state variable with another wrong value.

+  ValidationStateVar = 10;

+  will_return( StubGetVariableNull, TEST_POLICY_ATTRIBUTES_NULL );    // Attributes

+  will_return( StubGetVariableNull, sizeof(ValidationStateVar) );     // Size

+  will_return( StubGetVariableNull, &ValidationStateVar );            // DataPtr

+  will_return( StubGetVariableNull, EFI_SUCCESS );                    // Status

+  PolicyCheck = ValidateSetVariable( TEST_VAR_1_NAME,

+                                    &mTestGuid1,

+                                    VARIABLE_ATTRIBUTE_BS_RT_AT,

+                                    sizeof(DummyData),

+                                    DummyData );

+  UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );

+

+  // With a policy, make sure that a call with a correct state variable fails.

+  ValidationStateVar = 20;

+  will_return( StubGetVariableNull, TEST_POLICY_ATTRIBUTES_NULL );    // Attributes

+  will_return( StubGetVariableNull, sizeof(ValidationStateVar) );     // Size

+  will_return( StubGetVariableNull, &ValidationStateVar );            // DataPtr

+  will_return( StubGetVariableNull, EFI_SUCCESS );                    // Status

+  PolicyCheck = ValidateSetVariable( TEST_VAR_1_NAME,

+                                    &mTestGuid1,

+                                    VARIABLE_ATTRIBUTE_BS_RT_AT,

+                                    sizeof(DummyData),

+                                    DummyData );

+  UT_ASSERT_TRUE( EFI_ERROR( PolicyCheck ) );

+

+  return UNIT_TEST_PASSED;

+}

+

+/**

+  Test Case

+*/

+UNIT_TEST_STATUS

+EFIAPI

+LockOnStatePoliciesShouldApplyToNamespaces (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  EXPANDED_VARIABLE_POLICY_ENTRY   ValidationPolicy = {

+    {

+      VARIABLE_POLICY_ENTRY_REVISION,

+      0,    // Will be populated by init helper.

+      0,    // Will be populated by init helper.

+      TEST_GUID_1,

+      TEST_POLICY_MIN_SIZE_NULL,

+      TEST_POLICY_MAX_SIZE_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE

+    },

+    {

+      TEST_GUID_2,

+      20,           // Value

+      0             // Padding

+    },

+    L"",

+    L""

+  };

+  EFI_STATUS  PolicyCheck;

+  UINT8       DummyData[12];

+  UINT8       ValidationStateVar;

+  UINTN       ExpectedDataSize;

+  UT_ASSERT_TRUE( InitExpVarPolicyStrings( &ValidationPolicy, NULL, TEST_VAR_2_NAME ) );

+

+

+  // Without a policy, there should be no constraints on variable creation.

+  PolicyCheck = ValidateSetVariable( TEST_VAR_1_NAME,

+                                    &mTestGuid1,

+                                    VARIABLE_ATTRIBUTE_BS_RT_AT,

+                                    sizeof(DummyData),

+                                    DummyData );

+  UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );

+  PolicyCheck = ValidateSetVariable( TEST_VAR_3_NAME,

+                                    &mTestGuid1,

+                                    VARIABLE_ATTRIBUTE_BS_RT_AT,

+                                    sizeof(DummyData),

+                                    DummyData );

+  UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );

+

+  // Set a policy to test against.

+  UT_ASSERT_NOT_EFI_ERROR( RegisterVariablePolicy( &ValidationPolicy.Header ) );

+

+  // Set consistent expectations on what the calls are looking for.

+  expect_memory_count( StubGetVariableNull, VariableName, TEST_VAR_2_NAME, sizeof(TEST_VAR_2_NAME), 4 );

+  expect_memory_count( StubGetVariableNull, VendorGuid, &mTestGuid2, sizeof(mTestGuid2), 4 );

+  ExpectedDataSize = 1;

+  expect_memory_count( StubGetVariableNull, DataSize, &ExpectedDataSize, sizeof(ExpectedDataSize), 4 );

+

+  // With a policy, make sure that writes still work, since the variable doesn't exist.

+  will_return( StubGetVariableNull, TEST_POLICY_ATTRIBUTES_NULL );    // Attributes

+  will_return( StubGetVariableNull, 0 );                              // Size

+  will_return( StubGetVariableNull, NULL );                           // DataPtr

+  will_return( StubGetVariableNull, EFI_NOT_FOUND );                  // Status

+  PolicyCheck = ValidateSetVariable( TEST_VAR_1_NAME,

+                                    &mTestGuid1,

+                                    VARIABLE_ATTRIBUTE_BS_RT_AT,

+                                    sizeof(DummyData),

+                                    DummyData );

+  UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );

+  will_return( StubGetVariableNull, TEST_POLICY_ATTRIBUTES_NULL );    // Attributes

+  will_return( StubGetVariableNull, 0 );                              // Size

+  will_return( StubGetVariableNull, NULL );                           // DataPtr

+  will_return( StubGetVariableNull, EFI_NOT_FOUND );                  // Status

+  PolicyCheck = ValidateSetVariable( TEST_VAR_3_NAME,

+                                    &mTestGuid1,

+                                    VARIABLE_ATTRIBUTE_BS_RT_AT,

+                                    sizeof(DummyData),

+                                    DummyData );

+  UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );

+

+  // With a policy, make sure that a call with a correct state variable fails.

+  ValidationStateVar = 20;

+  will_return( StubGetVariableNull, TEST_POLICY_ATTRIBUTES_NULL );    // Attributes

+  will_return( StubGetVariableNull, sizeof(ValidationStateVar) );     // Size

+  will_return( StubGetVariableNull, &ValidationStateVar );            // DataPtr

+  will_return( StubGetVariableNull, EFI_SUCCESS );                    // Status

+  PolicyCheck = ValidateSetVariable( TEST_VAR_1_NAME,

+                                    &mTestGuid1,

+                                    VARIABLE_ATTRIBUTE_BS_RT_AT,

+                                    sizeof(DummyData),

+                                    DummyData );

+  UT_ASSERT_TRUE( EFI_ERROR( PolicyCheck ) );

+  will_return( StubGetVariableNull, TEST_POLICY_ATTRIBUTES_NULL );    // Attributes

+  will_return( StubGetVariableNull, sizeof(ValidationStateVar) );     // Size

+  will_return( StubGetVariableNull, &ValidationStateVar );            // DataPtr

+  will_return( StubGetVariableNull, EFI_SUCCESS );                    // Status

+  PolicyCheck = ValidateSetVariable( TEST_VAR_3_NAME,

+                                    &mTestGuid1,

+                                    VARIABLE_ATTRIBUTE_BS_RT_AT,

+                                    sizeof(DummyData),

+                                    DummyData );

+  UT_ASSERT_TRUE( EFI_ERROR( PolicyCheck ) );

+

+  return UNIT_TEST_PASSED;

+}

+

+/**

+  Test Case

+*/

+UNIT_TEST_STATUS

+EFIAPI

+LockOnStateShouldHandleErrorsGracefully (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  EXPANDED_VARIABLE_POLICY_ENTRY   ValidationPolicy = {

+    {

+      VARIABLE_POLICY_ENTRY_REVISION,

+      0,    // Will be populated by init helper.

+      0,    // Will be populated by init helper.

+      TEST_GUID_1,

+      TEST_POLICY_MIN_SIZE_NULL,

+      TEST_POLICY_MAX_SIZE_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE

+    },

+    {

+      TEST_GUID_2,

+      20,           // Value

+      0             // Padding

+    },

+    L"",

+    L""

+  };

+  EFI_STATUS  PolicyCheck;

+  UINT8       DummyData[12];

+  UT_ASSERT_TRUE( InitExpVarPolicyStrings( &ValidationPolicy, TEST_VAR_1_NAME, TEST_VAR_2_NAME ) );

+

+

+  // Without a policy, there should be no constraints on variable creation.

+  PolicyCheck = ValidateSetVariable( TEST_VAR_1_NAME,

+                                    &mTestGuid1,

+                                    VARIABLE_ATTRIBUTE_BS_RT_AT,

+                                    sizeof(DummyData),

+                                    DummyData );

+  UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );

+

+  // Set a policy to test against.

+  UT_ASSERT_NOT_EFI_ERROR( RegisterVariablePolicy( &ValidationPolicy.Header ) );

+

+  // Configure the stub to not care about parameters. We're testing errors.

+  expect_any_always( StubGetVariableNull, VariableName );

+  expect_any_always( StubGetVariableNull, VendorGuid );

+  expect_any_always( StubGetVariableNull, DataSize );

+

+  // With a policy, make sure that writes still work, since the variable doesn't exist.

+  will_return( StubGetVariableNull, TEST_POLICY_ATTRIBUTES_NULL );    // Attributes

+  will_return( StubGetVariableNull, 0 );                              // Size

+  will_return( StubGetVariableNull, NULL );                           // DataPtr

+  will_return( StubGetVariableNull, EFI_NOT_FOUND );                  // Status

+  PolicyCheck = ValidateSetVariable( TEST_VAR_1_NAME,

+                                    &mTestGuid1,

+                                    VARIABLE_ATTRIBUTE_BS_RT_AT,

+                                    sizeof(DummyData),

+                                    DummyData );

+  UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );

+

+  // Verify that state variables that are the wrong size won't lock the variable.

+  will_return( StubGetVariableNull, TEST_POLICY_ATTRIBUTES_NULL );    // Attributes

+  will_return( StubGetVariableNull, 0 );                              // Size

+  will_return( StubGetVariableNull, NULL );                           // DataPtr

+  will_return( StubGetVariableNull, EFI_BUFFER_TOO_SMALL );           // Status

+  PolicyCheck = ValidateSetVariable( TEST_VAR_1_NAME,

+                                    &mTestGuid1,

+                                    VARIABLE_ATTRIBUTE_BS_RT_AT,

+                                    sizeof(DummyData),

+                                    DummyData );

+  UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );

+

+  // Verify that unexpected errors default to locked.

+  will_return( StubGetVariableNull, TEST_POLICY_ATTRIBUTES_NULL );    // Attributes

+  will_return( StubGetVariableNull, 0 );                              // Size

+  will_return( StubGetVariableNull, NULL );                           // DataPtr

+  will_return( StubGetVariableNull, EFI_UNSUPPORTED );                // Status

+  PolicyCheck = ValidateSetVariable( TEST_VAR_1_NAME,

+                                    &mTestGuid1,

+                                    VARIABLE_ATTRIBUTE_BS_RT_AT,

+                                    sizeof(DummyData),

+                                    DummyData );

+  UT_ASSERT_TRUE( EFI_ERROR( PolicyCheck ) );

+

+  will_return( StubGetVariableNull, TEST_POLICY_ATTRIBUTES_NULL );    // Attributes

+  will_return( StubGetVariableNull, 0 );                              // Size

+  will_return( StubGetVariableNull, NULL );                           // DataPtr

+  will_return( StubGetVariableNull, EFI_NOT_READY );                  // Status

+  PolicyCheck = ValidateSetVariable( TEST_VAR_1_NAME,

+                                    &mTestGuid1,

+                                    VARIABLE_ATTRIBUTE_BS_RT_AT,

+                                    sizeof(DummyData),

+                                    DummyData );

+  UT_ASSERT_TRUE( EFI_ERROR( PolicyCheck ) );

+

+  return UNIT_TEST_PASSED;

+}

+

+/**

+  Test Case

+*/

+UNIT_TEST_STATUS

+EFIAPI

+BestMatchPriorityShouldBeObeyed (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  SIMPLE_VARIABLE_POLICY_ENTRY   ValidationPolicy = {

+    {

+      VARIABLE_POLICY_ENTRY_REVISION,

+      sizeof(VARIABLE_POLICY_ENTRY) + sizeof(L"Wild12Card34Placeholder"),

+      sizeof(VARIABLE_POLICY_ENTRY),

+      TEST_GUID_1,

+      TEST_POLICY_MIN_SIZE_NULL,

+      TEST_POLICY_MAX_SIZE_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      VARIABLE_POLICY_TYPE_NO_LOCK

+    },

+    L"Wild12Card34Placeholder"

+  };

+  EFI_STATUS  PolicyCheck;

+  UINT8       DummyData[70];

+  CHAR16      *PolicyName = (CHAR16*)((UINT8*)&ValidationPolicy + sizeof(VARIABLE_POLICY_ENTRY));

+  UINTN       PolicyNameSize = sizeof(L"Wild12Card34Placeholder");

+  CHAR16      *FourWildcards = L"Wild##Card##Placeholder";

+  CHAR16      *ThreeWildcards = L"Wild##Card#4Placeholder";

+  CHAR16      *TwoWildcards = L"Wild##Card34Placeholder";

+  CHAR16      *OneWildcard = L"Wild#2Card34Placeholder";

+  CHAR16      *NoWildcards = L"Wild12Card34Placeholder";

+

+  // Create all of the policies from least restrictive to most restrictive.

+  // NoWildcards should be the most restrictive.

+  ValidationPolicy.Header.MaxSize = 60;

+  ValidationPolicy.Header.Size = ValidationPolicy.Header.OffsetToName;

+  UT_ASSERT_NOT_EFI_ERROR( RegisterVariablePolicy( &ValidationPolicy.Header ) );

+  ValidationPolicy.Header.Size += (UINT16)PolicyNameSize;

+  ValidationPolicy.Header.MaxSize = 50;

+  CopyMem( PolicyName, FourWildcards, PolicyNameSize );

+  UT_ASSERT_NOT_EFI_ERROR( RegisterVariablePolicy( &ValidationPolicy.Header ) );

+  ValidationPolicy.Header.MaxSize = 40;

+  CopyMem( PolicyName, ThreeWildcards, PolicyNameSize );

+  UT_ASSERT_NOT_EFI_ERROR( RegisterVariablePolicy( &ValidationPolicy.Header ) );

+  ValidationPolicy.Header.MaxSize = 30;

+  CopyMem( PolicyName, TwoWildcards, PolicyNameSize );

+  UT_ASSERT_NOT_EFI_ERROR( RegisterVariablePolicy( &ValidationPolicy.Header ) );

+  ValidationPolicy.Header.MaxSize = 20;

+  CopyMem( PolicyName, OneWildcard, PolicyNameSize );

+  UT_ASSERT_NOT_EFI_ERROR( RegisterVariablePolicy( &ValidationPolicy.Header ) );

+  ValidationPolicy.Header.MaxSize = 10;

+  CopyMem( PolicyName, NoWildcards, PolicyNameSize );

+  UT_ASSERT_NOT_EFI_ERROR( RegisterVariablePolicy( &ValidationPolicy.Header ) );

+

+  // Verify that variables only matching the namespace have the most flexible policy.

+  PolicyCheck = ValidateSetVariable( L"ArbitraryName",

+                                     &mTestGuid1,

+                                     VARIABLE_ATTRIBUTE_BS_RT_AT,

+                                     65,

+                                     DummyData );

+  UT_ASSERT_TRUE( EFI_ERROR( PolicyCheck ) );

+  PolicyCheck = ValidateSetVariable( L"ArbitraryName",

+                                     &mTestGuid1,

+                                     VARIABLE_ATTRIBUTE_BS_RT_AT,

+                                     55,

+                                     DummyData );

+  UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );

+

+  // Verify that variables matching increasing characters get increasing policy restrictions.

+  PolicyCheck = ValidateSetVariable( L"Wild77Card77Placeholder",

+                                     &mTestGuid1,

+                                     VARIABLE_ATTRIBUTE_BS_RT_AT,

+                                     55,

+                                     DummyData );

+  UT_ASSERT_TRUE( EFI_ERROR( PolicyCheck ) );

+  PolicyCheck = ValidateSetVariable( L"Wild77Card77Placeholder",

+                                     &mTestGuid1,

+                                     VARIABLE_ATTRIBUTE_BS_RT_AT,

+                                     45,

+                                     DummyData );

+  UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );

+

+  PolicyCheck = ValidateSetVariable( L"Wild77Card74Placeholder",

+                                     &mTestGuid1,

+                                     VARIABLE_ATTRIBUTE_BS_RT_AT,

+                                     45,

+                                     DummyData );

+  UT_ASSERT_TRUE( EFI_ERROR( PolicyCheck ) );

+  PolicyCheck = ValidateSetVariable( L"Wild77Card74Placeholder",

+                                     &mTestGuid1,

+                                     VARIABLE_ATTRIBUTE_BS_RT_AT,

+                                     35,

+                                     DummyData );

+  UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );

+

+  PolicyCheck = ValidateSetVariable( L"Wild77Card34Placeholder",

+                                     &mTestGuid1,

+                                     VARIABLE_ATTRIBUTE_BS_RT_AT,

+                                     35,

+                                     DummyData );

+  UT_ASSERT_TRUE( EFI_ERROR( PolicyCheck ) );

+  PolicyCheck = ValidateSetVariable( L"Wild77Card34Placeholder",

+                                     &mTestGuid1,

+                                     VARIABLE_ATTRIBUTE_BS_RT_AT,

+                                     25,

+                                     DummyData );

+  UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );

+

+  PolicyCheck = ValidateSetVariable( L"Wild72Card34Placeholder",

+                                     &mTestGuid1,

+                                     VARIABLE_ATTRIBUTE_BS_RT_AT,

+                                     25,

+                                     DummyData );

+  UT_ASSERT_TRUE( EFI_ERROR( PolicyCheck ) );

+  PolicyCheck = ValidateSetVariable( L"Wild72Card34Placeholder",

+                                     &mTestGuid1,

+                                     VARIABLE_ATTRIBUTE_BS_RT_AT,

+                                     15,

+                                     DummyData );

+  UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );

+

+  PolicyCheck = ValidateSetVariable( L"Wild12Card34Placeholder",

+                                     &mTestGuid1,

+                                     VARIABLE_ATTRIBUTE_BS_RT_AT,

+                                     15,

+                                     DummyData );

+  UT_ASSERT_TRUE( EFI_ERROR( PolicyCheck ) );

+  PolicyCheck = ValidateSetVariable( L"Wild12Card34Placeholder",

+                                     &mTestGuid1,

+                                     VARIABLE_ATTRIBUTE_BS_RT_AT,

+                                     5,

+                                     DummyData );

+  UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );

+

+  return UNIT_TEST_PASSED;

+}

+

+

+///=== POLICY UTILITY SUITE ===================================================

+

+/**

+  Test Case

+*/

+UNIT_TEST_STATUS

+EFIAPI

+ShouldBeAbleToLockInterface (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  SIMPLE_VARIABLE_POLICY_ENTRY   TestPolicy = {

+    {

+      VARIABLE_POLICY_ENTRY_REVISION,

+      sizeof(VARIABLE_POLICY_ENTRY) + sizeof(TEST_VAR_1_NAME),

+      sizeof(VARIABLE_POLICY_ENTRY),

+      TEST_GUID_1,

+      TEST_POLICY_MIN_SIZE_NULL,

+      TEST_POLICY_MAX_SIZE_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      VARIABLE_POLICY_TYPE_NO_LOCK

+    },

+    TEST_VAR_1_NAME

+  };

+

+  // Make sure it's not already locked.

+  UT_ASSERT_FALSE( IsVariablePolicyInterfaceLocked() );

+  // Lock it.

+  UT_ASSERT_NOT_EFI_ERROR( LockVariablePolicy() );

+  // Verify that it's locked.

+  UT_ASSERT_TRUE( IsVariablePolicyInterfaceLocked() );

+

+  // Verify that all state-changing commands fail.

+  UT_ASSERT_TRUE( EFI_ERROR( LockVariablePolicy() ) );

+  UT_ASSERT_TRUE( EFI_ERROR( DisableVariablePolicy() ) );

+  UT_ASSERT_TRUE( EFI_ERROR( RegisterVariablePolicy( &TestPolicy.Header ) ) );

+

+  return UNIT_TEST_PASSED;

+}

+

+/**

+  Test Case

+*/

+UNIT_TEST_STATUS

+EFIAPI

+ShouldBeAbleToDisablePolicyEnforcement (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  SIMPLE_VARIABLE_POLICY_ENTRY   TestPolicy = {

+    {

+      VARIABLE_POLICY_ENTRY_REVISION,

+      sizeof(VARIABLE_POLICY_ENTRY) + sizeof(TEST_VAR_1_NAME),

+      sizeof(VARIABLE_POLICY_ENTRY),

+      TEST_GUID_1,

+      TEST_POLICY_MIN_SIZE_10,

+      TEST_POLICY_MAX_SIZE_200,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      VARIABLE_POLICY_TYPE_NO_LOCK

+    },

+    TEST_VAR_1_NAME

+  };

+  EFI_STATUS  PolicyCheck;

+  UINT8       DummyData[TEST_POLICY_MIN_SIZE_10-1];

+

+  // Make sure that the policy enforcement is currently enabled.

+  UT_ASSERT_TRUE( IsVariablePolicyEnabled() );

+  // Add a policy before it's disabled.

+  UT_ASSERT_NOT_EFI_ERROR( RegisterVariablePolicy( &TestPolicy.Header ) );

+  // Disable the policy enforcement.

+  UT_ASSERT_NOT_EFI_ERROR( DisableVariablePolicy() );

+  // Make sure that the policy enforcement is currently disabled.

+  UT_ASSERT_FALSE( IsVariablePolicyEnabled() );

+

+  // Check to make sure that a policy violation still passes.

+  PolicyCheck = ValidateSetVariable( TEST_VAR_1_NAME,

+                                    &mTestGuid1,

+                                    VARIABLE_ATTRIBUTE_NV_BS,

+                                    sizeof(DummyData),

+                                    DummyData );

+  UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );

+

+  return UNIT_TEST_PASSED;

+}

+

+/**

+  Test Case

+*/

+UNIT_TEST_STATUS

+EFIAPI

+ShouldNotBeAbleToDisablePoliciesTwice (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  // Make sure that the policy enforcement is currently enabled.

+  UT_ASSERT_TRUE( IsVariablePolicyEnabled() );

+  // Disable the policy enforcement.

+  UT_ASSERT_NOT_EFI_ERROR( DisableVariablePolicy() );

+  // Make sure that the policy enforcement is currently disabled.

+  UT_ASSERT_FALSE( IsVariablePolicyEnabled() );

+  // Try to disable again and verify failure.

+  UT_ASSERT_TRUE( EFI_ERROR( DisableVariablePolicy() ) );

+

+  return UNIT_TEST_PASSED;

+}

+

+/**

+  Test Case

+*/

+UNIT_TEST_STATUS

+EFIAPI

+ShouldBeAbleToAddNewPoliciesAfterDisabled (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  SIMPLE_VARIABLE_POLICY_ENTRY   TestPolicy = {

+    {

+      VARIABLE_POLICY_ENTRY_REVISION,

+      sizeof(VARIABLE_POLICY_ENTRY) + sizeof(TEST_VAR_1_NAME),

+      sizeof(VARIABLE_POLICY_ENTRY),

+      TEST_GUID_1,

+      TEST_POLICY_MIN_SIZE_10,

+      TEST_POLICY_MAX_SIZE_200,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      VARIABLE_POLICY_TYPE_NO_LOCK

+    },

+    TEST_VAR_1_NAME

+  };

+  EFI_STATUS  PolicyCheck;

+

+  // Make sure that the policy enforcement is currently enabled.

+  UT_ASSERT_TRUE( IsVariablePolicyEnabled() );

+  // Disable the policy enforcement.

+  UT_ASSERT_NOT_EFI_ERROR( DisableVariablePolicy() );

+

+  // Make sure that new policy creation still works, it just won't be enforced.

+  PolicyCheck = RegisterVariablePolicy( &TestPolicy.Header );

+  UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );

+

+  return UNIT_TEST_PASSED;

+}

+

+/**

+  Test Case

+*/

+UNIT_TEST_STATUS

+EFIAPI

+ShouldBeAbleToLockAfterDisabled (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  // Make sure that the policy enforcement is currently enabled.

+  UT_ASSERT_TRUE( IsVariablePolicyEnabled() );

+  // Disable the policy enforcement.

+  UT_ASSERT_NOT_EFI_ERROR( DisableVariablePolicy() );

+

+  // Make sure that we can lock in this state.

+  UT_ASSERT_FALSE( IsVariablePolicyInterfaceLocked() );

+  UT_ASSERT_NOT_EFI_ERROR( LockVariablePolicy() );

+  UT_ASSERT_TRUE( IsVariablePolicyInterfaceLocked() );

+

+  return UNIT_TEST_PASSED;

+}

+

+/**

+  Test Case

+*/

+UNIT_TEST_STATUS

+EFIAPI

+ShouldBeAbleToDumpThePolicyTable (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  SIMPLE_VARIABLE_POLICY_ENTRY   TestPolicy = {

+    {

+      VARIABLE_POLICY_ENTRY_REVISION,

+      sizeof(VARIABLE_POLICY_ENTRY) + sizeof(TEST_VAR_1_NAME),

+      sizeof(VARIABLE_POLICY_ENTRY),

+      TEST_GUID_1,

+      TEST_POLICY_MIN_SIZE_10,

+      TEST_POLICY_MAX_SIZE_200,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      VARIABLE_POLICY_TYPE_NO_LOCK

+    },

+    TEST_VAR_1_NAME

+  };

+  EFI_STATUS  PolicyCheck;

+  UINT32      DumpSize;

+  UINT32      BufferSize;

+  VOID        *DumpBuffer;

+

+  // For good measure, test some parameter validation.

+  UT_ASSERT_STATUS_EQUAL( DumpVariablePolicy( NULL, NULL ), EFI_INVALID_PARAMETER );

+  DumpSize = 10;

+  UT_ASSERT_STATUS_EQUAL( DumpVariablePolicy( NULL, &DumpSize ), EFI_INVALID_PARAMETER );

+

+  // Now for the actual test case.

+

+  // Allocate a buffer to hold the output.

+  BufferSize = sizeof(VARIABLE_POLICY_ENTRY) + sizeof(TEST_VAR_1_NAME);

+  DumpBuffer = AllocatePool( BufferSize );

+  UT_ASSERT_NOT_EQUAL( DumpBuffer, NULL );

+

+  // Verify that the current table size is 0.

+  DumpSize = BufferSize;

+  UT_ASSERT_NOT_EFI_ERROR( DumpVariablePolicy( DumpBuffer, &DumpSize ) );

+  UT_ASSERT_EQUAL( DumpSize, 0 );

+

+  // Now, set a new policy.

+  UT_ASSERT_NOT_EFI_ERROR( RegisterVariablePolicy( &TestPolicy.Header ) );

+

+  // Make sure that the new return is non-zero and fails as expected.

+  DumpSize = 0;

+  PolicyCheck = DumpVariablePolicy( NULL, &DumpSize );

+  UT_ASSERT_STATUS_EQUAL( PolicyCheck, EFI_BUFFER_TOO_SMALL );

+  UT_ASSERT_EQUAL( DumpSize, BufferSize );

+

+  // Now verify that we can fetch the dump.

+  DumpSize = BufferSize;

+  UT_ASSERT_NOT_EFI_ERROR( DumpVariablePolicy( DumpBuffer, &DumpSize ) );

+  UT_ASSERT_EQUAL( DumpSize, BufferSize );

+  UT_ASSERT_MEM_EQUAL( &TestPolicy, DumpBuffer, BufferSize );

+

+  // Always put away your toys.

+  FreePool( DumpBuffer );

+

+  return UNIT_TEST_PASSED;

+}

+

+/**

+  Test Case

+*/

+UNIT_TEST_STATUS

+EFIAPI

+ShouldBeAbleToDumpThePolicyTableAfterDisabled (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  SIMPLE_VARIABLE_POLICY_ENTRY   TestPolicy = {

+    {

+      VARIABLE_POLICY_ENTRY_REVISION,

+      sizeof(VARIABLE_POLICY_ENTRY) + sizeof(TEST_VAR_1_NAME),

+      sizeof(VARIABLE_POLICY_ENTRY),

+      TEST_GUID_1,

+      TEST_POLICY_MIN_SIZE_10,

+      TEST_POLICY_MAX_SIZE_200,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      VARIABLE_POLICY_TYPE_NO_LOCK

+    },

+    TEST_VAR_1_NAME

+  };

+  SIMPLE_VARIABLE_POLICY_ENTRY   TestPolicy2 = {

+    {

+      VARIABLE_POLICY_ENTRY_REVISION,

+      sizeof(VARIABLE_POLICY_ENTRY) + sizeof(TEST_VAR_2_NAME),

+      sizeof(VARIABLE_POLICY_ENTRY),

+      TEST_GUID_2,

+      TEST_POLICY_MIN_SIZE_10,

+      TEST_POLICY_MAX_SIZE_200,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      TEST_POLICY_ATTRIBUTES_NULL,

+      VARIABLE_POLICY_TYPE_NO_LOCK

+    },

+    TEST_VAR_2_NAME

+  };

+  EFI_STATUS  PolicyCheck;

+  UINT32      DumpSize;

+  VOID        *DumpBuffer;

+

+  DumpBuffer = NULL;

+  DumpSize = 0;

+

+  // Register a new policy.

+  UT_ASSERT_NOT_EFI_ERROR( RegisterVariablePolicy( &TestPolicy.Header ) );

+  // Make sure that we can dump the policy.

+  PolicyCheck = DumpVariablePolicy( DumpBuffer, &DumpSize );

+  UT_ASSERT_STATUS_EQUAL( PolicyCheck, EFI_BUFFER_TOO_SMALL );

+  DumpBuffer = AllocatePool( DumpSize );

+  UT_ASSERT_NOT_EFI_ERROR( DumpVariablePolicy( DumpBuffer, &DumpSize ) );

+  UT_ASSERT_MEM_EQUAL( DumpBuffer, &TestPolicy, DumpSize );

+

+  // Clean up from this step.

+  FreePool( DumpBuffer );

+  DumpBuffer = NULL;

+  DumpSize = 0;

+

+  // Now disable the engine.

+  DisableVariablePolicy();

+

+  // Now register a new policy and make sure that both can be dumped.

+  UT_ASSERT_NOT_EFI_ERROR( RegisterVariablePolicy( &TestPolicy2.Header ) );

+  // Make sure that we can dump the policy.

+  PolicyCheck = DumpVariablePolicy( DumpBuffer, &DumpSize );

+  UT_ASSERT_STATUS_EQUAL( PolicyCheck, EFI_BUFFER_TOO_SMALL );

+  DumpBuffer = AllocatePool( DumpSize );

+  UT_ASSERT_NOT_EFI_ERROR( DumpVariablePolicy( DumpBuffer, &DumpSize ) );

+

+  // Finally, make sure that both policies are in the dump.

+  UT_ASSERT_MEM_EQUAL( DumpBuffer, &TestPolicy, TestPolicy.Header.Size );

+  UT_ASSERT_MEM_EQUAL( (UINT8*)DumpBuffer + TestPolicy.Header.Size,

+                        &TestPolicy2,

+                        TestPolicy2.Header.Size );

+

+  // Always put away your toys.

+  FreePool( DumpBuffer );

+

+  return UNIT_TEST_PASSED;

+}

+

+

+///=== TEST ENGINE ================================================================================

+

+/**

+  SampleUnitTestApp

+

+  @param[in] ImageHandle  The firmware allocated handle for the EFI image.

+  @param[in] SystemTable  A pointer to the EFI System Table.

+

+  @retval EFI_SUCCESS     The entry point executed successfully.

+  @retval other           Some error occured when executing this entry point.

+

+**/

+int

+main (

+  )

+{

+  EFI_STATUS                  Status;

+  UNIT_TEST_FRAMEWORK_HANDLE  Framework = NULL;

+  UNIT_TEST_SUITE_HANDLE      ArchTests;

+  UNIT_TEST_SUITE_HANDLE      PolicyTests;

+  UNIT_TEST_SUITE_HANDLE      UtilityTests;

+#ifdef INTERNAL_UNIT_TEST

+  UNIT_TEST_SUITE_HANDLE      InternalTests;

+#endif // INTERNAL_UNIT_TEST

+

+  DEBUG(( DEBUG_INFO, "%a v%a\n", UNIT_TEST_NAME, UNIT_TEST_VERSION ));

+

+  //

+  // Start setting up the test framework for running the tests.

+  //

+  Status = InitUnitTestFramework( &Framework, UNIT_TEST_NAME, gEfiCallerBaseName, UNIT_TEST_VERSION );

+  if (EFI_ERROR( Status ))

+  {

+    DEBUG((DEBUG_ERROR, "Failed in InitUnitTestFramework. Status = %r\n", Status));

+    goto EXIT;

+  }

+

+

+  //

+  // Add all test suites and tests.

+  //

+  Status = CreateUnitTestSuite( &ArchTests, Framework, "Variable Policy Architectural Tests", "VarPolicy.Arch", NULL, NULL );

+  if (EFI_ERROR( Status ))

+  {

+    DEBUG((DEBUG_ERROR, "Failed in CreateUnitTestSuite for ArchTests\n"));

+    Status = EFI_OUT_OF_RESOURCES;

+    goto EXIT;

+  }

+  AddTestCase( ArchTests,

+                "Deinitialization should fail if not previously initialized", "VarPolicy.Arch.OnlyDeinit",

+                ShouldFailDeinitWithoutInit, NULL, NULL, NULL );

+  AddTestCase( ArchTests,

+                "Initialization followed by deinitialization should succeed", "VarPolicy.Arch.InitDeinit",

+                ShouldBeAbleToInitAndDeinitTheLibrary, NULL, NULL, NULL );

+  AddTestCase( ArchTests,

+                "The initialization function fail if called twice without a deinit", "VarPolicy.Arch.InitTwice",

+                ShouldNotBeAbleToInitializeTheLibraryTwice, NULL, LibCleanup, NULL );

+  AddTestCase( ArchTests,

+                "API functions should be unavailable until library is initialized", "VarPolicy.Arch.UninitApiOff",

+                ApiCommandsShouldNotRespondIfLibIsUninitialized, NULL, LibCleanup, NULL );

+

+#ifdef INTERNAL_UNIT_TEST

+  Status = CreateUnitTestSuite( &InternalTests, Framework, "Variable Policy Internal Tests", "VarPolicy.Internal", NULL, NULL );

+  if (EFI_ERROR( Status ))

+  {

+    DEBUG((DEBUG_ERROR, "Failed in CreateUnitTestSuite for InternalTests\n"));

+    Status = EFI_OUT_OF_RESOURCES;

+    goto EXIT;

+  }

+  AddTestCase( InternalTests,

+                "Policy matching should use name and GUID", "VarPolicy.Internal.NameGuid",

+                PoliciesShouldMatchByNameAndGuid, LibInitMocked, LibCleanup, NULL );

+  AddTestCase( InternalTests,

+                "# sign wildcards should match digits", "VarPolicy.Internal.WildDigits",

+                WildcardPoliciesShouldMatchDigits, LibInitMocked, LibCleanup, NULL );

+  AddTestCase( InternalTests,

+                "Digit wildcards should check edge cases", "VarPolicy.Internal.WildDigitsAdvanced",

+                WildcardPoliciesShouldMatchDigitsAdvanced, LibInitMocked, LibCleanup, NULL );

+  AddTestCase( InternalTests,

+                "Empty names should match an entire namespace", "VarPolicy.Internal.WildNamespace",

+                WildcardPoliciesShouldMatchNamespaces, LibInitMocked, LibCleanup, NULL );

+  AddTestCase( InternalTests,

+                "Match priority should weight correctly based on wildcards", "VarPolicy.Internal.Priorities",

+                MatchPrioritiesShouldFollowRules, LibInitMocked, LibCleanup, NULL );

+#endif // INTERNAL_UNIT_TEST

+

+  Status = CreateUnitTestSuite( &PolicyTests, Framework, "Variable Policy Manipulation Tests", "VarPolicy.Policy", NULL, NULL );

+  if (EFI_ERROR( Status ))

+  {

+    DEBUG((DEBUG_ERROR, "Failed in CreateUnitTestSuite for PolicyTests\n"));

+    Status = EFI_OUT_OF_RESOURCES;

+    goto EXIT;

+  }

+  AddTestCase( PolicyTests,

+                "RegisterShouldAllowNamespaceWildcards", "VarPolicy.Policy.AllowNamespace",

+                RegisterShouldAllowNamespaceWildcards, LibInitMocked, LibCleanup, NULL );

+  AddTestCase( PolicyTests,

+                "RegisterShouldAllowStateVarsForNamespaces", "VarPolicy.Policy.AllowStateNamespace",

+                RegisterShouldAllowStateVarsForNamespaces, LibInitMocked, LibCleanup, NULL );

+  AddTestCase( PolicyTests,

+                "RegisterShouldRejectNullPointers", "VarPolicy.Policy.NullPointers",

+                RegisterShouldRejectNullPointers, LibInitMocked, LibCleanup, NULL );

+  AddTestCase( PolicyTests,

+                "RegisterShouldRejectBadRevisions", "VarPolicy.Policy.BadRevisions",

+                RegisterShouldRejectBadRevisions, LibInitMocked, LibCleanup, NULL );

+  AddTestCase( PolicyTests,

+                "RegisterShouldRejectBadSizes", "VarPolicy.Policy.BadSizes",

+                RegisterShouldRejectBadSizes, LibInitMocked, LibCleanup, NULL );

+  AddTestCase( PolicyTests,

+                "RegisterShouldRejectBadOffsets", "VarPolicy.Policy.BadOffsets",

+                RegisterShouldRejectBadOffsets, LibInitMocked, LibCleanup, NULL );

+  AddTestCase( PolicyTests,

+                "RegisterShouldRejectMissingStateStrings", "VarPolicy.Policy.MissingStateString",

+                RegisterShouldRejectMissingStateStrings, LibInitMocked, LibCleanup, NULL );

+  AddTestCase( PolicyTests,

+                "RegisterShouldRejectStringsMissingNull", "VarPolicy.Policy.MissingNull",

+                RegisterShouldRejectStringsMissingNull, LibInitMocked, LibCleanup, NULL );

+  AddTestCase( PolicyTests,

+                "RegisterShouldRejectMalformedStrings", "VarPolicy.Policy.MalformedStrings",

+                RegisterShouldRejectMalformedStrings, LibInitMocked, LibCleanup, NULL );

+  AddTestCase( PolicyTests,

+                "RegisterShouldRejectUnpackedPolicies", "VarPolicy.Policy.PolicyPacking",

+                RegisterShouldRejectUnpackedPolicies, LibInitMocked, LibCleanup, NULL );

+  AddTestCase( PolicyTests,

+                "RegisterShouldRejectInvalidNameCharacters", "VarPolicy.Policy.InvalidCharacters",

+                RegisterShouldRejectInvalidNameCharacters, LibInitMocked, LibCleanup, NULL );

+  AddTestCase( PolicyTests,

+                "RegisterShouldRejectBadPolicyConstraints", "VarPolicy.Policy.BadConstraints",

+                RegisterShouldRejectBadPolicyConstraints, LibInitMocked, LibCleanup, NULL );

+  AddTestCase( PolicyTests,

+                "RegisterShouldRejectUnknownLockPolicies", "VarPolicy.Policy.BadLocks",

+                RegisterShouldRejectUnknownLockPolicies, LibInitMocked, LibCleanup, NULL );

+  AddTestCase( PolicyTests,

+                "RegisterShouldRejectPolicesWithTooManyWildcards", "VarPolicy.Policy.TooManyWildcards",

+                RegisterShouldRejectPolicesWithTooManyWildcards, LibInitMocked, LibCleanup, NULL );

+  AddTestCase( PolicyTests,

+                "RegisterShouldRejectDuplicatePolicies", "VarPolicy.Policy.DuplicatePolicies",

+                RegisterShouldRejectDuplicatePolicies, LibInitMocked, LibCleanup, NULL );

+  AddTestCase( PolicyTests,

+                "Variables that exceed min or max sizes should be rejected", "VarPolicy.Policy.MinMax",

+                MinAndMaxSizePoliciesShouldBeHonored, LibInitMocked, LibCleanup, NULL );

+  AddTestCase( PolicyTests,

+                "AttributeMustPoliciesShouldBeHonored", "VarPolicy.Policy.AttrMust",

+                AttributeMustPoliciesShouldBeHonored, LibInitMocked, LibCleanup, NULL );

+  AddTestCase( PolicyTests,

+                "AttributeCantPoliciesShouldBeHonored", "VarPolicy.Policy.AttrCant",

+                AttributeCantPoliciesShouldBeHonored, LibInitMocked, LibCleanup, NULL );

+  AddTestCase( PolicyTests,

+                "VariablesShouldBeDeletableRegardlessOfSize", "VarPolicy.Policy.DeleteIgnoreSize",

+                VariablesShouldBeDeletableRegardlessOfSize, LibInitMocked, LibCleanup, NULL );

+  AddTestCase( PolicyTests,

+                "LockNowPoliciesShouldBeHonored", "VarPolicy.Policy.VARIABLE_POLICY_TYPE_LOCK_NOW",

+                LockNowPoliciesShouldBeHonored, LibInitMocked, LibCleanup, NULL );

+  AddTestCase( PolicyTests,

+                "LockOnCreatePoliciesShouldBeHonored", "VarPolicy.Policy.VARIABLE_POLICY_TYPE_LOCK_ON_CREATE",

+                LockOnCreatePoliciesShouldBeHonored, LibInitMocked, LibCleanup, NULL );

+  AddTestCase( PolicyTests,

+                "LockOnStatePoliciesShouldBeHonored", "VarPolicy.Policy.LockState",

+                LockOnStatePoliciesShouldBeHonored, LibInitMocked, LibCleanup, NULL );

+  AddTestCase( PolicyTests,

+                "LockOnStatePoliciesShouldApplyToNamespaces", "VarPolicy.Policy.NamespaceLockState",

+                LockOnStatePoliciesShouldApplyToNamespaces, LibInitMocked, LibCleanup, NULL );

+  AddTestCase( PolicyTests,

+                "LockOnStateShouldHandleErrorsGracefully", "VarPolicy.Policy.LockStateErrors",

+                LockOnStateShouldHandleErrorsGracefully, LibInitMocked, LibCleanup, NULL );

+  AddTestCase( PolicyTests,

+                "BestMatchPriorityShouldBeObeyed", "VarPolicy.Policy.BestMatch",

+                BestMatchPriorityShouldBeObeyed, LibInitMocked, LibCleanup, NULL );

+

+  Status = CreateUnitTestSuite( &UtilityTests, Framework, "Variable Policy Utility Tests", "VarPolicy.Utility", NULL, NULL );

+  if (EFI_ERROR( Status ))

+  {

+    DEBUG((DEBUG_ERROR, "Failed in CreateUnitTestSuite for UtilityTests\n"));

+    Status = EFI_OUT_OF_RESOURCES;

+    goto EXIT;

+  }

+  AddTestCase( UtilityTests,

+                "API commands that change state should not respond after interface is locked", "VarPolicy.Utility.InterfaceLock",

+                ShouldBeAbleToLockInterface, LibInitMocked, LibCleanup, NULL );

+  AddTestCase( UtilityTests,

+                "All policies should pass once enforcement is disabled", "VarPolicy.Utility.DisableEnforcement",

+                ShouldBeAbleToDisablePolicyEnforcement, LibInitMocked, LibCleanup, NULL );

+  AddTestCase( UtilityTests,

+                "Disabling enforcement twice should produce an error", "VarPolicy.Utility.DisableEnforcementTwice",

+                ShouldNotBeAbleToDisablePoliciesTwice, LibInitMocked, LibCleanup, NULL );

+  AddTestCase( UtilityTests,

+                "ShouldBeAbleToAddNewPoliciesAfterDisabled", "VarPolicy.Utility.AddAfterDisable",

+                ShouldBeAbleToAddNewPoliciesAfterDisabled, LibInitMocked, LibCleanup, NULL );

+  AddTestCase( UtilityTests,

+                "ShouldBeAbleToLockAfterDisabled", "VarPolicy.Utility.LockAfterDisable",

+                ShouldBeAbleToLockAfterDisabled, LibInitMocked, LibCleanup, NULL );

+  AddTestCase( UtilityTests,

+                "Should be able to dump the policy table", "VarPolicy.Utility.DumpTable",

+                ShouldBeAbleToDumpThePolicyTable, LibInitMocked, LibCleanup, NULL );

+  AddTestCase( UtilityTests,

+                "ShouldBeAbleToDumpThePolicyTableAfterDisabled", "VarPolicy.Utility.DumpTableAfterDisable",

+                ShouldBeAbleToDumpThePolicyTableAfterDisabled, LibInitMocked, LibCleanup, NULL );

+

+

+  //

+  // Execute the tests.

+  //

+  Status = RunAllTestSuites( Framework );

+

+EXIT:

+  if (Framework != NULL)

+  {

+    FreeUnitTestFramework( Framework );

+  }

+

+  return Status;

+}

diff --git a/MdeModulePkg/Include/Library/VariablePolicyLib.h b/MdeModulePkg/Include/Library/VariablePolicyLib.h
new file mode 100644
index 000000000000..efd1840112ec
--- /dev/null
+++ b/MdeModulePkg/Include/Library/VariablePolicyLib.h
@@ -0,0 +1,207 @@
+/** @file -- VariablePolicyLib.h

+Business logic for Variable Policy enforcement.

+

+Copyright (c) Microsoft Corporation.

+SPDX-License-Identifier: BSD-2-Clause-Patent

+

+**/

+

+#ifndef _VARIABLE_POLICY_LIB_H_

+#define _VARIABLE_POLICY_LIB_H_

+

+#include <Protocol/VariablePolicy.h>

+

+/**

+  This API function validates and registers a new policy with

+  the policy enforcement engine.

+

+  @param[in]  NewPolicy     Pointer to the incoming policy structure.

+

+  @retval     EFI_SUCCESS

+  @retval     EFI_INVALID_PARAMETER   NewPolicy is NULL or is internally inconsistent.

+  @retval     EFI_ALREADY_STARTED     An identical matching policy already exists.

+  @retval     EFI_WRITE_PROTECTED     The interface has been locked until the next reboot.

+  @retval     EFI_UNSUPPORTED         Policy enforcement has been disabled. No reason to add more policies.

+  @retval     EFI_ABORTED             A calculation error has prevented this function from completing.

+  @retval     EFI_OUT_OF_RESOURCES    Cannot grow the table to hold any more policies.

+  @retval     EFI_NOT_READY           Library has not yet been initialized.

+

+**/

+EFI_STATUS

+EFIAPI

+RegisterVariablePolicy (

+  IN CONST VARIABLE_POLICY_ENTRY    *NewPolicy

+  );

+

+

+/**

+  This API function checks to see whether the parameters to SetVariable would

+  be allowed according to the current variable policies.

+

+  @param[in]  VariableName       Same as EFI_SET_VARIABLE.

+  @param[in]  VendorGuid         Same as EFI_SET_VARIABLE.

+  @param[in]  Attributes         Same as EFI_SET_VARIABLE.

+  @param[in]  DataSize           Same as EFI_SET_VARIABLE.

+  @param[in]  Data               Same as EFI_SET_VARIABLE.

+

+  @retval     EFI_SUCCESS             A matching policy allows this update.

+  @retval     EFI_SUCCESS             There are currently no policies that restrict this update.

+  @retval     EFI_SUCCESS             The protections have been disable until the next reboot.

+  @retval     EFI_WRITE_PROTECTED     Variable is currently locked.

+  @retval     EFI_INVALID_PARAMETER   Attributes or size are invalid.

+  @retval     EFI_ABORTED             A lock policy exists, but an error prevented evaluation.

+  @retval     EFI_NOT_READY           Library has not been initialized.

+

+**/

+EFI_STATUS

+EFIAPI

+ValidateSetVariable (

+  IN  CHAR16                       *VariableName,

+  IN  EFI_GUID                     *VendorGuid,

+  IN  UINT32                       Attributes,

+  IN  UINTN                        DataSize,

+  IN  VOID                         *Data

+  );

+

+

+/**

+  This API function disables the variable policy enforcement. If it's

+  already been called once, will return EFI_ALREADY_STARTED.

+

+  @retval     EFI_SUCCESS

+  @retval     EFI_ALREADY_STARTED   Has already been called once this boot.

+  @retval     EFI_WRITE_PROTECTED   Interface has been locked until reboot.

+  @retval     EFI_WRITE_PROTECTED   Interface option is disabled by platform PCD.

+  @retval     EFI_NOT_READY   Library has not yet been initialized.

+

+**/

+EFI_STATUS

+EFIAPI

+DisableVariablePolicy (

+  VOID

+  );

+

+

+/**

+  This API function will dump the entire contents of the variable policy table.

+

+  Similar to GetVariable, the first call can be made with a 0 size and it will return

+  the size of the buffer required to hold the entire table.

+

+  @param[out]     Policy  Pointer to the policy buffer. Can be NULL if Size is 0.

+  @param[in,out]  Size    On input, the size of the output buffer. On output, the size

+                          of the data returned.

+

+  @retval     EFI_SUCCESS             Policy data is in the output buffer and Size has been updated.

+  @retval     EFI_INVALID_PARAMETER   Size is NULL, or Size is non-zero and Policy is NULL.

+  @retval     EFI_BUFFER_TOO_SMALL    Size is insufficient to hold policy. Size updated with required size.

+  @retval     EFI_NOT_READY           Library has not yet been initialized.

+

+**/

+EFI_STATUS

+EFIAPI

+DumpVariablePolicy (

+  OUT     UINT8         *Policy,

+  IN OUT  UINT32        *Size

+  );

+

+

+/**

+  This API function returns whether or not the policy engine is

+  currently being enforced.

+

+  @retval     TRUE

+  @retval     FALSE

+  @retval     FALSE         Library has not yet been initialized.

+

+**/

+BOOLEAN

+EFIAPI

+IsVariablePolicyEnabled (

+  VOID

+  );

+

+

+/**

+  This API function locks the interface so that no more policy updates

+  can be performed or changes made to the enforcement until the next boot.

+

+  @retval     EFI_SUCCESS

+  @retval     EFI_NOT_READY   Library has not yet been initialized.

+

+**/

+EFI_STATUS

+EFIAPI

+LockVariablePolicy (

+  VOID

+  );

+

+

+/**

+  This API function returns whether or not the policy interface is locked

+  for the remainder of the boot.

+

+  @retval     TRUE

+  @retval     FALSE

+  @retval     FALSE         Library has not yet been initialized.

+

+**/

+BOOLEAN

+EFIAPI

+IsVariablePolicyInterfaceLocked (

+  VOID

+  );

+

+

+/**

+  This helper function initializes the library and sets

+  up any required internal structures or handlers.

+

+  Also registers the internal pointer for the GetVariable helper.

+

+  @param[in]  GetVariableHelper A function pointer matching the EFI_GET_VARIABLE prototype that will be used to

+                  check policy criteria that involve the existence of other variables.

+

+  @retval     EFI_SUCCESS

+  @retval     EFI_ALREADY_STARTED   The initialize function has been called more than once without a call to

+                                    deinitialize.

+

+**/

+EFI_STATUS

+EFIAPI

+InitVariablePolicyLib (

+  IN  EFI_GET_VARIABLE    GetVariableHelper

+  );

+

+

+/**

+  This helper function returns whether or not the library is currently initialized.

+

+  @retval     TRUE

+  @retval     FALSE

+

+**/

+BOOLEAN

+EFIAPI

+IsVariablePolicyLibInitialized (

+  VOID

+  );

+

+

+/**

+  This helper function tears down  the library.

+

+  Should generally only be used for test harnesses.

+

+  @retval     EFI_SUCCESS

+  @retval     EFI_NOT_READY     Deinitialize was called without first calling initialize.

+

+**/

+EFI_STATUS

+EFIAPI

+DeinitVariablePolicyLib (

+  VOID

+  );

+

+

+#endif // _VARIABLE_POLICY_LIB_H_

diff --git a/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.inf b/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.inf
new file mode 100644
index 000000000000..f4a879d5382f
--- /dev/null
+++ b/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.inf
@@ -0,0 +1,44 @@
+## @file VariablePolicyLib.inf

+# Business logic for Variable Policy enforcement.

+#

+##

+# Copyright (c) Microsoft Corporation.

+# SPDX-License-Identifier: BSD-2-Clause-Patent

+##

+

+

+[Defines]

+  INF_VERSION         = 0x00010017

+  BASE_NAME           = VariablePolicyLib

+  FILE_GUID           = E9ECD342-159A-4F24-9FDF-65724027C594

+  VERSION_STRING      = 1.0

+  MODULE_TYPE         = DXE_DRIVER

+  LIBRARY_CLASS       = VariablePolicyLib|DXE_DRIVER DXE_SMM_DRIVER MM_STANDALONE

+

+#

+# The following information is for reference only and not required by the build tools.

+#

+#  VALID_ARCHITECTURES           = ANY

+#

+

+

+[Sources]

+  VariablePolicyLib.c

+  VariablePolicyExtraInitNull.c

+

+

+[Packages]

+  MdePkg/MdePkg.dec

+  MdeModulePkg/MdeModulePkg.dec

+

+

+[LibraryClasses]

+  DebugLib

+  BaseMemoryLib

+  MemoryAllocationLib

+  SafeIntLib

+  PcdLib

+

+

+[Pcd]

+  gEfiMdeModulePkgTokenSpaceGuid.PcdAllowVariablePolicyEnforcementDisable     ## CONSUMES

diff --git a/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.uni b/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.uni
new file mode 100644
index 000000000000..2227ec427828
--- /dev/null
+++ b/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.uni
@@ -0,0 +1,12 @@
+// /** @file

+// VariablePolicyLib.uni

+//

+// Copyright (c) Microsoft Corporation.

+// SPDX-License-Identifier: BSD-2-Clause-Patent

+//

+// **/

+

+

+#string STR_MODULE_ABSTRACT             #language en-US "Library containing the business logic for the VariablePolicy engine"

+

+#string STR_MODULE_DESCRIPTION          #language en-US "Library containing the business logic for the VariablePolicy engine"

diff --git a/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLibRuntimeDxe.inf b/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLibRuntimeDxe.inf
new file mode 100644
index 000000000000..8b8365741864
--- /dev/null
+++ b/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLibRuntimeDxe.inf
@@ -0,0 +1,51 @@
+## @file VariablePolicyLibRuntimeDxe.inf

+# Business logic for Variable Policy enforcement.

+# This instance is specifically for RuntimeDxe and contains

+# extra routines to register for VirtualAddressChangeEvents.

+#

+# Copyright (c) Microsoft Corporation.

+# SPDX-License-Identifier: BSD-2-Clause-Patent

+##

+

+

+[Defines]

+  INF_VERSION         = 0x00010017

+  BASE_NAME           = VariablePolicyLibRuntimeDxe

+  FILE_GUID           = 205F7F0E-8EAC-4914-8390-1B90DD7E2A27

+  VERSION_STRING      = 1.0

+  MODULE_TYPE         = DXE_RUNTIME_DRIVER

+  LIBRARY_CLASS       = VariablePolicyLib|DXE_RUNTIME_DRIVER

+

+#

+# The following information is for reference only and not required by the build tools.

+#

+#  VALID_ARCHITECTURES           = ANY

+#

+

+

+[Sources]

+  VariablePolicyLib.c

+  VariablePolicyExtraInitRuntimeDxe.c

+

+

+[Packages]

+  MdePkg/MdePkg.dec

+  MdeModulePkg/MdeModulePkg.dec

+

+

+[LibraryClasses]

+  DebugLib

+  BaseMemoryLib

+  MemoryAllocationLib

+  SafeIntLib

+  UefiBootServicesTableLib

+  UefiRuntimeServicesTableLib

+  PcdLib

+

+

+[Pcd]

+  gEfiMdeModulePkgTokenSpaceGuid.PcdAllowVariablePolicyEnforcementDisable     ## CONSUMES

+

+

+[Guids]

+  gEfiEventVirtualAddressChangeGuid

diff --git a/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyUnitTest/VariablePolicyUnitTest.inf b/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyUnitTest/VariablePolicyUnitTest.inf
new file mode 100644
index 000000000000..ccc04bb600d6
--- /dev/null
+++ b/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyUnitTest/VariablePolicyUnitTest.inf
@@ -0,0 +1,40 @@
+## @file VariablePolicyUnitTest.inf

+# UnitTest for...

+# Business logic for Variable Policy enforcement.

+#

+# Copyright (c) Microsoft Corporation.

+# SPDX-License-Identifier: BSD-2-Clause-Patent

+##

+

+

+[Defines]

+  INF_VERSION                    = 0x00010006

+  BASE_NAME                      = VariablePolicyUnitTest

+  FILE_GUID                      = 1200A2E4-D756-418C-9768-528C2D181A98

+  MODULE_TYPE                    = HOST_APPLICATION

+  VERSION_STRING                 = 1.0

+

+#

+# The following information is for reference only and not required by the build tools.

+#

+#  VALID_ARCHITECTURES           = IA32 X64 ARM AARCH64

+#

+

+[Sources]

+  VariablePolicyUnitTest.c

+

+

+[Packages]

+  MdePkg/MdePkg.dec

+  MdeModulePkg/MdeModulePkg.dec

+  UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec

+

+

+[LibraryClasses]

+  BaseLib

+  DebugLib

+  UnitTestLib

+  PrintLib

+  VariablePolicyLib

+  BaseMemoryLib

+  MemoryAllocationLib

diff --git a/MdeModulePkg/MdeModulePkg.dec b/MdeModulePkg/MdeModulePkg.dec
index 2e0461b87c32..31339741b840 100644
--- a/MdeModulePkg/MdeModulePkg.dec
+++ b/MdeModulePkg/MdeModulePkg.dec
@@ -31,6 +31,9 @@ [LibraryClasses]
   ##  @libraryclass  Defines a set of methods to reset whole system.

   ResetSystemLib|Include/Library/ResetSystemLib.h

 

+  ##  @libraryclass  Business logic for storing and testing variable policies

+  VariablePolicyLib|Include/Library/VariablePolicyLib.h

+

   ##  @libraryclass  Defines a set of helper functions for resetting the system.

   ResetUtilityLib|Include/Library/ResetUtilityLib.h

 

diff --git a/MdeModulePkg/MdeModulePkg.dsc b/MdeModulePkg/MdeModulePkg.dsc
index 25aea3e2a481..14b6ed536962 100644
--- a/MdeModulePkg/MdeModulePkg.dsc
+++ b/MdeModulePkg/MdeModulePkg.dsc
@@ -3,6 +3,7 @@
 #

 # (C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR>

 # Copyright (c) 2007 - 2019, Intel Corporation. All rights reserved.<BR>

+# Copyright (c) Microsoft Corporation.

 #

 #    SPDX-License-Identifier: BSD-2-Clause-Patent

 #

@@ -58,6 +59,7 @@ [LibraryClasses]
   DxeServicesLib|MdePkg/Library/DxeServicesLib/DxeServicesLib.inf

   DxeServicesTableLib|MdePkg/Library/DxeServicesTableLib/DxeServicesTableLib.inf

   UefiBootManagerLib|MdeModulePkg/Library/UefiBootManagerLib/UefiBootManagerLib.inf

+  VariablePolicyLib|MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.inf

   #

   # Generic Modules

   #

@@ -129,6 +131,7 @@ [LibraryClasses.common.DXE_RUNTIME_DRIVER]
   DebugLib|MdePkg/Library/UefiDebugLibConOut/UefiDebugLibConOut.inf

   LockBoxLib|MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxDxeLib.inf

   CapsuleLib|MdeModulePkg/Library/DxeCapsuleLibFmp/DxeRuntimeCapsuleLib.inf

+  VariablePolicyLib|MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLibRuntimeDxe.inf

 

 [LibraryClasses.common.SMM_CORE]

   HobLib|MdePkg/Library/DxeHobLib/DxeHobLib.inf

@@ -306,6 +309,8 @@ [Components]
   MdeModulePkg/Library/BootLogoLib/BootLogoLib.inf

   MdeModulePkg/Library/TpmMeasurementLibNull/TpmMeasurementLibNull.inf

   MdeModulePkg/Library/AuthVariableLibNull/AuthVariableLibNull.inf

+  MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.inf

+  MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLibRuntimeDxe.inf

   MdeModulePkg/Library/VarCheckLib/VarCheckLib.inf

   MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLib.inf

   MdeModulePkg/Library/VarCheckPcdLib/VarCheckPcdLib.inf

diff --git a/MdeModulePkg/Test/MdeModulePkgHostTest.dsc b/MdeModulePkg/Test/MdeModulePkgHostTest.dsc
index 72a119db4568..095e613f1be1 100644
--- a/MdeModulePkg/Test/MdeModulePkgHostTest.dsc
+++ b/MdeModulePkg/Test/MdeModulePkgHostTest.dsc
@@ -19,12 +19,23 @@ [Defines]
 

 !include UnitTestFrameworkPkg/UnitTestFrameworkPkgHost.dsc.inc

 

+[LibraryClasses]

+  SafeIntLib|MdePkg/Library/BaseSafeIntLib/BaseSafeIntLib.inf

+

 [Components]

   MdeModulePkg/Library/DxeResetSystemLib/UnitTest/MockUefiRuntimeServicesTableLib.inf

 

   #

   # Build MdeModulePkg HOST_APPLICATION Tests

   #

+  MdeModulePkg/Library/VariablePolicyLib/VariablePolicyUnitTest/VariablePolicyUnitTest.inf {

+    <LibraryClasses>

+      VariablePolicyLib|MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.inf

+

+    <PcdsFixedAtBuild>

+      gEfiMdeModulePkgTokenSpaceGuid.PcdAllowVariablePolicyEnforcementDisable|TRUE

+  }

+

   MdeModulePkg/Library/DxeResetSystemLib/UnitTest/DxeResetSystemLibUnitTestHost.inf {

     <LibraryClasses>

       ResetSystemLib|MdeModulePkg/Library/DxeResetSystemLib/DxeResetSystemLib.inf

--
2.26.2.windows.1.8.g01c50adf56.20200515075929


-=-=-=-=-=-=
Groups.io Links: You receive all messages sent to this group.

View/Reply Online (#60643): https://nam06.safelinks.protection.outlook.com/?url=https%3A%2F%2Fedk2.groups.io%2Fg%2Fdevel%2Fmessage%2F60643&amp;data=02%7C01%7Cbret.barkelew%40microsoft.com%7C5f525d9b2e954b4b474d08d807a3da45%7C72f988bf86f141af91ab2d7cd011db47%7C1%7C0%7C637267747622315664&amp;sdata=NShPJaGWqn%2F4krAZWL9B1QUdajPc1uWC3%2BZPd3wcz4E%3D&amp;reserved=0
Mute This Topic: https://nam06.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgroups.io%2Fmt%2F74646432%2F1852292&amp;data=02%7C01%7Cbret.barkelew%40microsoft.com%7C5f525d9b2e954b4b474d08d807a3da45%7C72f988bf86f141af91ab2d7cd011db47%7C1%7C0%7C637267747622315664&amp;sdata=aq1LOygDYZbMpRGiibZCOCfMPffZtEFQLR8K4LKmUYk%3D&amp;reserved=0
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://nam06.safelinks.protection.outlook.com/?url=https%3A%2F%2Fedk2.groups.io%2Fg%2Fdevel%2Funsub&amp;data=02%7C01%7Cbret.barkelew%40microsoft.com%7C5f525d9b2e954b4b474d08d807a3da45%7C72f988bf86f141af91ab2d7cd011db47%7C1%7C0%7C637267747622315664&amp;sdata=CGyCvVr0DX3Z%2F%2BKh43OWSObWZZG58YFT6f94FhOY1LA%3D&amp;reserved=0  [bret.barkelew@microsoft.com]
-=-=-=-=-=-=