From: "Bret Barkelew" <bret.barkelew@microsoft.com>
To: "devel@edk2.groups.io" <devel@edk2.groups.io>,
"bret@corthon.com" <bret@corthon.com>
Cc: Jian J Wang <jian.j.wang@intel.com>,
Hao A Wu <hao.a.wu@intel.com>, liming.gao <liming.gao@intel.com>
Subject: Re: [EXTERNAL] [edk2-devel] [PATCH v5 02/14] MdeModulePkg: Define the VariablePolicyLib
Date: Wed, 17 Jun 2020 07:29:19 +0000 [thread overview]
Message-ID: <CY4PR21MB074358CF8FE24CBA96894524EF9A0@CY4PR21MB0743.namprd21.prod.outlook.com> (raw)
In-Reply-To: <20200603065810.806-3-brbarkel@microsoft.com>
[-- Attachment #1: Type: text/plain, Size: 151350 bytes --]
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&data=02%7C01%7Cbret.barkelew%40microsoft.com%7C5f525d9b2e954b4b474d08d807a3da45%7C72f988bf86f141af91ab2d7cd011db47%7C1%7C0%7C637267747622305708&sdata=V3OQlMW5ifVdpn5BJiGAmc8HsjXplYCm%2FdANjL9xbdI%3D&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>
---
| 46 +
| 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(+)
--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;
+}
--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&data=02%7C01%7Cbret.barkelew%40microsoft.com%7C5f525d9b2e954b4b474d08d807a3da45%7C72f988bf86f141af91ab2d7cd011db47%7C1%7C0%7C637267747622315664&sdata=NShPJaGWqn%2F4krAZWL9B1QUdajPc1uWC3%2BZPd3wcz4E%3D&reserved=0
Mute This Topic: https://nam06.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgroups.io%2Fmt%2F74646432%2F1852292&data=02%7C01%7Cbret.barkelew%40microsoft.com%7C5f525d9b2e954b4b474d08d807a3da45%7C72f988bf86f141af91ab2d7cd011db47%7C1%7C0%7C637267747622315664&sdata=aq1LOygDYZbMpRGiibZCOCfMPffZtEFQLR8K4LKmUYk%3D&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&data=02%7C01%7Cbret.barkelew%40microsoft.com%7C5f525d9b2e954b4b474d08d807a3da45%7C72f988bf86f141af91ab2d7cd011db47%7C1%7C0%7C637267747622315664&sdata=CGyCvVr0DX3Z%2F%2BKh43OWSObWZZG58YFT6f94FhOY1LA%3D&reserved=0 [bret.barkelew@microsoft.com]
-=-=-=-=-=-=
[-- Attachment #2: Type: text/html, Size: 302265 bytes --]
next prev parent reply other threads:[~2020-06-17 7:29 UTC|newest]
Thread overview: 29+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-06-03 6:57 [PATCH v5 00/14] Add the VariablePolicy feature Bret Barkelew
2020-06-03 6:57 ` [PATCH v5 01/14] MdeModulePkg: Define the VariablePolicy protocol interface Bret Barkelew
2020-06-17 7:28 ` [EXTERNAL] [edk2-devel] " Bret Barkelew
2020-06-03 6:57 ` [PATCH v5 02/14] MdeModulePkg: Define the VariablePolicyLib Bret Barkelew
2020-06-17 7:29 ` Bret Barkelew [this message]
2020-06-03 6:57 ` [PATCH v5 03/14] MdeModulePkg: Define the VariablePolicyHelperLib Bret Barkelew
2020-06-17 7:29 ` [EXTERNAL] [edk2-devel] " Bret Barkelew
2020-06-03 6:58 ` [PATCH v5 04/14] MdeModulePkg: Define the VarCheckPolicyLib and SMM interface Bret Barkelew
2020-06-03 6:58 ` [PATCH v5 05/14] OvmfPkg: Add VariablePolicy engine to OvmfPkg platform Bret Barkelew
2020-06-03 6:58 ` [PATCH v5 06/14] EmulatorPkg: Add VariablePolicy engine to EmulatorPkg platform Bret Barkelew
2020-06-17 7:32 ` [EXTERNAL] [edk2-devel] " Bret Barkelew
2020-06-03 6:58 ` [PATCH v5 07/14] ArmVirtPkg: Add VariablePolicy engine to ArmVirtPkg platform Bret Barkelew
2020-06-03 6:58 ` [PATCH v5 08/14] UefiPayloadPkg: Add VariablePolicy engine to UefiPayloadPkg platform Bret Barkelew
2020-06-03 14:35 ` Ma, Maurice
2020-06-03 6:58 ` [PATCH v5 09/14] MdeModulePkg: Connect VariablePolicy business logic to VariableServices Bret Barkelew
2020-06-03 6:58 ` [PATCH v5 10/14] MdeModulePkg: Allow VariablePolicy state to delete protected variables Bret Barkelew
2020-06-17 7:34 ` [EXTERNAL] [edk2-devel] " Bret Barkelew
2020-06-03 6:58 ` [PATCH v5 11/14] SecurityPkg: Allow VariablePolicy state to delete authenticated variables Bret Barkelew
2020-06-17 7:34 ` [EXTERNAL] [edk2-devel] " Bret Barkelew
2020-06-03 6:58 ` [PATCH v5 12/14] MdeModulePkg: Change TCG MOR variables to use VariablePolicy Bret Barkelew
2020-06-17 7:35 ` [EXTERNAL] [edk2-devel] " Bret Barkelew
2020-06-03 6:58 ` [PATCH v5 13/14] MdeModulePkg: Drop VarLock from RuntimeDxe variable driver Bret Barkelew
2020-06-03 6:58 ` [PATCH v5 14/14] MdeModulePkg: Add a shell-based functional test for VariablePolicy Bret Barkelew
2020-06-17 7:37 ` [EXTERNAL] [edk2-devel] " Bret Barkelew
2020-06-03 13:38 ` [PATCH v5 00/14] Add the VariablePolicy feature Laszlo Ersek
2020-06-03 15:09 ` [edk2-devel] " Leif Lindholm
2020-06-09 5:49 ` [EXTERNAL] " Bret Barkelew
2020-06-09 5:52 ` [EXTERNAL] " Bret Barkelew
2020-06-17 7:44 ` Guomin Jiang
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-list from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=CY4PR21MB074358CF8FE24CBA96894524EF9A0@CY4PR21MB0743.namprd21.prod.outlook.com \
--to=devel@edk2.groups.io \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox