From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-pj1-f46.google.com (mail-pj1-f46.google.com [209.85.216.46]) by mx.groups.io with SMTP id smtpd.web11.6963.1600841305616344223 for ; Tue, 22 Sep 2020 23:08:25 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=@corthon-com.20150623.gappssmtp.com header.s=20150623 header.b=Zz/O4q3S; spf=none, err=permanent DNS error (domain: corthon.com, ip: 209.85.216.46, mailfrom: bret@corthon.com) Received: by mail-pj1-f46.google.com with SMTP id b17so2614554pji.1 for ; Tue, 22 Sep 2020 23:08:25 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=corthon-com.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=gsjB3WL4yvnkvpf2gL778EafbosvFuZ2XY+XTxWNZuc=; b=Zz/O4q3St8svJMGKclUm5mW58v9iYs6/ydf02FCHPdcb2B6K4tlZVzNO+HqG0zvICl F1+R+hwUFv1dtaRZliSSGU4QoQ8jQmpt/xmQiVPdfSH5V1IjX2L4tomZudlY6Lfo7wYJ 8aIR9qNLgsToVvgqNqzcsarlhDGDz0B3HBDORkUCul1TVXWmzLpc1C8w233eFXuHuTfE jS5NGINMmiE7PI1iCkbyWFKZXjArhJAzkJppRnOrUlAqWLYXS9jN82EPAT3avW8AokXW h6QKjnqYYJEtGtblbSKg4y0wfOKRImw6sMQPnCb9VRr6Bh0HpD41+SCaXtmXuNZwbG2T CQSw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=gsjB3WL4yvnkvpf2gL778EafbosvFuZ2XY+XTxWNZuc=; b=bXJZxIFD8oVV9twtgj+3GQ42QrECNe1MCtysEVib1bAwjhMPexDXeNkty5cIv/OrvQ uz4BK1gXtyNauQF2r3F5diwrQjaAGGGW+DNWOnMQqhoxL/DlDGDXPQCl4JRzdrm5mP0Z zX0FJ4jqiih4lOGSC1I0WO70hyynwPRTZLemiNh/bXuuTtFvCbFFeCm4/jXj7MmwXyYK XzwTpq2826EdNs1CjRm1jTCT/tjSoSRtGASltyOTwEvpzQwFiloPGu6fn6AGUyk6euuE Cw8XKx+ryHFTBJwICR6JK9yVNfBKMwWI4C1Eli7ntLQV+hjC7GZoKK7AmXL/9ErFZjvT Grag== X-Gm-Message-State: AOAM5318e1ngT/N2+Ud4BcmU5IPGcl6qiNGSoy4EGVwXLUFjYZrTQubq 99eQJzdRqbbLtvRL11QH/5ymPnMrel15GPoF X-Google-Smtp-Source: ABdhPJzXTPy/x9OnKwrbx9SmxP/lxJhsiTYUhBx2lqHA4PuLEt4oQet7VnrvTdjozGoRC0X6NLpGkQ== X-Received: by 2002:a17:90b:693:: with SMTP id m19mr6755723pjz.111.1600841303909; Tue, 22 Sep 2020 23:08:23 -0700 (PDT) Return-Path: Received: from localhost.localdomain (174-21-140-128.tukw.qwest.net. [174.21.140.128]) by smtp.gmail.com with ESMTPSA id x4sm16960498pff.57.2020.09.22.23.08.22 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 22 Sep 2020 23:08:23 -0700 (PDT) From: "Bret Barkelew" X-Google-Original-From: Bret Barkelew To: devel@edk2.groups.io Cc: Jian J Wang , Hao A Wu , Liming Gao , Bret Barkelew , Dandan Bi Subject: [PATCH v8 02/14] MdeModulePkg: Define the VariablePolicyLib Date: Tue, 22 Sep 2020 23:07:36 -0700 Message-Id: <20200923060748.3795-3-bret.barkelew@microsoft.com> X-Mailer: git-send-email 2.28.0.windows.1 In-Reply-To: <20200923060748.3795-1-bret.barkelew@microsoft.com> References: <20200923060748.3795-1-bret.barkelew@microsoft.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable From: Bret Barkelew https://bugzilla.tianocore.org/show_bug.cgi?id=3D2522 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 Cc: Hao A Wu Cc: Liming Gao Cc: Bret Barkelew Signed-off-by: Bret Barkelew Reviewed-by: Dandan Bi Acked-by: Jian J Wang --- MdeModulePkg/Library/VariablePolicyLib/VariablePolicyExtraInitNull.c = | 46 + MdeModulePkg/Library/VariablePolicyLib/VariablePolicyExtraInitRuntimeDxe.c= | 85 + MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.c = | 830 +++++++ MdeModulePkg/Library/VariablePolicyLib/VariablePolicyUnitTest/VariablePoli= cyUnitTest.c | 2452 ++++++++++++++++++++ MdeModulePkg/Include/Library/VariablePolicyLib.h = | 207 ++ MdeModulePkg/Library/VariablePolicyLib/ReadMe.md = | 410 ++++ MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.inf = | 49 + MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.uni = | 12 + MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLibRuntimeDxe.inf = | 51 + MdeModulePkg/Library/VariablePolicyLib/VariablePolicyUnitTest/VariablePoli= cyUnitTest.inf | 45 + MdeModulePkg/MdeModulePkg.ci.yaml = | 4 +- MdeModulePkg/MdeModulePkg.dec = | 3 + MdeModulePkg/MdeModulePkg.dsc = | 5 + MdeModulePkg/Test/MdeModulePkgHostTest.dsc = | 11 + 14 files changed, 4209 insertions(+), 1 deletion(-) diff --git a/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyExtraInit= Null.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=0D +This file contains extra init and deinit routines that don't do anything=0D +extra.=0D +=0D +Copyright (c) Microsoft Corporation.=0D +SPDX-License-Identifier: BSD-2-Clause-Patent=0D +=0D +**/=0D +=0D +#include =0D +=0D +=0D +/**=0D + An extra init hook that enables the RuntimeDxe library instance to=0D + register VirtualAddress change callbacks. Among other things.=0D +=0D + @retval EFI_SUCCESS Everything is good. Continue with init.=0D + @retval Others Uh... don't continue.=0D +=0D +**/=0D +EFI_STATUS=0D +VariablePolicyExtraInit (=0D + VOID=0D + )=0D +{=0D + // NULL implementation.=0D + return EFI_SUCCESS;=0D +}=0D +=0D +=0D +/**=0D + An extra deinit hook that enables the RuntimeDxe library instance to=0D + register VirtualAddress change callbacks. Among other things.=0D +=0D + @retval EFI_SUCCESS Everything is good. Continue with deinit.=0D + @retval Others Uh... don't continue.=0D +=0D +**/=0D +EFI_STATUS=0D +VariablePolicyExtraDeinit (=0D + VOID=0D + )=0D +{=0D + // NULL implementation.=0D + return EFI_SUCCESS;=0D +}=0D diff --git a/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyExtraInit= RuntimeDxe.c b/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyExtraIn= itRuntimeDxe.c new file mode 100644 index 000000000000..3ca87048b14b --- /dev/null +++ b/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyExtraInitRuntime= Dxe.c @@ -0,0 +1,85 @@ +/** @file -- VariablePolicyExtraInitRuntimeDxe.c=0D +This file contains extra init and deinit routines that register and unregi= ster=0D +VariableAddressChange callbacks.=0D +=0D +Copyright (c) Microsoft Corporation.=0D +SPDX-License-Identifier: BSD-2-Clause-Patent=0D +=0D +**/=0D +=0D +#include =0D +#include =0D +=0D +extern EFI_GET_VARIABLE mGetVariableHelper;=0D +extern UINT8 *mPolicyTable;=0D +STATIC BOOLEAN mIsVirtualAddrConverted;=0D +STATIC EFI_EVENT mVariablePolicyLibVirtualAddressChangeEvent =3D= NULL;=0D +=0D +/**=0D + For the RuntimeDxe version of this lib, convert internal pointer address= es to virtual addresses.=0D +=0D + @param[in] Event Event whose notification function is being invoked= .=0D + @param[in] Context The pointer to the notification function's context= , which=0D + is implementation-dependent.=0D +**/=0D +STATIC=0D +VOID=0D +EFIAPI=0D +VariablePolicyLibVirtualAddressCallback (=0D + IN EFI_EVENT Event,=0D + IN VOID *Context=0D + )=0D +{=0D + gRT->ConvertPointer (0, (VOID **)&mPolicyTable);=0D + gRT->ConvertPointer (0, (VOID **)&mGetVariableHelper);=0D + mIsVirtualAddrConverted =3D TRUE;=0D +}=0D +=0D +=0D +/**=0D + An extra init hook that enables the RuntimeDxe library instance to=0D + register VirtualAddress change callbacks. Among other things.=0D +=0D + @retval EFI_SUCCESS Everything is good. Continue with init.=0D + @retval Others Uh... don't continue.=0D +=0D +**/=0D +EFI_STATUS=0D +VariablePolicyExtraInit (=0D + VOID=0D + )=0D +{=0D + return gBS->CreateEventEx (EVT_NOTIFY_SIGNAL,=0D + TPL_NOTIFY,=0D + VariablePolicyLibVirtualAddressCallback,=0D + NULL,=0D + &gEfiEventVirtualAddressChangeGuid,=0D + &mVariablePolicyLibVirtualAddressChangeEvent= );=0D +}=0D +=0D +=0D +/**=0D + An extra deinit hook that enables the RuntimeDxe library instance to=0D + register VirtualAddress change callbacks. Among other things.=0D +=0D + @retval EFI_SUCCESS Everything is good. Continue with deinit.=0D + @retval Others Uh... don't continue.=0D +=0D +**/=0D +EFI_STATUS=0D +VariablePolicyExtraDeinit (=0D + VOID=0D + )=0D +{=0D + EFI_STATUS Status;=0D +=0D + Status =3D EFI_SUCCESS;=0D + if (mIsVirtualAddrConverted) {=0D + Status =3D gBS->CloseEvent (mVariablePolicyLibVirtualAddressChangeEven= t);=0D + }=0D + else {=0D + Status =3D EFI_SUCCESS;=0D + }=0D +=0D + return Status;=0D +}=0D diff --git a/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.c b/M= deModulePkg/Library/VariablePolicyLib/VariablePolicyLib.c new file mode 100644 index 000000000000..5029ddb96adb --- /dev/null +++ b/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.c @@ -0,0 +1,830 @@ +/** @file -- VariablePolicyLib.c=0D +Business logic for Variable Policy enforcement.=0D +=0D +Copyright (c) Microsoft Corporation.=0D +SPDX-License-Identifier: BSD-2-Clause-Patent=0D +=0D +**/=0D +=0D +#include =0D +=0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +=0D +#include =0D +#include =0D +=0D +=0D +// IMPORTANT NOTE: This library is currently rife with multiple return sta= tements=0D +// for error handling. A refactor should remove these at s= ome point.=0D +=0D +//=0D +// This library was designed with advanced unit-test features.=0D +// This define handles the configuration.=0D +#ifdef INTERNAL_UNIT_TEST=0D +#undef STATIC=0D +#define STATIC // Nothing...=0D +#endif=0D +=0D +// An abstracted GetVariable interface that enables configuration regardle= ss of the environment.=0D +EFI_GET_VARIABLE mGetVariableHelper =3D NULL;=0D +=0D +// Master switch to lock this entire interface. Does not stop enforcement,= =0D +// just prevents the configuration from being changed for the rest of the = boot.=0D +STATIC BOOLEAN mInterfaceLocked =3D FALSE;=0D +=0D +// Master switch to disable the entire interface for a single boot.=0D +// This will disable all policy enforcement for the duration of the boot.= =0D +STATIC BOOLEAN mProtectionDisabled =3D FALSE;=0D +=0D +// Table to hold all the current policies.=0D +UINT8 *mPolicyTable =3D NULL;=0D +STATIC UINT32 mCurrentTableSize =3D 0;=0D +STATIC UINT32 mCurrentTableUsage =3D 0;=0D +STATIC UINT32 mCurrentTableCount =3D 0;=0D +=0D +#define POLICY_TABLE_STEP_SIZE 0x1000=0D +=0D +// NOTE: DO NOT USE THESE MACROS on any structure that has not been valida= ted.=0D +// Current table data has already been sanitized.=0D +#define GET_NEXT_POLICY(CurPolicy) (VARIABLE_POLICY_ENTRY*)((UINT8*)Cur= Policy + CurPolicy->Size)=0D +#define GET_POLICY_NAME(CurPolicy) (CHAR16*)((UINTN)CurPolicy + CurPoli= cy->OffsetToName)=0D +=0D +#define MATCH_PRIORITY_EXACT 0=0D +#define MATCH_PRIORITY_MAX MATCH_PRIORITY_EXACT=0D +#define MATCH_PRIORITY_MIN MAX_UINT8=0D +=0D +=0D +/**=0D + An extra init hook that enables the RuntimeDxe library instance to=0D + register VirtualAddress change callbacks. Among other things.=0D +=0D + @retval EFI_SUCCESS Everything is good. Continue with init.=0D + @retval Others Uh... don't continue.=0D +=0D +**/=0D +EFI_STATUS=0D +VariablePolicyExtraInit (=0D + VOID=0D + );=0D +=0D +/**=0D + An extra deinit hook that enables the RuntimeDxe library instance to=0D + register VirtualAddress change callbacks. Among other things.=0D +=0D + @retval EFI_SUCCESS Everything is good. Continue with deinit.=0D + @retval Others Uh... don't continue.=0D +=0D +**/=0D +EFI_STATUS=0D +VariablePolicyExtraDeinit (=0D + VOID=0D + );=0D +=0D +=0D +/**=0D + This helper function determines whether the structure of an incoming pol= icy=0D + is valid and internally consistent.=0D +=0D + @param[in] NewPolicy Pointer to the incoming policy structure.=0D +=0D + @retval TRUE=0D + @retval FALSE Pointer is NULL, size is wrong, strings are empty, o= r=0D + substructures overlap.=0D +=0D +**/=0D +STATIC=0D +BOOLEAN=0D +IsValidVariablePolicyStructure (=0D + IN CONST VARIABLE_POLICY_ENTRY *NewPolicy=0D + )=0D +{=0D + EFI_STATUS Status;=0D + UINTN EntryEnd;=0D + CHAR16 *CheckChar;=0D + UINTN WildcardCount;=0D +=0D + // Sanitize some quick values.=0D + if (NewPolicy =3D=3D NULL || NewPolicy->Size =3D=3D 0 ||=0D + // Structure size should be at least as long as the minumum structur= e and a NULL string.=0D + NewPolicy->Size < sizeof(VARIABLE_POLICY_ENTRY) ||=0D + // Check for the known revision.=0D + NewPolicy->Version !=3D VARIABLE_POLICY_ENTRY_REVISION) {=0D + return FALSE;=0D + }=0D +=0D + // Calculate the theoretical end of the structure and make sure=0D + // that the structure can fit in memory.=0D + Status =3D SafeUintnAdd( (UINTN)NewPolicy, NewPolicy->Size, &EntryEnd );= =0D + if (EFI_ERROR( Status )) {=0D + return FALSE;=0D + }=0D +=0D + // Check for a valid Max Size.=0D + if (NewPolicy->MaxSize =3D=3D 0) {=0D + return FALSE;=0D + }=0D +=0D + // Check for the valid list of lock policies.=0D + if (NewPolicy->LockPolicyType !=3D VARIABLE_POLICY_TYPE_NO_LOCK &&=0D + NewPolicy->LockPolicyType !=3D VARIABLE_POLICY_TYPE_LOCK_NOW &&=0D + NewPolicy->LockPolicyType !=3D VARIABLE_POLICY_TYPE_LOCK_ON_CREATE &= &=0D + NewPolicy->LockPolicyType !=3D VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STAT= E)=0D + {=0D + return FALSE;=0D + }=0D +=0D + // If the policy type is VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE, make su= re that the matching state variable Name=0D + // terminates before the OffsetToName for the matching policy variable N= ame.=0D + if (NewPolicy->LockPolicyType =3D=3D VARIABLE_POLICY_TYPE_LOCK_ON_VAR_ST= ATE) {=0D + // Adjust CheckChar to the offset of the LockPolicy->Name.=0D + Status =3D SafeUintnAdd( (UINTN)NewPolicy + sizeof(VARIABLE_POLICY_ENT= RY),=0D + sizeof(VARIABLE_LOCK_ON_VAR_STATE_POLICY),=0D + (UINTN*)&CheckChar );=0D + if (EFI_ERROR( Status ) || EntryEnd <=3D (UINTN)CheckChar) {=0D + return FALSE;=0D + }=0D + while (*CheckChar !=3D CHAR_NULL) {=0D + if (EntryEnd <=3D (UINTN)CheckChar) {=0D + return FALSE;=0D + }=0D + CheckChar++;=0D + }=0D + // At this point we should have either exeeded the structure or be poi= nting at the last char in LockPolicy->Name.=0D + // We should check to make sure that the policy Name comes immediately= after this charcter.=0D + if ((UINTN)++CheckChar !=3D (UINTN)NewPolicy + NewPolicy->OffsetToName= ) {=0D + return FALSE;=0D + }=0D + // If the policy type is any other value, make sure that the LockPolicy = structure has a zero length.=0D + } else {=0D + if (NewPolicy->OffsetToName !=3D sizeof(VARIABLE_POLICY_ENTRY)) {=0D + return FALSE;=0D + }=0D + }=0D +=0D + // Check to make sure that the name has a terminating character=0D + // before the end of the structure.=0D + // We've already checked that the name is within the bounds of the struc= ture.=0D + if (NewPolicy->Size !=3D NewPolicy->OffsetToName) {=0D + CheckChar =3D (CHAR16*)((UINTN)NewPolicy + NewPolicy->OffsetToName);=0D + WildcardCount =3D 0;=0D + while (*CheckChar !=3D CHAR_NULL) {=0D + // Make sure there aren't excessive wildcards.=0D + if (*CheckChar =3D=3D '#') {=0D + WildcardCount++;=0D + if (WildcardCount > MATCH_PRIORITY_MIN) {=0D + return FALSE;=0D + }=0D + }=0D + // Make sure you're still within the bounds of the policy structure.= =0D + if (EntryEnd <=3D (UINTN)CheckChar) {=0D + return FALSE;=0D + }=0D + CheckChar++;=0D + }=0D +=0D + // Finally, we should be pointed at the very last character in Name, s= o we should be right=0D + // up against the end of the structure.=0D + if ((UINTN)++CheckChar !=3D EntryEnd) {=0D + return FALSE;=0D + }=0D + }=0D +=0D + return TRUE;=0D +}=0D +=0D +=0D +/**=0D + This helper function evaluates a policy and determines whether it matche= s the target=0D + variable. If matched, will also return a value corresponding to the prio= rity of the match.=0D +=0D + The rules for "best match" are listed in the Variable Policy Spec.=0D + Perfect name matches will return 0.=0D + Single wildcard characters will return the number of wildcard characters= .=0D + Full namespaces will return MAX_UINT8.=0D +=0D + @param[in] EvalEntry Pointer to the policy entry being evaluate= d.=0D + @param[in] VariableName Same as EFI_SET_VARIABLE.=0D + @param[in] VendorGuid Same as EFI_SET_VARIABLE.=0D + @param[out] MatchPriority [Optional] On finding a match, this value = contains the priority of the match.=0D + Lower number =3D=3D higher priority. Only = valid if a match found.=0D +=0D + @retval TRUE Current entry matches the target variable.=0D + @retval FALSE Current entry does not match at all.=0D +=0D +**/=0D +STATIC=0D +BOOLEAN=0D +EvaluatePolicyMatch (=0D + IN CONST VARIABLE_POLICY_ENTRY *EvalEntry,=0D + IN CONST CHAR16 *VariableName,=0D + IN CONST EFI_GUID *VendorGuid,=0D + OUT UINT8 *MatchPriority OPTIONAL=0D + )=0D +{=0D + BOOLEAN Result;=0D + CHAR16 *PolicyName;=0D + UINT8 CalculatedPriority;=0D + UINTN Index;=0D +=0D + Result =3D FALSE;=0D + CalculatedPriority =3D MATCH_PRIORITY_EXACT;=0D +=0D + // Step 1: If the GUID doesn't match, we're done. No need to evaluate an= ything else.=0D + if (!CompareGuid( &EvalEntry->Namespace, VendorGuid )) {=0D + goto Exit;=0D + }=0D +=0D + // If the GUID matches, check to see whether there is a Name associated= =0D + // with the policy. If not, this policy matches the entire namespace.=0D + // Missing Name is indicated by size being equal to name.=0D + if (EvalEntry->Size =3D=3D EvalEntry->OffsetToName) {=0D + CalculatedPriority =3D MATCH_PRIORITY_MIN;=0D + Result =3D TRUE;=0D + goto Exit;=0D + }=0D +=0D + // Now that we know the name exists, get it.=0D + PolicyName =3D GET_POLICY_NAME( EvalEntry );=0D +=0D + // Evaluate the name against the policy name and check for a match.=0D + // Account for any wildcards.=0D + Index =3D 0;=0D + Result =3D TRUE;=0D + // Keep going until the end of both strings.=0D + while (PolicyName[Index] !=3D CHAR_NULL || VariableName[Index] !=3D CHAR= _NULL) {=0D + // If we don't have a match...=0D + if (PolicyName[Index] !=3D VariableName[Index] || PolicyName[Index] = =3D=3D '#') {=0D + // If this is a numerical wildcard, we can consider=0D + // it a match if we alter the priority.=0D + if (PolicyName[Index] =3D=3D L'#' &&=0D + ((L'0' <=3D VariableName[Index] && VariableName[Index] <=3D L'= 9') ||=0D + (L'A' <=3D VariableName[Index] && VariableName[Index] <=3D L'= F') ||=0D + (L'a' <=3D VariableName[Index] && VariableName[Index] <=3D L'= f'))) {=0D + if (CalculatedPriority < MATCH_PRIORITY_MIN) {=0D + CalculatedPriority++;=0D + }=0D + // Otherwise, not a match.=0D + } else {=0D + Result =3D FALSE;=0D + goto Exit;=0D + }=0D + }=0D + Index++;=0D + }=0D +=0D +Exit:=0D + if (Result && MatchPriority !=3D NULL) {=0D + *MatchPriority =3D CalculatedPriority;=0D + }=0D + return Result;=0D +}=0D +=0D +=0D +/**=0D + This helper function walks the current policy table and returns a pointe= r=0D + to the best match, if any are found. Leverages EvaluatePolicyMatch() to= =0D + determine "best".=0D +=0D + @param[in] VariableName Same as EFI_SET_VARIABLE.=0D + @param[in] VendorGuid Same as EFI_SET_VARIABLE.=0D + @param[out] ReturnPriority [Optional] If pointer is provided, return= the=0D + priority of the match. Same as EvaluatePo= licyMatch().=0D + Only valid if a match is returned.=0D +=0D + @retval VARIABLE_POLICY_ENTRY* Best match that was found.=0D + @retval NULL No match was found.=0D +=0D +**/=0D +STATIC=0D +VARIABLE_POLICY_ENTRY*=0D +GetBestPolicyMatch (=0D + IN CONST CHAR16 *VariableName,=0D + IN CONST EFI_GUID *VendorGuid,=0D + OUT UINT8 *ReturnPriority OPTIONAL=0D + )=0D +{=0D + VARIABLE_POLICY_ENTRY *BestResult;=0D + VARIABLE_POLICY_ENTRY *CurrentEntry;=0D + UINT8 MatchPriority;=0D + UINT8 CurrentPriority;=0D + UINTN Index;=0D +=0D + BestResult =3D NULL;=0D + MatchPriority =3D MATCH_PRIORITY_EXACT;=0D +=0D + // Walk all entries in the table, looking for matches.=0D + CurrentEntry =3D (VARIABLE_POLICY_ENTRY*)mPolicyTable;=0D + for (Index =3D 0; Index < mCurrentTableCount; Index++) {=0D + // Check for a match.=0D + if (EvaluatePolicyMatch( CurrentEntry, VariableName, VendorGuid, &Curr= entPriority )) {=0D + // If match is better, take it.=0D + if (BestResult =3D=3D NULL || CurrentPriority < MatchPriority) {=0D + BestResult =3D CurrentEntry;=0D + MatchPriority =3D CurrentPriority;=0D + }=0D +=0D + // If you've hit the highest-priority match, can exit now.=0D + if (MatchPriority =3D=3D 0) {=0D + break;=0D + }=0D + }=0D +=0D + // If we're still in the loop, move to the next entry.=0D + CurrentEntry =3D GET_NEXT_POLICY( CurrentEntry );=0D + }=0D +=0D + // If a return priority was requested, return it.=0D + if (ReturnPriority !=3D NULL) {=0D + *ReturnPriority =3D MatchPriority;=0D + }=0D +=0D + return BestResult;=0D +}=0D +=0D +=0D +/**=0D + This API function validates and registers a new policy with=0D + the policy enforcement engine.=0D +=0D + @param[in] NewPolicy Pointer to the incoming policy structure.=0D +=0D + @retval EFI_SUCCESS=0D + @retval EFI_INVALID_PARAMETER NewPolicy is NULL or is internally i= nconsistent.=0D + @retval EFI_ALREADY_STARTED An identical matching policy already= exists.=0D + @retval EFI_WRITE_PROTECTED The interface has been locked until = the next reboot.=0D + @retval EFI_UNSUPPORTED Policy enforcement has been disabled= . No reason to add more policies.=0D + @retval EFI_ABORTED A calculation error has prevented th= is function from completing.=0D + @retval EFI_OUT_OF_RESOURCES Cannot grow the table to hold any mo= re policies.=0D + @retval EFI_NOT_READY Library has not yet been initialized= .=0D +=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +RegisterVariablePolicy (=0D + IN CONST VARIABLE_POLICY_ENTRY *NewPolicy=0D + )=0D +{=0D + EFI_STATUS Status;=0D + VARIABLE_POLICY_ENTRY *MatchPolicy;=0D + UINT8 MatchPriority;=0D + UINT32 NewSize;=0D + UINT8 *NewTable;=0D +=0D + if (!IsVariablePolicyLibInitialized()) {=0D + return EFI_NOT_READY;=0D + }=0D + if (mInterfaceLocked) {=0D + return EFI_WRITE_PROTECTED;=0D + }=0D +=0D + if (!IsValidVariablePolicyStructure( NewPolicy )) {=0D + return EFI_INVALID_PARAMETER;=0D + }=0D +=0D + // Check to see whether an exact matching policy already exists.=0D + MatchPolicy =3D GetBestPolicyMatch( GET_POLICY_NAME( NewPolicy ),=0D + &NewPolicy->Namespace,=0D + &MatchPriority );=0D + if (MatchPolicy !=3D NULL && MatchPriority =3D=3D MATCH_PRIORITY_EXACT) = {=0D + return EFI_ALREADY_STARTED;=0D + }=0D +=0D + // If none exists, create it.=0D + // If we need more space, allocate that now.=0D + Status =3D SafeUint32Add( mCurrentTableUsage, NewPolicy->Size, &NewSize = );=0D + if (EFI_ERROR( Status )) {=0D + return EFI_ABORTED;=0D + }=0D + if (NewSize > mCurrentTableSize) {=0D + // Use NewSize to calculate the new table size in units of POLICY_TABL= E_STEP_SIZE.=0D + NewSize =3D (NewSize % POLICY_TABLE_STEP_SIZE) > 0 ?=0D + (NewSize / POLICY_TABLE_STEP_SIZE) + 1 :=0D + (NewSize / POLICY_TABLE_STEP_SIZE);=0D + // Calculate the new table size in absolute bytes.=0D + Status =3D SafeUint32Mult( NewSize, POLICY_TABLE_STEP_SIZE, &NewSize )= ;=0D + if (EFI_ERROR( Status )) {=0D + return EFI_ABORTED;=0D + }=0D +=0D + // Reallocate and copy the table.=0D + NewTable =3D AllocatePool( NewSize );=0D + if (NewTable =3D=3D NULL) {=0D + return EFI_OUT_OF_RESOURCES;=0D + }=0D + CopyMem( NewTable, mPolicyTable, mCurrentTableUsage );=0D + mCurrentTableSize =3D NewSize;=0D + if (mPolicyTable !=3D NULL) {=0D + FreePool( mPolicyTable );=0D + }=0D + mPolicyTable =3D NewTable;=0D + }=0D + // Copy the policy into the table.=0D + CopyMem( mPolicyTable + mCurrentTableUsage, NewPolicy, NewPolicy->Size )= ;=0D + mCurrentTableUsage +=3D NewPolicy->Size;=0D + mCurrentTableCount +=3D 1;=0D +=0D + // We're done here.=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +=0D +/**=0D + This API function checks to see whether the parameters to SetVariable wo= uld=0D + be allowed according to the current variable policies.=0D +=0D + @param[in] VariableName Same as EFI_SET_VARIABLE.=0D + @param[in] VendorGuid Same as EFI_SET_VARIABLE.=0D + @param[in] Attributes Same as EFI_SET_VARIABLE.=0D + @param[in] DataSize Same as EFI_SET_VARIABLE.=0D + @param[in] Data Same as EFI_SET_VARIABLE.=0D +=0D + @retval EFI_SUCCESS A matching policy allows this update= .=0D + @retval EFI_SUCCESS There are currently no policies that= restrict this update.=0D + @retval EFI_SUCCESS The protections have been disable un= til the next reboot.=0D + @retval EFI_WRITE_PROTECTED Variable is currently locked.=0D + @retval EFI_INVALID_PARAMETER Attributes or size are invalid.=0D + @retval EFI_ABORTED A lock policy exists, but an error p= revented evaluation.=0D + @retval EFI_NOT_READY Library has not been initialized.=0D +=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +ValidateSetVariable (=0D + IN CHAR16 *VariableName,=0D + IN EFI_GUID *VendorGuid,=0D + IN UINT32 Attributes,=0D + IN UINTN DataSize,=0D + IN VOID *Data=0D + )=0D +{=0D + BOOLEAN IsDel;=0D + VARIABLE_POLICY_ENTRY *ActivePolicy;=0D + EFI_STATUS Status;=0D + EFI_STATUS ReturnStatus;=0D + VARIABLE_LOCK_ON_VAR_STATE_POLICY *StateVarPolicy;=0D + CHAR16 *StateVarName;=0D + UINTN StateVarSize;=0D + UINT8 StateVar;=0D +=0D + ReturnStatus =3D EFI_SUCCESS;=0D +=0D + if (!IsVariablePolicyLibInitialized()) {=0D + ReturnStatus =3D EFI_NOT_READY;=0D + goto Exit;=0D + }=0D +=0D + // Bail if the protections are currently disabled.=0D + if (mProtectionDisabled) {=0D + ReturnStatus =3D EFI_SUCCESS;=0D + goto Exit;=0D + }=0D +=0D + // Determine whether this is a delete operation.=0D + // If so, it will affect which tests are applied.=0D + if ((DataSize =3D=3D 0) && ((Attributes & EFI_VARIABLE_APPEND_WRITE) =3D= =3D 0)) {=0D + IsDel =3D TRUE;=0D + } else {=0D + IsDel =3D FALSE;=0D + }=0D +=0D + // Find an active policy if one exists.=0D + ActivePolicy =3D GetBestPolicyMatch( VariableName, VendorGuid, NULL );=0D +=0D + // If we have an active policy, check it against the incoming data.=0D + if (ActivePolicy !=3D NULL) {=0D + //=0D + // Only enforce size and attribute constraints when updating data, not= deleting.=0D + if (!IsDel) {=0D + // Check for size constraints.=0D + if ((ActivePolicy->MinSize > 0 && DataSize < ActivePolicy->MinSize) = ||=0D + (ActivePolicy->MaxSize > 0 && DataSize > ActivePolicy->MaxSize))= {=0D + ReturnStatus =3D EFI_INVALID_PARAMETER;=0D + DEBUG(( DEBUG_VERBOSE, "%a - Bad Size. 0x%X <> 0x%X-0x%X\n", __FUN= CTION__,=0D + DataSize, ActivePolicy->MinSize, ActivePolicy->MaxSize ));= =0D + goto Exit;=0D + }=0D +=0D + // Check for attribute constraints.=0D + if ((ActivePolicy->AttributesMustHave & Attributes) !=3D ActivePolic= y->AttributesMustHave ||=0D + (ActivePolicy->AttributesCantHave & Attributes) !=3D 0) {=0D + ReturnStatus =3D EFI_INVALID_PARAMETER;=0D + DEBUG(( DEBUG_VERBOSE, "%a - Bad Attributes. 0x%X <> 0x%X:0x%X\n",= __FUNCTION__,=0D + Attributes, ActivePolicy->AttributesMustHave, ActivePolicy= ->AttributesCantHave ));=0D + goto Exit;=0D + }=0D + }=0D +=0D + //=0D + // Lock policy check.=0D + //=0D + // Check for immediate lock.=0D + if (ActivePolicy->LockPolicyType =3D=3D VARIABLE_POLICY_TYPE_LOCK_NOW)= {=0D + ReturnStatus =3D EFI_WRITE_PROTECTED;=0D + goto Exit;=0D + // Check for lock on create.=0D + } else if (ActivePolicy->LockPolicyType =3D=3D VARIABLE_POLICY_TYPE_LO= CK_ON_CREATE) {=0D + StateVarSize =3D 0;=0D + Status =3D mGetVariableHelper( VariableName,=0D + VendorGuid,=0D + NULL,=0D + &StateVarSize,=0D + NULL );=0D + if (Status =3D=3D EFI_BUFFER_TOO_SMALL) {=0D + ReturnStatus =3D EFI_WRITE_PROTECTED;=0D + goto Exit;=0D + }=0D + // Check for lock on state variable.=0D + } else if (ActivePolicy->LockPolicyType =3D=3D VARIABLE_POLICY_TYPE_LO= CK_ON_VAR_STATE) {=0D + StateVarPolicy =3D (VARIABLE_LOCK_ON_VAR_STATE_POLICY*)((UINT8*)Acti= vePolicy + sizeof(VARIABLE_POLICY_ENTRY));=0D + StateVarName =3D (CHAR16*)((UINT8*)StateVarPolicy + sizeof(VARIABLE_= LOCK_ON_VAR_STATE_POLICY));=0D + StateVarSize =3D sizeof(StateVar);=0D + Status =3D mGetVariableHelper( StateVarName,=0D + &StateVarPolicy->Namespace,=0D + NULL,=0D + &StateVarSize,=0D + &StateVar );=0D +=0D + // If the variable was found, check the state. If matched, this vari= able is locked.=0D + if (!EFI_ERROR( Status )) {=0D + if (StateVar =3D=3D StateVarPolicy->Value) {=0D + ReturnStatus =3D EFI_WRITE_PROTECTED;=0D + goto Exit;=0D + }=0D + // EFI_NOT_FOUND and EFI_BUFFER_TOO_SMALL indicate that the state do= esn't match.=0D + } else if (Status !=3D EFI_NOT_FOUND && Status !=3D EFI_BUFFER_TOO_S= MALL) {=0D + // We don't know what happened, but it isn't good.=0D + ReturnStatus =3D EFI_ABORTED;=0D + goto Exit;=0D + }=0D + }=0D + }=0D +=0D +Exit:=0D + DEBUG(( DEBUG_VERBOSE, "%a - Variable (%g:%s) returning %r.\n", __FUNCTI= ON__, VendorGuid, VariableName, ReturnStatus ));=0D + return ReturnStatus;=0D +}=0D +=0D +=0D +/**=0D + This API function disables the variable policy enforcement. If it's=0D + already been called once, will return EFI_ALREADY_STARTED.=0D +=0D + @retval EFI_SUCCESS=0D + @retval EFI_ALREADY_STARTED Has already been called once this boot= .=0D + @retval EFI_WRITE_PROTECTED Interface has been locked until reboot= .=0D + @retval EFI_WRITE_PROTECTED Interface option is disabled by platfo= rm PCD.=0D + @retval EFI_NOT_READY Library has not yet been initialized.= =0D +=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +DisableVariablePolicy (=0D + VOID=0D + )=0D +{=0D + if (!IsVariablePolicyLibInitialized()) {=0D + return EFI_NOT_READY;=0D + }=0D + if (mProtectionDisabled) {=0D + return EFI_ALREADY_STARTED;=0D + }=0D + if (mInterfaceLocked) {=0D + return EFI_WRITE_PROTECTED;=0D + }=0D + if (!PcdGetBool (PcdAllowVariablePolicyEnforcementDisable)) {=0D + return EFI_WRITE_PROTECTED;=0D + }=0D + mProtectionDisabled =3D TRUE;=0D + return EFI_SUCCESS;=0D +}=0D +=0D +=0D +/**=0D + This API function will dump the entire contents of the variable policy t= able.=0D +=0D + Similar to GetVariable, the first call can be made with a 0 size and it = will return=0D + the size of the buffer required to hold the entire table.=0D +=0D + @param[out] Policy Pointer to the policy buffer. Can be NULL if Siz= e is 0.=0D + @param[in,out] Size On input, the size of the output buffer. On outp= ut, the size=0D + of the data returned.=0D +=0D + @retval EFI_SUCCESS Policy data is in the output buffer = and Size has been updated.=0D + @retval EFI_INVALID_PARAMETER Size is NULL, or Size is non-zero an= d Policy is NULL.=0D + @retval EFI_BUFFER_TOO_SMALL Size is insufficient to hold policy.= Size updated with required size.=0D + @retval EFI_NOT_READY Library has not yet been initialized= .=0D +=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +DumpVariablePolicy (=0D + OUT UINT8 *Policy,=0D + IN OUT UINT32 *Size=0D + )=0D +{=0D + if (!IsVariablePolicyLibInitialized()) {=0D + return EFI_NOT_READY;=0D + }=0D +=0D + // Check the parameters.=0D + if (Size =3D=3D NULL || (*Size > 0 && Policy =3D=3D NULL)) {=0D + return EFI_INVALID_PARAMETER;=0D + }=0D +=0D + // Make sure the size is sufficient to hold the policy table.=0D + if (*Size < mCurrentTableUsage) {=0D + *Size =3D mCurrentTableUsage;=0D + return EFI_BUFFER_TOO_SMALL;=0D + }=0D +=0D + // If we're still here, copy the table and bounce.=0D + CopyMem( Policy, mPolicyTable, mCurrentTableUsage );=0D + *Size =3D mCurrentTableUsage;=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +=0D +/**=0D + This API function returns whether or not the policy engine is=0D + currently being enforced.=0D +=0D + @retval TRUE=0D + @retval FALSE=0D + @retval FALSE Library has not yet been initialized.=0D +=0D +**/=0D +BOOLEAN=0D +EFIAPI=0D +IsVariablePolicyEnabled (=0D + VOID=0D + )=0D +{=0D + if (!IsVariablePolicyLibInitialized()) {=0D + return FALSE;=0D + }=0D + return !mProtectionDisabled;=0D +}=0D +=0D +=0D +/**=0D + This API function locks the interface so that no more policy updates=0D + can be performed or changes made to the enforcement until the next boot.= =0D +=0D + @retval EFI_SUCCESS=0D + @retval EFI_NOT_READY Library has not yet been initialized.=0D +=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +LockVariablePolicy (=0D + VOID=0D + )=0D +{=0D + if (!IsVariablePolicyLibInitialized()) {=0D + return EFI_NOT_READY;=0D + }=0D + if (mInterfaceLocked) {=0D + return EFI_WRITE_PROTECTED;=0D + }=0D + mInterfaceLocked =3D TRUE;=0D + return EFI_SUCCESS;=0D +}=0D +=0D +=0D +/**=0D + This API function returns whether or not the policy interface is locked= =0D + for the remainder of the boot.=0D +=0D + @retval TRUE=0D + @retval FALSE=0D + @retval FALSE Library has not yet been initialized.=0D +=0D +**/=0D +BOOLEAN=0D +EFIAPI=0D +IsVariablePolicyInterfaceLocked (=0D + VOID=0D + )=0D +{=0D + if (!IsVariablePolicyLibInitialized()) {=0D + return FALSE;=0D + }=0D + return mInterfaceLocked;=0D +}=0D +=0D +=0D +/**=0D + This helper function initializes the library and sets=0D + up any required internal structures or handlers.=0D +=0D + Also registers the internal pointer for the GetVariable helper.=0D +=0D + @param[in] GetVariableHelper A function pointer matching the EFI_GET_VA= RIABLE prototype that will be used to=0D + check policy criteria that involve the existence of othe= r variables.=0D +=0D + @retval EFI_SUCCESS=0D + @retval EFI_ALREADY_STARTED The initialize function has been calle= d more than once without a call to=0D + deinitialize.=0D +=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +InitVariablePolicyLib (=0D + IN EFI_GET_VARIABLE GetVariableHelper=0D + )=0D +{=0D + EFI_STATUS Status;=0D +=0D + Status =3D EFI_SUCCESS;=0D +=0D + if (mGetVariableHelper !=3D NULL) {=0D + return EFI_ALREADY_STARTED;=0D + }=0D +=0D + if (!EFI_ERROR( Status )) {=0D + Status =3D VariablePolicyExtraInit();=0D + }=0D +=0D + if (!EFI_ERROR( Status )) {=0D + // Save an internal pointer to the GetVariableHelper.=0D + mGetVariableHelper =3D GetVariableHelper;=0D +=0D + // Initialize the global state.=0D + mInterfaceLocked =3D FALSE;=0D + mProtectionDisabled =3D FALSE;=0D + mPolicyTable =3D NULL;=0D + mCurrentTableSize =3D 0;=0D + mCurrentTableUsage =3D 0;=0D + mCurrentTableCount =3D 0;=0D + }=0D +=0D + return Status;=0D +}=0D +=0D +=0D +/**=0D + This helper function returns whether or not the library is currently ini= tialized.=0D +=0D + @retval TRUE=0D + @retval FALSE=0D +=0D +**/=0D +BOOLEAN=0D +EFIAPI=0D +IsVariablePolicyLibInitialized (=0D + VOID=0D + )=0D +{=0D + return (mGetVariableHelper !=3D NULL);=0D +}=0D +=0D +=0D +/**=0D + This helper function tears down the library.=0D +=0D + Should generally only be used for test harnesses.=0D +=0D + @retval EFI_SUCCESS=0D + @retval EFI_NOT_READY Deinitialize was called without first call= ing initialize.=0D +=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +DeinitVariablePolicyLib (=0D + VOID=0D + )=0D +{=0D + EFI_STATUS Status;=0D +=0D + Status =3D EFI_SUCCESS;=0D +=0D + if (mGetVariableHelper =3D=3D NULL) {=0D + return EFI_NOT_READY;=0D + }=0D +=0D + if (!EFI_ERROR( Status )) {=0D + Status =3D VariablePolicyExtraDeinit();=0D + }=0D +=0D + if (!EFI_ERROR( Status )) {=0D + mGetVariableHelper =3D NULL;=0D + mInterfaceLocked =3D FALSE;=0D + mProtectionDisabled =3D FALSE;=0D + mCurrentTableSize =3D 0;=0D + mCurrentTableUsage =3D 0;=0D + mCurrentTableCount =3D 0;=0D +=0D + if (mPolicyTable !=3D NULL) {=0D + FreePool( mPolicyTable );=0D + mPolicyTable =3D NULL;=0D + }=0D + }=0D +=0D + return Status;=0D +}=0D diff --git a/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyUnitTest/= VariablePolicyUnitTest.c b/MdeModulePkg/Library/VariablePolicyLib/VariableP= olicyUnitTest/VariablePolicyUnitTest.c new file mode 100644 index 000000000000..40e946a73814 --- /dev/null +++ b/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyUnitTest/Variabl= ePolicyUnitTest.c @@ -0,0 +1,2452 @@ +/** @file -- VariablePolicyUnitTest.c=0D +UnitTest for...=0D +Business logic for Variable Policy enforcement.=0D +=0D +Copyright (c) Microsoft Corporation.=0D +SPDX-License-Identifier: BSD-2-Clause-Patent=0D +=0D +**/=0D +=0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +=0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +=0D +#include =0D +=0D +#include =0D +#include =0D +=0D +#ifndef INTERNAL_UNIT_TEST=0D +#error Make sure to build thie with INTERNAL_UNIT_TEST enabled! Otherwise,= some important tests may be skipped!=0D +#endif=0D +=0D +=0D +#define UNIT_TEST_NAME "UEFI Variable Policy UnitTest"=0D +#define UNIT_TEST_VERSION "0.5"=0D +=0D +///=3D=3D=3D TEST DATA =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=0D +=0D +#pragma pack(push, 1)=0D +#define SIMPLE_VARIABLE_POLICY_ENTRY_VAR_NAME_LENGTH 1001 // 1000 char= acters + terminator.=0D +#define SIMPLE_VARIABLE_POLICY_ENTRY_VAR_NAME_SIZE (SIMPLE_VARIABLE_POL= ICY_ENTRY_VAR_NAME_LENGTH * sizeof(CHAR16))=0D +typedef struct _SIMPLE_VARIABLE_POLICY_ENTRY {=0D + VARIABLE_POLICY_ENTRY Header;=0D + CHAR16 Name[SIMPLE_VARIABLE_POLICY_ENTRY_VAR_NAME_LEN= GTH];=0D +} SIMPLE_VARIABLE_POLICY_ENTRY;=0D +#define EXPANDED_VARIABLE_POLICY_ENTRY_VAR_NAME_LENGTH 1001 // 1000 ch= aracters + terminator.=0D +#define EXPANDED_VARIABLE_POLICY_ENTRY_VAR_NAME_SIZE (EXPANDED_VARIABLE= _POLICY_ENTRY_VAR_NAME_LENGTH * sizeof(CHAR16))=0D +typedef struct _EXPANDED_VARIABLE_POLICY_ENTRY {=0D + VARIABLE_POLICY_ENTRY Header;=0D + VARIABLE_LOCK_ON_VAR_STATE_POLICY StatePolicy;=0D + CHAR16 StateName[EXPANDED_VARIABLE_POLICY_E= NTRY_VAR_NAME_LENGTH];=0D + CHAR16 Name[EXPANDED_VARIABLE_POLICY_ENTRY_= VAR_NAME_LENGTH];=0D +} EXPANDED_VARIABLE_POLICY_ENTRY;=0D +#pragma pack(pop)=0D +=0D +// {F955BA2D-4A2C-480C-BFD1-3CC522610592}=0D +#define TEST_GUID_1 { 0xf955ba2d, 0x4a2c, 0x480c, { 0xbf, 0xd1, 0x3c, 0xc5= , 0x22, 0x61, 0x5, 0x92 } }=0D +EFI_GUID mTestGuid1 =3D TEST_GUID_1;=0D +// {2DEA799E-5E73-43B9-870E-C945CE82AF3A}=0D +#define TEST_GUID_2 { 0x2dea799e, 0x5e73, 0x43b9, { 0x87, 0xe, 0xc9, 0x45,= 0xce, 0x82, 0xaf, 0x3a } }=0D +EFI_GUID mTestGuid2 =3D TEST_GUID_2;=0D +// {698A2BFD-A616-482D-B88C-7100BD6682A9}=0D +#define TEST_GUID_3 { 0x698a2bfd, 0xa616, 0x482d, { 0xb8, 0x8c, 0x71, 0x0,= 0xbd, 0x66, 0x82, 0xa9 } }=0D +EFI_GUID mTestGuid3 =3D TEST_GUID_3;=0D +=0D +#define TEST_VAR_1_NAME L"TestVar1"=0D +#define TEST_VAR_2_NAME L"TestVar2"=0D +#define TEST_VAR_3_NAME L"TestVar3"=0D +=0D +#define TEST_POLICY_ATTRIBUTES_NULL 0=0D +#define TEST_POLICY_MIN_SIZE_NULL 0=0D +#define TEST_POLICY_MAX_SIZE_NULL MAX_UINT32=0D +=0D +#define TEST_POLICY_MIN_SIZE_10 10=0D +#define TEST_POLICY_MAX_SIZE_200 200=0D +=0D +#define TEST_300_HASHES_STRING L"####################################= ##############"\=0D + "###################################= ###############"\=0D + "###################################= ###############"\=0D + "###################################= ###############"\=0D + "###################################= ###############"\=0D + "###################################= ###############"=0D +=0D +=0D +///=3D=3D=3D HELPER FUNCTIONS =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=0D +=0D +/**=0D + Helper function to initialize a VARIABLE_POLICY_ENTRY structure with a N= ame and StateName.=0D +=0D + Takes care of all the messy packing.=0D +=0D + @param[in,out] Entry=0D + @param[in] Name [Optional]=0D + @param[in] StateName [Optional]=0D +=0D + @retval TRUE=0D + @retval FALSE=0D +=0D +**/=0D +STATIC=0D +BOOLEAN=0D +InitExpVarPolicyStrings (=0D + EXPANDED_VARIABLE_POLICY_ENTRY *Entry,=0D + CHAR16 *Name, OPTIONAL=0D + CHAR16 *StateName OPTIONAL=0D + )=0D +{=0D + UINTN NameSize;=0D + UINTN StateNameSize;=0D +=0D + NameSize =3D Name =3D=3D NULL ? 0 : StrSize( Name );=0D + StateNameSize =3D StateName =3D=3D NULL ? 0 : StrSize( StateName );=0D +=0D + if (NameSize > EXPANDED_VARIABLE_POLICY_ENTRY_VAR_NAME_SIZE || NameSize = > MAX_UINT16 ||=0D + StateNameSize > EXPANDED_VARIABLE_POLICY_ENTRY_VAR_NAME_SIZE || Stat= eNameSize > MAX_UINT16) {=0D + return FALSE;=0D + }=0D +=0D + Entry->Header.OffsetToName =3D sizeof(VARIABLE_POLICY_ENTRY);=0D + if (StateName !=3D NULL) {=0D + Entry->Header.OffsetToName +=3D (UINT16)sizeof(VARIABLE_LOCK_ON_VAR_ST= ATE_POLICY) + (UINT16)StateNameSize;=0D + }=0D + Entry->Header.Size =3D Entry->Header.OffsetToName + (UINT16)NameSize;=0D +=0D + CopyMem( (UINT8*)Entry + Entry->Header.OffsetToName, Name, NameSize );=0D + if (StateName !=3D NULL) {=0D + CopyMem( (UINT8*)Entry + sizeof(VARIABLE_POLICY_ENTRY) + sizeof(VARIAB= LE_LOCK_ON_VAR_STATE_POLICY), StateName, StateNameSize );=0D + }=0D +=0D + return TRUE;=0D +}=0D +=0D +/**=0D + Mocked version of GetVariable, for testing.=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +StubGetVariableNull (=0D + IN CHAR16 *VariableName,=0D + IN EFI_GUID *VendorGuid,=0D + OUT UINT32 *Attributes, OPTIONAL=0D + IN OUT UINTN *DataSize,=0D + OUT VOID *Data OPTIONAL=0D + )=0D +{=0D + UINT32 MockedAttr;=0D + UINTN MockedDataSize;=0D + VOID *MockedData;=0D + EFI_STATUS MockedReturn;=0D +=0D + check_expected_ptr( VariableName );=0D + check_expected_ptr( VendorGuid );=0D + check_expected_ptr( DataSize );=0D +=0D + MockedAttr =3D (UINT32)mock();=0D + MockedDataSize =3D (UINTN)mock();=0D + MockedData =3D (VOID*)mock();=0D + MockedReturn =3D (EFI_STATUS)mock();=0D +=0D + if (Attributes !=3D NULL) {=0D + *Attributes =3D MockedAttr;=0D + }=0D + if (Data !=3D NULL && !EFI_ERROR(MockedReturn)) {=0D + CopyMem( Data, MockedData, MockedDataSize );=0D + }=0D +=0D + *DataSize =3D MockedDataSize;=0D +=0D + return MockedReturn;=0D +}=0D +=0D +//=0D +// Anything you think might be helpful that isn't a test itself.=0D +//=0D +=0D +/**=0D + This is a common setup function that will ensure the library is always i= nitialized=0D + with the stubbed GetVariable.=0D +=0D + Not used by all test cases, but by most.=0D +**/=0D +STATIC=0D +UNIT_TEST_STATUS=0D +EFIAPI=0D +LibInitMocked (=0D + IN UNIT_TEST_CONTEXT Context=0D + )=0D +{=0D + return EFI_ERROR(InitVariablePolicyLib( StubGetVariableNull )) ? UNIT_TE= ST_ERROR_PREREQUISITE_NOT_MET : UNIT_TEST_PASSED;=0D +}=0D +=0D +/**=0D + Common cleanup function to make sure that the library is always de-initi= alized prior=0D + to the next test case.=0D +*/=0D +STATIC=0D +VOID=0D +EFIAPI=0D +LibCleanup (=0D + IN UNIT_TEST_CONTEXT Context=0D + )=0D +{=0D + DeinitVariablePolicyLib();=0D +}=0D +=0D +=0D +///=3D=3D=3D TEST CASES =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=0D +=0D +///=3D=3D=3D=3D=3D ARCHITECTURAL SUITE =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=0D +=0D +/**=0D + Test Case=0D +*/=0D +UNIT_TEST_STATUS=0D +EFIAPI=0D +ShouldBeAbleToInitAndDeinitTheLibrary (=0D + IN UNIT_TEST_CONTEXT Context=0D + )=0D +{=0D + EFI_STATUS Status;=0D + Status =3D InitVariablePolicyLib( StubGetVariableNull );=0D + UT_ASSERT_NOT_EFI_ERROR( Status );=0D +=0D + UT_ASSERT_TRUE( IsVariablePolicyLibInitialized() );=0D +=0D + Status =3D DeinitVariablePolicyLib();=0D + UT_ASSERT_NOT_EFI_ERROR( Status );=0D +=0D + UT_ASSERT_FALSE( IsVariablePolicyLibInitialized() );=0D +=0D + return UNIT_TEST_PASSED;=0D +}=0D +=0D +/**=0D + Test Case=0D +*/=0D +UNIT_TEST_STATUS=0D +EFIAPI=0D +ShouldNotBeAbleToInitializeTheLibraryTwice (=0D + IN UNIT_TEST_CONTEXT Context=0D + )=0D +{=0D + EFI_STATUS Status;=0D + Status =3D InitVariablePolicyLib( StubGetVariableNull );=0D + UT_ASSERT_NOT_EFI_ERROR( Status );=0D + Status =3D InitVariablePolicyLib( StubGetVariableNull );=0D + UT_ASSERT_TRUE( EFI_ERROR( Status ) );=0D + return UNIT_TEST_PASSED;=0D +}=0D +=0D +/**=0D + Test Case=0D +*/=0D +UNIT_TEST_STATUS=0D +EFIAPI=0D +ShouldFailDeinitWithoutInit (=0D + IN UNIT_TEST_CONTEXT Context=0D + )=0D +{=0D + EFI_STATUS Status;=0D + Status =3D DeinitVariablePolicyLib();=0D + UT_ASSERT_TRUE( EFI_ERROR( Status ) );=0D + return UNIT_TEST_PASSED;=0D +}=0D +=0D +/**=0D + Test Case=0D +*/=0D +UNIT_TEST_STATUS=0D +EFIAPI=0D +ApiCommandsShouldNotRespondIfLibIsUninitialized (=0D + IN UNIT_TEST_CONTEXT Context=0D + )=0D +{=0D + SIMPLE_VARIABLE_POLICY_ENTRY TestPolicy =3D {=0D + {=0D + VARIABLE_POLICY_ENTRY_REVISION,=0D + sizeof(VARIABLE_POLICY_ENTRY) + sizeof(TEST_VAR_1_NAME),=0D + sizeof(VARIABLE_POLICY_ENTRY),=0D + TEST_GUID_1,=0D + TEST_POLICY_MIN_SIZE_NULL,=0D + TEST_POLICY_MAX_SIZE_NULL,=0D + TEST_POLICY_ATTRIBUTES_NULL,=0D + TEST_POLICY_ATTRIBUTES_NULL,=0D + VARIABLE_POLICY_TYPE_NO_LOCK=0D + },=0D + TEST_VAR_1_NAME=0D + };=0D + UINT8 DummyData[8];=0D + UINT32 DummyDataSize =3D sizeof(DummyData);=0D +=0D + // This test should not start with an initialized library.=0D +=0D + // Verify that all API commands fail.=0D + UT_ASSERT_TRUE( EFI_ERROR( LockVariablePolicy() ) );=0D + UT_ASSERT_TRUE( EFI_ERROR( DisableVariablePolicy() ) );=0D + UT_ASSERT_TRUE( EFI_ERROR( RegisterVariablePolicy( &TestPolicy.Header ) = ) );=0D + UT_ASSERT_TRUE( EFI_ERROR( DumpVariablePolicy( DummyData, &DummyDataSize= ) ) );=0D + UT_ASSERT_FALSE( IsVariablePolicyInterfaceLocked() );=0D + UT_ASSERT_FALSE( IsVariablePolicyEnabled() );=0D + UT_ASSERT_TRUE( EFI_ERROR( ValidateSetVariable( TEST_VAR_1_NAME,=0D + &mTestGuid1,=0D + VARIABLE_ATTRIBUTE_NV_BS,= =0D + sizeof(DummyData),=0D + DummyData ) ) );=0D +=0D + return UNIT_TEST_PASSED;=0D +}=0D +=0D +=0D +///=3D=3D=3D=3D=3D INTERNAL FUNCTION SUITE =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=0D +=0D +#ifdef INTERNAL_UNIT_TEST=0D +=0D +BOOLEAN=0D +EvaluatePolicyMatch (=0D + IN CONST VARIABLE_POLICY_ENTRY *EvalEntry,=0D + IN CONST CHAR16 *VariableName,=0D + IN CONST EFI_GUID *VendorGuid,=0D + OUT UINT8 *MatchPriority OPTIONAL=0D + );=0D +=0D +/**=0D + Test Case=0D +*/=0D +UNIT_TEST_STATUS=0D +EFIAPI=0D +PoliciesShouldMatchByNameAndGuid (=0D + IN UNIT_TEST_CONTEXT Context=0D + )=0D +{=0D + SIMPLE_VARIABLE_POLICY_ENTRY MatchCheckPolicy =3D {=0D + {=0D + VARIABLE_POLICY_ENTRY_REVISION,=0D + sizeof(VARIABLE_POLICY_ENTRY) + sizeof(TEST_VAR_1_NAME),=0D + sizeof(VARIABLE_POLICY_ENTRY),=0D + TEST_GUID_1,=0D + TEST_POLICY_MIN_SIZE_NULL,=0D + TEST_POLICY_MAX_SIZE_NULL,=0D + TEST_POLICY_ATTRIBUTES_NULL,=0D + TEST_POLICY_ATTRIBUTES_NULL,=0D + VARIABLE_POLICY_TYPE_NO_LOCK=0D + },=0D + TEST_VAR_1_NAME=0D + };=0D + CHAR16 *CheckVar1Name =3D TEST_VAR_1_NAME;=0D + CHAR16 *CheckVar2Name =3D TEST_VAR_2_NAME;=0D +=0D + // Make sure that a different name does not match.=0D + UT_ASSERT_FALSE( EvaluatePolicyMatch( &MatchCheckPolicy.Header, CheckVar= 2Name, &mTestGuid1, NULL ) );=0D +=0D + // Make sure that a different GUID does not match.=0D + UT_ASSERT_FALSE( EvaluatePolicyMatch( &MatchCheckPolicy.Header, CheckVar= 1Name, &mTestGuid2, NULL ) );=0D +=0D + // Make sure that the same name and GUID match.=0D + UT_ASSERT_TRUE( EvaluatePolicyMatch( &MatchCheckPolicy.Header, CheckVar1= Name, &mTestGuid1, NULL ) );=0D +=0D + return UNIT_TEST_PASSED;=0D +}=0D +=0D +/**=0D + Test Case=0D +*/=0D +UNIT_TEST_STATUS=0D +EFIAPI=0D +WildcardPoliciesShouldMatchDigits (=0D + IN UNIT_TEST_CONTEXT Context=0D + )=0D +{=0D + SIMPLE_VARIABLE_POLICY_ENTRY MatchCheckPolicy =3D {=0D + {=0D + VARIABLE_POLICY_ENTRY_REVISION,=0D + sizeof(VARIABLE_POLICY_ENTRY) + sizeof(L"Wildcard#VarName##"),=0D + sizeof(VARIABLE_POLICY_ENTRY),=0D + TEST_GUID_1,=0D + TEST_POLICY_MIN_SIZE_NULL,=0D + TEST_POLICY_MAX_SIZE_NULL,=0D + TEST_POLICY_ATTRIBUTES_NULL,=0D + TEST_POLICY_ATTRIBUTES_NULL,=0D + VARIABLE_POLICY_TYPE_NO_LOCK=0D + },=0D + L"Wildcard#VarName##"=0D + };=0D + CHAR16 *CheckVar1Name =3D L"Wildcard1VarName12";=0D + CHAR16 *CheckVar2Name =3D L"Wildcard2VarName34";=0D + CHAR16 *CheckVarBName =3D L"WildcardBVarName56";=0D + CHAR16 *CheckVarFName =3D L"WildcardFVarName0A";=0D + CHAR16 *CheckVarZName =3D L"WildcardZVarName56";=0D + CHAR16 *CheckVarLName =3D L"WildcardLVarName56";=0D + CHAR16 *CheckVarHName =3D L"Wildcard#VarName56";=0D +=0D + // Make sure that all hexidecimal sets of wildcard numbers match.=0D + UT_ASSERT_TRUE( EvaluatePolicyMatch( &MatchCheckPolicy.Header, CheckVar1= Name, &mTestGuid1, NULL ) );=0D + UT_ASSERT_TRUE( EvaluatePolicyMatch( &MatchCheckPolicy.Header, CheckVar2= Name, &mTestGuid1, NULL ) );=0D + UT_ASSERT_TRUE( EvaluatePolicyMatch( &MatchCheckPolicy.Header, CheckVarB= Name, &mTestGuid1, NULL ) );=0D + UT_ASSERT_TRUE( EvaluatePolicyMatch( &MatchCheckPolicy.Header, CheckVarF= Name, &mTestGuid1, NULL ) );=0D +=0D + // Make sure that the non-number charaters don't match.=0D + UT_ASSERT_FALSE( EvaluatePolicyMatch( &MatchCheckPolicy.Header, CheckVar= ZName, &mTestGuid1, NULL ) );=0D + UT_ASSERT_FALSE( EvaluatePolicyMatch( &MatchCheckPolicy.Header, CheckVar= LName, &mTestGuid1, NULL ) );=0D +=0D + // Make sure that '#' signs don't match.=0D + UT_ASSERT_FALSE( EvaluatePolicyMatch( &MatchCheckPolicy.Header, CheckVar= HName, &mTestGuid1, NULL ) );=0D +=0D + return UNIT_TEST_PASSED;=0D +}=0D +=0D +/**=0D + Test Case=0D +*/=0D +UNIT_TEST_STATUS=0D +EFIAPI=0D +WildcardPoliciesShouldMatchDigitsAdvanced (=0D + IN UNIT_TEST_CONTEXT Context=0D + )=0D +{=0D + SIMPLE_VARIABLE_POLICY_ENTRY MatchCheckPolicy =3D {=0D + {=0D + VARIABLE_POLICY_ENTRY_REVISION,=0D + sizeof(VARIABLE_POLICY_ENTRY) + sizeof(TEST_300_HASHES_STRING),=0D + sizeof(VARIABLE_POLICY_ENTRY),=0D + TEST_GUID_1,=0D + TEST_POLICY_MIN_SIZE_NULL,=0D + TEST_POLICY_MAX_SIZE_NULL,=0D + TEST_POLICY_ATTRIBUTES_NULL,=0D + TEST_POLICY_ATTRIBUTES_NULL,=0D + VARIABLE_POLICY_TYPE_NO_LOCK=0D + },=0D + TEST_300_HASHES_STRING=0D + };=0D + CHAR16 *CheckShorterString =3D L"01234567890123456789012345678901= 234567890123456789";=0D + CHAR16 *CheckValidString =3D L"0123456789012345678901234567890123= 4567890123456789"\=0D + "01234567890123456789012345678901234= 567890123456789"\=0D + "01234567890123456789012345678901234= 567890123456789"\=0D + "01234567890123456789012345678901234= 567890123456789"\=0D + "01234567890123456789012345678901234= 567890123456789"\=0D + "01234567890123456789012345678901234= 567890123456789";=0D + CHAR16 *CheckValidHexString =3D L"0123456789012345678901234567890= 12345678901234F6789"\=0D + "01234567890123456789012345678901234= 567890123456789"\=0D + "012345678901ABC56789012345678901234= 567890123456789"\=0D + "01234567890123456789012345678901234= 567890123456789"\=0D + "01234567890123456789012345678901234= 5678DEADBEEF789"\=0D + "01234ABCDEF123456789012345678901234= 567890123456789";=0D + CHAR16 *CheckLongerString =3D L"012345678901234567890123456789012= 34567890123456789"\=0D + "01234567890123456789012345678901234= 567890123456789"\=0D + "01234567890123456789012345678901234= 567890123456789"\=0D + "01234567890123456789012345678901234= 567890123456789"\=0D + "01234567890123456789012345678901234= 567890123456789"\=0D + "01234567890123456789012345678901234= 567890123456789"\=0D + "01234567890123456789012345678901234= 567890123456789";=0D + UINT8 MatchPriority;=0D +=0D + // Make sure that the shorter and the longer do not match.=0D + UT_ASSERT_FALSE( EvaluatePolicyMatch( &MatchCheckPolicy.Header, CheckSho= rterString, &mTestGuid1, NULL ) );=0D + UT_ASSERT_FALSE( EvaluatePolicyMatch( &MatchCheckPolicy.Header, CheckLon= gerString, &mTestGuid1, NULL ) );=0D +=0D + // Make sure that the valid one matches and has the expected priority.=0D + UT_ASSERT_TRUE( EvaluatePolicyMatch( &MatchCheckPolicy.Header, CheckVali= dString, &mTestGuid1, &MatchPriority ) );=0D + UT_ASSERT_TRUE( EvaluatePolicyMatch( &MatchCheckPolicy.Header, CheckVali= dHexString, &mTestGuid1, &MatchPriority ) );=0D + UT_ASSERT_EQUAL( MatchPriority, MAX_UINT8 );=0D +=0D + return UNIT_TEST_PASSED;=0D +}=0D +=0D +/**=0D + Test Case=0D +*/=0D +UNIT_TEST_STATUS=0D +EFIAPI=0D +WildcardPoliciesShouldMatchNamespaces (=0D + IN UNIT_TEST_CONTEXT Context=0D + )=0D +{=0D + VARIABLE_POLICY_ENTRY MatchCheckPolicy =3D {=0D + VARIABLE_POLICY_ENTRY_REVISION,=0D + sizeof(VARIABLE_POLICY_ENTRY),=0D + sizeof(VARIABLE_POLICY_ENTRY),=0D + TEST_GUID_1,=0D + TEST_POLICY_MIN_SIZE_NULL,=0D + TEST_POLICY_MAX_SIZE_NULL,=0D + TEST_POLICY_ATTRIBUTES_NULL,=0D + TEST_POLICY_ATTRIBUTES_NULL,=0D + VARIABLE_POLICY_TYPE_NO_LOCK=0D + };=0D + CHAR16 *CheckVar1Name =3D L"Wildcard1VarName12";=0D + CHAR16 *CheckVar2Name =3D L"Wildcard2VarName34";=0D + CHAR16 *CheckVarBName =3D L"WildcardBVarName56";=0D + CHAR16 *CheckVarHName =3D L"Wildcard#VarName56";=0D +=0D + // Make sure that all names in the same namespace match.=0D + UT_ASSERT_TRUE( EvaluatePolicyMatch( &MatchCheckPolicy, CheckVar1Name, &= mTestGuid1, NULL ) );=0D + UT_ASSERT_TRUE( EvaluatePolicyMatch( &MatchCheckPolicy, CheckVar2Name, &= mTestGuid1, NULL ) );=0D + UT_ASSERT_TRUE( EvaluatePolicyMatch( &MatchCheckPolicy, CheckVarBName, &= mTestGuid1, NULL ) );=0D + UT_ASSERT_TRUE( EvaluatePolicyMatch( &MatchCheckPolicy, CheckVarHName, &= mTestGuid1, NULL ) );=0D +=0D + // Make sure that different namespace doesn't match.=0D + UT_ASSERT_FALSE( EvaluatePolicyMatch( &MatchCheckPolicy, CheckVar1Name, = &mTestGuid2, NULL ) );=0D +=0D +=0D + return UNIT_TEST_PASSED;=0D +}=0D +=0D +/**=0D + Test Case=0D +*/=0D +UNIT_TEST_STATUS=0D +EFIAPI=0D +MatchPrioritiesShouldFollowRules (=0D + IN UNIT_TEST_CONTEXT Context=0D + )=0D +{=0D + SIMPLE_VARIABLE_POLICY_ENTRY MatchCheckPolicy =3D {=0D + {=0D + VARIABLE_POLICY_ENTRY_REVISION,=0D + sizeof(VARIABLE_POLICY_ENTRY) + sizeof(L"Wildcard1VarName12"),=0D + sizeof(VARIABLE_POLICY_ENTRY),=0D + TEST_GUID_1,=0D + TEST_POLICY_MIN_SIZE_NULL,=0D + TEST_POLICY_MAX_SIZE_NULL,=0D + TEST_POLICY_ATTRIBUTES_NULL,=0D + TEST_POLICY_ATTRIBUTES_NULL,=0D + VARIABLE_POLICY_TYPE_NO_LOCK=0D + },=0D + L"Wildcard1VarName12"=0D + };=0D + CHAR16 CheckVar1Name[] =3D L"Wildcard1VarName12";=0D + CHAR16 MatchVar1Name[] =3D L"Wildcard1VarName12";=0D + CHAR16 MatchVar2Name[] =3D L"Wildcard#VarName12";=0D + CHAR16 MatchVar3Name[] =3D L"Wildcard#VarName#2";=0D + CHAR16 MatchVar4Name[] =3D L"Wildcard#VarName##";=0D + UINT8 MatchPriority;=0D +=0D + // Check with a perfect match.=0D + CopyMem( &MatchCheckPolicy.Name, MatchVar1Name, sizeof(MatchVar1Name) );= =0D + UT_ASSERT_TRUE( EvaluatePolicyMatch( &MatchCheckPolicy.Header, CheckVar1= Name, &mTestGuid1, &MatchPriority ) );=0D + UT_ASSERT_EQUAL( MatchPriority, 0 );=0D +=0D + // Check with progressively lower priority matches.=0D + CopyMem( &MatchCheckPolicy.Name, MatchVar2Name, sizeof(MatchVar2Name) );= =0D + UT_ASSERT_TRUE( EvaluatePolicyMatch( &MatchCheckPolicy.Header, CheckVar1= Name, &mTestGuid1, &MatchPriority ) );=0D + UT_ASSERT_EQUAL( MatchPriority, 1 );=0D + CopyMem( &MatchCheckPolicy.Name, MatchVar3Name, sizeof(MatchVar3Name) );= =0D + UT_ASSERT_TRUE( EvaluatePolicyMatch( &MatchCheckPolicy.Header, CheckVar1= Name, &mTestGuid1, &MatchPriority ) );=0D + UT_ASSERT_EQUAL( MatchPriority, 2 );=0D + CopyMem( &MatchCheckPolicy.Name, MatchVar4Name, sizeof(MatchVar4Name) );= =0D + UT_ASSERT_TRUE( EvaluatePolicyMatch( &MatchCheckPolicy.Header, CheckVar1= Name, &mTestGuid1, &MatchPriority ) );=0D + UT_ASSERT_EQUAL( MatchPriority, 3 );=0D +=0D + // Check against the entire namespace.=0D + MatchCheckPolicy.Header.Size =3D sizeof(VARIABLE_POLICY_ENTRY);=0D + UT_ASSERT_TRUE( EvaluatePolicyMatch( &MatchCheckPolicy.Header, CheckVar1= Name, &mTestGuid1, &MatchPriority ) );=0D + UT_ASSERT_EQUAL( MatchPriority, MAX_UINT8 );=0D +=0D + return UNIT_TEST_PASSED;=0D +}=0D +=0D +#endif // INTERNAL_UNIT_TEST=0D +=0D +=0D +///=3D=3D=3D POLICY MANIPULATION SUITE =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=0D +=0D +/**=0D + Test Case=0D +*/=0D +UNIT_TEST_STATUS=0D +EFIAPI=0D +RegisterShouldAllowNamespaceWildcards (=0D + IN UNIT_TEST_CONTEXT Context=0D + )=0D +{=0D + SIMPLE_VARIABLE_POLICY_ENTRY ValidationPolicy =3D {=0D + {=0D + VARIABLE_POLICY_ENTRY_REVISION,=0D + sizeof(VARIABLE_POLICY_ENTRY),=0D + sizeof(VARIABLE_POLICY_ENTRY),=0D + TEST_GUID_1,=0D + TEST_POLICY_MIN_SIZE_NULL,=0D + TEST_POLICY_MAX_SIZE_NULL,=0D + TEST_POLICY_ATTRIBUTES_NULL,=0D + TEST_POLICY_ATTRIBUTES_NULL,=0D + VARIABLE_POLICY_TYPE_NO_LOCK=0D + },=0D + L""=0D + };=0D +=0D + UT_ASSERT_NOT_EFI_ERROR( RegisterVariablePolicy( &ValidationPolicy.Heade= r ) );=0D +=0D + return UNIT_TEST_PASSED;=0D +}=0D +=0D +/**=0D + Test Case=0D +*/=0D +UNIT_TEST_STATUS=0D +EFIAPI=0D +RegisterShouldAllowStateVarsForNamespaces (=0D + IN UNIT_TEST_CONTEXT Context=0D + )=0D +{=0D + EXPANDED_VARIABLE_POLICY_ENTRY ValidationPolicy =3D {=0D + {=0D + VARIABLE_POLICY_ENTRY_REVISION,=0D + 0, // Will be populated by init helper.=0D + 0, // Will be populated by init helper.=0D + TEST_GUID_1,=0D + TEST_POLICY_MIN_SIZE_NULL,=0D + TEST_POLICY_MAX_SIZE_NULL,=0D + TEST_POLICY_ATTRIBUTES_NULL,=0D + TEST_POLICY_ATTRIBUTES_NULL,=0D + VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE=0D + },=0D + {=0D + TEST_GUID_2,=0D + 1, // Value=0D + 0 // Padding=0D + },=0D + L"",=0D + L""=0D + };=0D + UT_ASSERT_TRUE( InitExpVarPolicyStrings( &ValidationPolicy, NULL, TEST_V= AR_2_NAME ) );=0D +=0D + UT_ASSERT_NOT_EFI_ERROR( RegisterVariablePolicy( &ValidationPolicy.Heade= r ) );=0D +=0D + return UNIT_TEST_PASSED;=0D +}=0D +=0D +/**=0D + Test Case=0D +*/=0D +UNIT_TEST_STATUS=0D +EFIAPI=0D +RegisterShouldRejectNullPointers (=0D + IN UNIT_TEST_CONTEXT Context=0D + )=0D +{=0D + UT_ASSERT_EQUAL( RegisterVariablePolicy( NULL ), EFI_INVALID_PARAMETER )= ;=0D + return UNIT_TEST_PASSED;=0D +}=0D +=0D +/**=0D + Test Case=0D +*/=0D +UNIT_TEST_STATUS=0D +EFIAPI=0D +RegisterShouldRejectBadRevisions (=0D + IN UNIT_TEST_CONTEXT Context=0D + )=0D +{=0D + SIMPLE_VARIABLE_POLICY_ENTRY ValidationPolicy =3D {=0D + {=0D + VARIABLE_POLICY_ENTRY_REVISION,=0D + sizeof(VARIABLE_POLICY_ENTRY) + sizeof(TEST_VAR_1_NAME),=0D + sizeof(VARIABLE_POLICY_ENTRY),=0D + TEST_GUID_1,=0D + TEST_POLICY_MIN_SIZE_NULL,=0D + TEST_POLICY_MAX_SIZE_NULL,=0D + TEST_POLICY_ATTRIBUTES_NULL,=0D + TEST_POLICY_ATTRIBUTES_NULL,=0D + VARIABLE_POLICY_TYPE_NO_LOCK=0D + },=0D + TEST_VAR_1_NAME=0D + };=0D +=0D + ValidationPolicy.Header.Version =3D MAX_UINT32;=0D + UT_ASSERT_EQUAL( RegisterVariablePolicy( &ValidationPolicy.Header ), EFI= _INVALID_PARAMETER );=0D +=0D + return UNIT_TEST_PASSED;=0D +}=0D +=0D +/**=0D + Test Case=0D +*/=0D +UNIT_TEST_STATUS=0D +EFIAPI=0D +RegisterShouldRejectBadSizes (=0D + IN UNIT_TEST_CONTEXT Context=0D + )=0D +{=0D + SIMPLE_VARIABLE_POLICY_ENTRY ValidationPolicy =3D {=0D + {=0D + VARIABLE_POLICY_ENTRY_REVISION,=0D + sizeof(VARIABLE_POLICY_ENTRY) + sizeof(TEST_VAR_1_NAME),=0D + sizeof(VARIABLE_POLICY_ENTRY),=0D + TEST_GUID_1,=0D + TEST_POLICY_MIN_SIZE_NULL,=0D + TEST_POLICY_MAX_SIZE_NULL,=0D + TEST_POLICY_ATTRIBUTES_NULL,=0D + TEST_POLICY_ATTRIBUTES_NULL,=0D + VARIABLE_POLICY_TYPE_NO_LOCK=0D + },=0D + TEST_VAR_1_NAME=0D + };=0D +=0D + ValidationPolicy.Header.Size =3D sizeof(VARIABLE_POLICY_ENTRY) - 2;=0D + UT_ASSERT_EQUAL( RegisterVariablePolicy( &ValidationPolicy.Header ), EFI= _INVALID_PARAMETER );=0D +=0D + return UNIT_TEST_PASSED;=0D +}=0D +=0D +/**=0D + Test Case=0D +*/=0D +UNIT_TEST_STATUS=0D +EFIAPI=0D +RegisterShouldRejectBadOffsets (=0D + IN UNIT_TEST_CONTEXT Context=0D + )=0D +{=0D + EXPANDED_VARIABLE_POLICY_ENTRY ValidationPolicy =3D {=0D + {=0D + VARIABLE_POLICY_ENTRY_REVISION,=0D + 0, // Will be populated by init helper.=0D + 0, // Will be populated by init helper.=0D + TEST_GUID_1,=0D + TEST_POLICY_MIN_SIZE_NULL,=0D + TEST_POLICY_MAX_SIZE_NULL,=0D + TEST_POLICY_ATTRIBUTES_NULL,=0D + TEST_POLICY_ATTRIBUTES_NULL,=0D + VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE=0D + },=0D + {=0D + TEST_GUID_2,=0D + 1, // Value=0D + 0 // Padding=0D + },=0D + L"",=0D + L""=0D + };=0D + UT_ASSERT_TRUE( InitExpVarPolicyStrings( &ValidationPolicy, TEST_VAR_1_N= AME, TEST_VAR_2_NAME ) );=0D +=0D + // Check for an offset outside the size bounds.=0D + ValidationPolicy.Header.OffsetToName =3D ValidationPolicy.Header.Size + = 1;=0D + UT_ASSERT_EQUAL( RegisterVariablePolicy( &ValidationPolicy.Header ), EFI= _INVALID_PARAMETER );=0D +=0D + // Check for an offset inside the policy header.=0D + ValidationPolicy.Header.OffsetToName =3D sizeof(VARIABLE_POLICY_ENTRY) -= 2;=0D + UT_ASSERT_EQUAL( RegisterVariablePolicy( &ValidationPolicy.Header ), EFI= _INVALID_PARAMETER );=0D +=0D + // Check for an offset inside the state policy header.=0D + ValidationPolicy.Header.OffsetToName =3D sizeof(VARIABLE_POLICY_ENTRY) += 2;=0D + UT_ASSERT_EQUAL( RegisterVariablePolicy( &ValidationPolicy.Header ), EFI= _INVALID_PARAMETER );=0D +=0D + // Check for a ridiculous offset.=0D + ValidationPolicy.Header.OffsetToName =3D MAX_UINT16;=0D + UT_ASSERT_EQUAL( RegisterVariablePolicy( &ValidationPolicy.Header ), EFI= _INVALID_PARAMETER );=0D +=0D + return UNIT_TEST_PASSED;=0D +}=0D +=0D +/**=0D + Test Case=0D +*/=0D +UNIT_TEST_STATUS=0D +EFIAPI=0D +RegisterShouldRejectMissingStateStrings (=0D + IN UNIT_TEST_CONTEXT Context=0D + )=0D +{=0D + EXPANDED_VARIABLE_POLICY_ENTRY ValidationPolicy =3D {=0D + {=0D + VARIABLE_POLICY_ENTRY_REVISION,=0D + 0, // Will be populated by init helper.=0D + 0, // Will be populated by init helper.=0D + TEST_GUID_1,=0D + TEST_POLICY_MIN_SIZE_NULL,=0D + TEST_POLICY_MAX_SIZE_NULL,=0D + TEST_POLICY_ATTRIBUTES_NULL,=0D + TEST_POLICY_ATTRIBUTES_NULL,=0D + VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE=0D + },=0D + {=0D + TEST_GUID_2,=0D + 1, // Value=0D + 0 // Padding=0D + },=0D + L"",=0D + L""=0D + };=0D + UT_ASSERT_TRUE( InitExpVarPolicyStrings( &ValidationPolicy, TEST_VAR_1_N= AME, TEST_VAR_2_NAME ) );=0D +=0D + // Remove the state string and copy the Name into it's place.=0D + // Also adjust the offset.=0D + ValidationPolicy.Header.Size =3D sizeof(VARIABLE_POLICY_ENTRY) = + sizeof(VARIABLE_LOCK_ON_VAR_STATE_POLICY) + sizeof(TEST_VAR_1_NAME);=0D + ValidationPolicy.Header.OffsetToName =3D sizeof(VARIABLE_POLICY_ENTRY) = + sizeof(VARIABLE_LOCK_ON_VAR_STATE_POLICY);=0D + CopyMem( (UINT8*)&ValidationPolicy + ValidationPolicy.Header.OffsetToNam= e, TEST_VAR_1_NAME, sizeof(TEST_VAR_1_NAME) );=0D +=0D + // Make sure that this structure fails.=0D + UT_ASSERT_EQUAL( RegisterVariablePolicy( &ValidationPolicy.Header ), EFI= _INVALID_PARAMETER );=0D +=0D + return UNIT_TEST_PASSED;=0D +}=0D +=0D +/**=0D + Test Case=0D +*/=0D +UNIT_TEST_STATUS=0D +EFIAPI=0D +RegisterShouldRejectStringsMissingNull (=0D + IN UNIT_TEST_CONTEXT Context=0D + )=0D +{=0D + EXPANDED_VARIABLE_POLICY_ENTRY ValidationPolicy =3D {=0D + {=0D + VARIABLE_POLICY_ENTRY_REVISION,=0D + 0, // Will be populated by init helper.=0D + 0, // Will be populated by init helper.=0D + TEST_GUID_1,=0D + TEST_POLICY_MIN_SIZE_NULL,=0D + TEST_POLICY_MAX_SIZE_NULL,=0D + TEST_POLICY_ATTRIBUTES_NULL,=0D + TEST_POLICY_ATTRIBUTES_NULL,=0D + VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE=0D + },=0D + {=0D + TEST_GUID_2,=0D + 1, // Value=0D + 0 // Padding=0D + },=0D + L"",=0D + L""=0D + };=0D + UT_ASSERT_TRUE( InitExpVarPolicyStrings( &ValidationPolicy, TEST_VAR_1_N= AME, TEST_VAR_2_NAME ) );=0D +=0D + // Removing the NULL from the Name should fail.=0D + ValidationPolicy.Header.Size =3D ValidationPolicy.Header.Size - sizeof(C= HAR16);=0D + UT_ASSERT_EQUAL( RegisterVariablePolicy( &ValidationPolicy.Header ), EFI= _INVALID_PARAMETER );=0D +=0D + // Removing the NULL from the State Name is a little trickier.=0D + // Copy the Name up one byte.=0D + ValidationPolicy.Header.OffsetToName =3D ValidationPolicy.Header.OffsetT= oName - sizeof(CHAR16);=0D + CopyMem( (UINT8*)&ValidationPolicy + ValidationPolicy.Header.OffsetToNam= e, TEST_VAR_1_NAME, sizeof(TEST_VAR_1_NAME) );=0D + UT_ASSERT_EQUAL( RegisterVariablePolicy( &ValidationPolicy.Header ), EFI= _INVALID_PARAMETER );=0D +=0D + return UNIT_TEST_PASSED;=0D +}=0D +=0D +/**=0D + Test Case=0D +*/=0D +UNIT_TEST_STATUS=0D +EFIAPI=0D +RegisterShouldRejectMalformedStrings (=0D + IN UNIT_TEST_CONTEXT Context=0D + )=0D +{=0D + EXPANDED_VARIABLE_POLICY_ENTRY ValidationPolicy =3D {=0D + {=0D + VARIABLE_POLICY_ENTRY_REVISION,=0D + 0, // Will be populated by init helper.=0D + 0, // Will be populated by init helper.=0D + TEST_GUID_1,=0D + TEST_POLICY_MIN_SIZE_NULL,=0D + TEST_POLICY_MAX_SIZE_NULL,=0D + TEST_POLICY_ATTRIBUTES_NULL,=0D + TEST_POLICY_ATTRIBUTES_NULL,=0D + VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE=0D + },=0D + {=0D + TEST_GUID_2,=0D + 1, // Value=0D + 0 // Padding=0D + },=0D + L"",=0D + L""=0D + };=0D + UT_ASSERT_TRUE( InitExpVarPolicyStrings( &ValidationPolicy, TEST_VAR_1_N= AME, TEST_VAR_2_NAME ) );=0D +=0D + // Bisecting the NULL from the Name should fail.=0D + ValidationPolicy.Header.Size =3D ValidationPolicy.Header.Size - 1;=0D + UT_ASSERT_EQUAL( RegisterVariablePolicy( &ValidationPolicy.Header ), EFI= _INVALID_PARAMETER );=0D +=0D + // Bisecting the NULL from the State Name is a little trickier.=0D + // Copy the Name up one byte.=0D + ValidationPolicy.Header.OffsetToName =3D ValidationPolicy.Header.OffsetT= oName - 1;=0D + CopyMem( (UINT8*)&ValidationPolicy + ValidationPolicy.Header.OffsetToNam= e, TEST_VAR_1_NAME, sizeof(TEST_VAR_1_NAME) );=0D + UT_ASSERT_EQUAL( RegisterVariablePolicy( &ValidationPolicy.Header ), EFI= _INVALID_PARAMETER );=0D +=0D + return UNIT_TEST_PASSED;=0D +}=0D +=0D +/**=0D + Test Case=0D +*/=0D +UNIT_TEST_STATUS=0D +EFIAPI=0D +RegisterShouldRejectUnpackedPolicies (=0D + IN UNIT_TEST_CONTEXT Context=0D + )=0D +{=0D + EXPANDED_VARIABLE_POLICY_ENTRY ValidationPolicy =3D {=0D + {=0D + VARIABLE_POLICY_ENTRY_REVISION,=0D + 0, // Will be populated by init helper.=0D + 0, // Will be populated by init helper.=0D + TEST_GUID_1,=0D + TEST_POLICY_MIN_SIZE_NULL,=0D + TEST_POLICY_MAX_SIZE_NULL,=0D + TEST_POLICY_ATTRIBUTES_NULL,=0D + TEST_POLICY_ATTRIBUTES_NULL,=0D + VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE=0D + },=0D + {=0D + TEST_GUID_2,=0D + 1, // Value=0D + 0 // Padding=0D + },=0D + L"",=0D + L""=0D + };=0D + UT_ASSERT_TRUE( InitExpVarPolicyStrings( &ValidationPolicy, TEST_VAR_1_N= AME, TEST_VAR_2_NAME ) );=0D +=0D + // Increase the size and move the Name out a bit.=0D + ValidationPolicy.Header.Size =3D ValidationPolicy.Header.Size + sizeof(C= HAR16);=0D + ValidationPolicy.Header.OffsetToName =3D ValidationPolicy.Header.OffsetT= oName + sizeof(CHAR16);=0D + CopyMem( (UINT8*)&ValidationPolicy + ValidationPolicy.Header.OffsetToNam= e, TEST_VAR_1_NAME, sizeof(TEST_VAR_1_NAME) );=0D + UT_ASSERT_EQUAL( RegisterVariablePolicy( &ValidationPolicy.Header ), EFI= _INVALID_PARAMETER );=0D +=0D + // Reintialize without the state policy and try the same test.=0D + ValidationPolicy.Header.LockPolicyType =3D VARIABLE_POLICY_TYPE_NO_LOCK;= =0D + UT_ASSERT_TRUE( InitExpVarPolicyStrings( &ValidationPolicy, TEST_VAR_1_N= AME, NULL ) );=0D + ValidationPolicy.Header.Size =3D ValidationPolicy.Header.Size + sizeof(C= HAR16);=0D + ValidationPolicy.Header.OffsetToName =3D ValidationPolicy.Header.OffsetT= oName + sizeof(CHAR16);=0D + CopyMem( (UINT8*)&ValidationPolicy + ValidationPolicy.Header.OffsetToNam= e, TEST_VAR_1_NAME, sizeof(TEST_VAR_1_NAME) );=0D + UT_ASSERT_EQUAL( RegisterVariablePolicy( &ValidationPolicy.Header ), EFI= _INVALID_PARAMETER );=0D +=0D + return UNIT_TEST_PASSED;=0D +}=0D +=0D +/**=0D + Test Case=0D +*/=0D +UNIT_TEST_STATUS=0D +EFIAPI=0D +RegisterShouldRejectInvalidNameCharacters (=0D + IN UNIT_TEST_CONTEXT Context=0D + )=0D +{=0D + // EXPANDED_VARIABLE_POLICY_ENTRY ValidationPolicy =3D {=0D + // {=0D + // VARIABLE_POLICY_ENTRY_REVISION,=0D + // 0, // Will be populated by init helper.=0D + // 0, // Will be populated by init helper.=0D + // TEST_GUID_1,=0D + // TEST_POLICY_MIN_SIZE_NULL,=0D + // TEST_POLICY_MAX_SIZE_NULL,=0D + // TEST_POLICY_ATTRIBUTES_NULL,=0D + // TEST_POLICY_ATTRIBUTES_NULL,=0D + // VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE=0D + // },=0D + // {=0D + // TEST_GUID_2,=0D + // 1, // Value=0D + // 0 // Padding=0D + // },=0D + // L"",=0D + // L""=0D + // };=0D +=0D + // Currently, there are no known invalid characters.=0D + // '#' in LockPolicy->Name are taken as literal.=0D +=0D + return UNIT_TEST_PASSED;=0D +}=0D +=0D +/**=0D + Test Case=0D +*/=0D +UNIT_TEST_STATUS=0D +EFIAPI=0D +RegisterShouldRejectBadPolicyConstraints (=0D + IN UNIT_TEST_CONTEXT Context=0D + )=0D +{=0D + SIMPLE_VARIABLE_POLICY_ENTRY ValidationPolicy =3D {=0D + {=0D + VARIABLE_POLICY_ENTRY_REVISION,=0D + sizeof(VARIABLE_POLICY_ENTRY) + sizeof(TEST_VAR_1_NAME),=0D + sizeof(VARIABLE_POLICY_ENTRY),=0D + TEST_GUID_1,=0D + TEST_POLICY_MIN_SIZE_NULL,=0D + TEST_POLICY_MAX_SIZE_NULL,=0D + TEST_POLICY_ATTRIBUTES_NULL,=0D + TEST_POLICY_ATTRIBUTES_NULL,=0D + VARIABLE_POLICY_TYPE_NO_LOCK=0D + },=0D + TEST_VAR_1_NAME=0D + };=0D +=0D + // Make sure that invalid MAXes are rejected.=0D + ValidationPolicy.Header.MaxSize =3D 0;=0D + UT_ASSERT_EQUAL( RegisterVariablePolicy( &ValidationPolicy.Header ), EFI= _INVALID_PARAMETER );=0D +=0D + return UNIT_TEST_PASSED;=0D +}=0D +=0D +/**=0D + Test Case=0D +*/=0D +UNIT_TEST_STATUS=0D +EFIAPI=0D +RegisterShouldRejectUnknownLockPolicies (=0D + IN UNIT_TEST_CONTEXT Context=0D + )=0D +{=0D + SIMPLE_VARIABLE_POLICY_ENTRY ValidationPolicy =3D {=0D + {=0D + VARIABLE_POLICY_ENTRY_REVISION,=0D + sizeof(VARIABLE_POLICY_ENTRY) + sizeof(TEST_VAR_1_NAME),=0D + sizeof(VARIABLE_POLICY_ENTRY),=0D + TEST_GUID_1,=0D + TEST_POLICY_MIN_SIZE_NULL,=0D + TEST_POLICY_MAX_SIZE_NULL,=0D + TEST_POLICY_ATTRIBUTES_NULL,=0D + TEST_POLICY_ATTRIBUTES_NULL,=0D + VARIABLE_POLICY_TYPE_NO_LOCK=0D + },=0D + TEST_VAR_1_NAME=0D + };=0D +=0D + ValidationPolicy.Header.LockPolicyType =3D VARIABLE_POLICY_TYPE_LOCK_ON_= VAR_STATE + 1;=0D + UT_ASSERT_EQUAL( RegisterVariablePolicy( &ValidationPolicy.Header ), EFI= _INVALID_PARAMETER );=0D + ValidationPolicy.Header.LockPolicyType =3D VARIABLE_POLICY_TYPE_LOCK_ON_= VAR_STATE + 1;=0D + UT_ASSERT_EQUAL( RegisterVariablePolicy( &ValidationPolicy.Header ), EFI= _INVALID_PARAMETER );=0D +=0D + return UNIT_TEST_PASSED;=0D +}=0D +=0D +/**=0D + Test Case=0D +*/=0D +UNIT_TEST_STATUS=0D +EFIAPI=0D +RegisterShouldRejectPolicesWithTooManyWildcards (=0D + IN UNIT_TEST_CONTEXT Context=0D + )=0D +{=0D + SIMPLE_VARIABLE_POLICY_ENTRY ValidationPolicy =3D {=0D + {=0D + VARIABLE_POLICY_ENTRY_REVISION,=0D + sizeof(VARIABLE_POLICY_ENTRY) + sizeof(TEST_300_HASHES_STRING),=0D + sizeof(VARIABLE_POLICY_ENTRY),=0D + TEST_GUID_1,=0D + TEST_POLICY_MIN_SIZE_NULL,=0D + TEST_POLICY_MAX_SIZE_NULL,=0D + TEST_POLICY_ATTRIBUTES_NULL,=0D + TEST_POLICY_ATTRIBUTES_NULL,=0D + VARIABLE_POLICY_TYPE_NO_LOCK=0D + },=0D + TEST_300_HASHES_STRING=0D + };=0D +=0D + // 300 Hashes is currently larger than the possible maximum match priori= ty.=0D + UT_ASSERT_EQUAL( RegisterVariablePolicy( &ValidationPolicy.Header ), EFI= _INVALID_PARAMETER );=0D +=0D + return UNIT_TEST_PASSED;=0D +}=0D +=0D +/**=0D + Test Case=0D +*/=0D +UNIT_TEST_STATUS=0D +EFIAPI=0D +RegisterShouldRejectDuplicatePolicies (=0D + IN UNIT_TEST_CONTEXT Context=0D + )=0D +{=0D + SIMPLE_VARIABLE_POLICY_ENTRY ValidationPolicy =3D {=0D + {=0D + VARIABLE_POLICY_ENTRY_REVISION,=0D + sizeof(VARIABLE_POLICY_ENTRY) + sizeof(TEST_VAR_1_NAME),=0D + sizeof(VARIABLE_POLICY_ENTRY),=0D + TEST_GUID_1,=0D + TEST_POLICY_MIN_SIZE_NULL,=0D + TEST_POLICY_MAX_SIZE_NULL,=0D + TEST_POLICY_ATTRIBUTES_NULL,=0D + TEST_POLICY_ATTRIBUTES_NULL,=0D + VARIABLE_POLICY_TYPE_NO_LOCK=0D + },=0D + TEST_VAR_1_NAME=0D + };=0D +=0D + UT_ASSERT_NOT_EFI_ERROR( RegisterVariablePolicy( &ValidationPolicy.Heade= r ) );=0D + UT_ASSERT_STATUS_EQUAL( RegisterVariablePolicy( &ValidationPolicy.Header= ), EFI_ALREADY_STARTED );=0D +=0D + return UNIT_TEST_PASSED;=0D +}=0D +=0D +/**=0D + Test Case=0D +*/=0D +UNIT_TEST_STATUS=0D +EFIAPI=0D +MinAndMaxSizePoliciesShouldBeHonored (=0D + IN UNIT_TEST_CONTEXT Context=0D + )=0D +{=0D + SIMPLE_VARIABLE_POLICY_ENTRY ValidationPolicy =3D {=0D + {=0D + VARIABLE_POLICY_ENTRY_REVISION,=0D + sizeof(VARIABLE_POLICY_ENTRY) + sizeof(TEST_VAR_1_NAME),=0D + sizeof(VARIABLE_POLICY_ENTRY),=0D + TEST_GUID_1,=0D + TEST_POLICY_MIN_SIZE_10,=0D + TEST_POLICY_MAX_SIZE_200,=0D + TEST_POLICY_ATTRIBUTES_NULL,=0D + TEST_POLICY_ATTRIBUTES_NULL,=0D + VARIABLE_POLICY_TYPE_NO_LOCK=0D + },=0D + TEST_VAR_1_NAME=0D + };=0D + EFI_STATUS PolicyCheck;=0D + UINT8 DummyData[TEST_POLICY_MAX_SIZE_200+1];=0D +=0D +=0D + // Without a policy, there should be no constraints on variable creation= .=0D + PolicyCheck =3D ValidateSetVariable( TEST_VAR_1_NAME,=0D + &mTestGuid1,=0D + VARIABLE_ATTRIBUTE_NV_BS,=0D + TEST_POLICY_MAX_SIZE_200+1,=0D + DummyData );=0D + UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );=0D +=0D + // Set a policy to test against.=0D + UT_ASSERT_NOT_EFI_ERROR( RegisterVariablePolicy( &ValidationPolicy.Heade= r ) );=0D +=0D + // With a policy, make sure that sizes outsize the target range fail.=0D + PolicyCheck =3D ValidateSetVariable( TEST_VAR_1_NAME,=0D + &mTestGuid1,=0D + VARIABLE_ATTRIBUTE_NV_BS,=0D + TEST_POLICY_MAX_SIZE_200+1,=0D + DummyData );=0D + UT_ASSERT_TRUE( EFI_ERROR( PolicyCheck ) );=0D +=0D + // With a policy, make sure that sizes outsize the target range fail.=0D + PolicyCheck =3D ValidateSetVariable( TEST_VAR_1_NAME,=0D + &mTestGuid1,=0D + VARIABLE_ATTRIBUTE_NV_BS,=0D + TEST_POLICY_MIN_SIZE_10-1,=0D + DummyData );=0D + UT_ASSERT_TRUE( EFI_ERROR( PolicyCheck ) );=0D +=0D + // With a policy, make sure a valid variable is still valid.=0D + PolicyCheck =3D ValidateSetVariable( TEST_VAR_1_NAME,=0D + &mTestGuid1,=0D + VARIABLE_ATTRIBUTE_NV_BS,=0D + TEST_POLICY_MIN_SIZE_10+1,=0D + DummyData );=0D + UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );=0D +=0D + return UNIT_TEST_PASSED;=0D +}=0D +=0D +/**=0D + Test Case=0D +*/=0D +UNIT_TEST_STATUS=0D +EFIAPI=0D +AttributeMustPoliciesShouldBeHonored (=0D + IN UNIT_TEST_CONTEXT Context=0D + )=0D +{=0D + SIMPLE_VARIABLE_POLICY_ENTRY ValidationPolicy =3D {=0D + {=0D + VARIABLE_POLICY_ENTRY_REVISION,=0D + sizeof(VARIABLE_POLICY_ENTRY) + sizeof(TEST_VAR_1_NAME),=0D + sizeof(VARIABLE_POLICY_ENTRY),=0D + TEST_GUID_1,=0D + TEST_POLICY_MIN_SIZE_NULL,=0D + TEST_POLICY_MAX_SIZE_NULL,=0D + VARIABLE_ATTRIBUTE_NV_BS_RT,=0D + TEST_POLICY_ATTRIBUTES_NULL,=0D + VARIABLE_POLICY_TYPE_NO_LOCK=0D + },=0D + TEST_VAR_1_NAME=0D + };=0D + EFI_STATUS PolicyCheck;=0D + UINT8 DummyData[12];=0D +=0D +=0D + // Without a policy, there should be no constraints on variable creation= .=0D + PolicyCheck =3D ValidateSetVariable( TEST_VAR_1_NAME,=0D + &mTestGuid1,=0D + TEST_POLICY_ATTRIBUTES_NULL,=0D + sizeof(DummyData),=0D + DummyData );=0D + UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );=0D +=0D + // Set a policy to test against.=0D + UT_ASSERT_NOT_EFI_ERROR( RegisterVariablePolicy( &ValidationPolicy.Heade= r ) );=0D +=0D + // With a policy, make sure that no attributes fail.=0D + PolicyCheck =3D ValidateSetVariable( TEST_VAR_1_NAME,=0D + &mTestGuid1,=0D + TEST_POLICY_ATTRIBUTES_NULL,=0D + sizeof(DummyData),=0D + DummyData );=0D + UT_ASSERT_TRUE( EFI_ERROR( PolicyCheck ) );=0D +=0D + // With a policy, make sure that some -- but not all -- attributes fail.= =0D + PolicyCheck =3D ValidateSetVariable( TEST_VAR_1_NAME,=0D + &mTestGuid1,=0D + VARIABLE_ATTRIBUTE_BS_RT_AT,=0D + sizeof(DummyData),=0D + DummyData );=0D + UT_ASSERT_TRUE( EFI_ERROR( PolicyCheck ) );=0D +=0D + // With a policy, make sure that all attributes pass.=0D + PolicyCheck =3D ValidateSetVariable( TEST_VAR_1_NAME,=0D + &mTestGuid1,=0D + VARIABLE_ATTRIBUTE_NV_BS_RT,=0D + sizeof(DummyData),=0D + DummyData );=0D + UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );=0D +=0D + // With a policy, make sure that all attributes -- plus some -- pass.=0D + PolicyCheck =3D ValidateSetVariable( TEST_VAR_1_NAME,=0D + &mTestGuid1,=0D + VARIABLE_ATTRIBUTE_NV_BS_RT_AT,=0D + sizeof(DummyData),=0D + DummyData );=0D + UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );=0D +=0D + return UNIT_TEST_PASSED;=0D +}=0D +=0D +/**=0D + Test Case=0D +*/=0D +UNIT_TEST_STATUS=0D +EFIAPI=0D +AttributeCantPoliciesShouldBeHonored (=0D + IN UNIT_TEST_CONTEXT Context=0D + )=0D +{=0D + SIMPLE_VARIABLE_POLICY_ENTRY ValidationPolicy =3D {=0D + {=0D + VARIABLE_POLICY_ENTRY_REVISION,=0D + sizeof(VARIABLE_POLICY_ENTRY) + sizeof(TEST_VAR_1_NAME),=0D + sizeof(VARIABLE_POLICY_ENTRY),=0D + TEST_GUID_1,=0D + TEST_POLICY_MIN_SIZE_NULL,=0D + TEST_POLICY_MAX_SIZE_NULL,=0D + TEST_POLICY_ATTRIBUTES_NULL,=0D + EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS,=0D + VARIABLE_POLICY_TYPE_NO_LOCK=0D + },=0D + TEST_VAR_1_NAME=0D + };=0D + EFI_STATUS PolicyCheck;=0D + UINT8 DummyData[12];=0D +=0D +=0D + // Without a policy, there should be no constraints on variable creation= .=0D + PolicyCheck =3D ValidateSetVariable( TEST_VAR_1_NAME,=0D + &mTestGuid1,=0D + VARIABLE_ATTRIBUTE_BS_RT_AT,=0D + sizeof(DummyData),=0D + DummyData );=0D + UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );=0D +=0D + // Set a policy to test against.=0D + UT_ASSERT_NOT_EFI_ERROR( RegisterVariablePolicy( &ValidationPolicy.Heade= r ) );=0D +=0D + // With a policy, make sure that forbidden attributes fail.=0D + PolicyCheck =3D ValidateSetVariable( TEST_VAR_1_NAME,=0D + &mTestGuid1,=0D + EFI_VARIABLE_TIME_BASED_AUTHENTICATED_= WRITE_ACCESS,=0D + sizeof(DummyData),=0D + DummyData );=0D + UT_ASSERT_TRUE( EFI_ERROR( PolicyCheck ) );=0D +=0D + // With a policy, make sure that a mixture of attributes -- including th= e forbidden -- fail.=0D + PolicyCheck =3D ValidateSetVariable( TEST_VAR_1_NAME,=0D + &mTestGuid1,=0D + VARIABLE_ATTRIBUTE_BS_RT_AT,=0D + sizeof(DummyData),=0D + DummyData );=0D + UT_ASSERT_TRUE( EFI_ERROR( PolicyCheck ) );=0D +=0D + // With a policy, make sure that attributes without the forbidden pass.= =0D + PolicyCheck =3D ValidateSetVariable( TEST_VAR_1_NAME,=0D + &mTestGuid1,=0D + VARIABLE_ATTRIBUTE_NV_BS_RT,=0D + sizeof(DummyData),=0D + DummyData );=0D + UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );=0D +=0D + return UNIT_TEST_PASSED;=0D +}=0D +=0D +/**=0D + Test Case=0D +*/=0D +UNIT_TEST_STATUS=0D +EFIAPI=0D +VariablesShouldBeDeletableRegardlessOfSize (=0D + IN UNIT_TEST_CONTEXT Context=0D + )=0D +{=0D + SIMPLE_VARIABLE_POLICY_ENTRY ValidationPolicy =3D {=0D + {=0D + VARIABLE_POLICY_ENTRY_REVISION,=0D + sizeof(VARIABLE_POLICY_ENTRY) + sizeof(TEST_VAR_1_NAME),=0D + sizeof(VARIABLE_POLICY_ENTRY),=0D + TEST_GUID_1,=0D + TEST_POLICY_MIN_SIZE_10,=0D + TEST_POLICY_MAX_SIZE_NULL,=0D + TEST_POLICY_ATTRIBUTES_NULL,=0D + EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS,=0D + VARIABLE_POLICY_TYPE_NO_LOCK=0D + },=0D + TEST_VAR_1_NAME=0D + };=0D + EFI_STATUS PolicyCheck;=0D + UINT8 DummyData[TEST_POLICY_MAX_SIZE_200+1];=0D +=0D + // Create a policy enforcing a minimum variable size.=0D + UT_ASSERT_NOT_EFI_ERROR( RegisterVariablePolicy( &ValidationPolicy.Heade= r ) );=0D +=0D + // Make sure that a normal set would fail.=0D + PolicyCheck =3D ValidateSetVariable( TEST_VAR_1_NAME,=0D + &mTestGuid1,=0D + VARIABLE_ATTRIBUTE_NV_BS,=0D + TEST_POLICY_MIN_SIZE_10-1,=0D + DummyData );=0D + UT_ASSERT_STATUS_EQUAL( PolicyCheck, EFI_INVALID_PARAMETER );=0D +=0D + // Now make sure that a delete would succeed.=0D + PolicyCheck =3D ValidateSetVariable( TEST_VAR_1_NAME,=0D + &mTestGuid1,=0D + VARIABLE_ATTRIBUTE_NV_BS,=0D + 0,=0D + NULL );=0D + UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );=0D +=0D + return UNIT_TEST_PASSED;=0D +}=0D +=0D +/**=0D + Test Case=0D +*/=0D +UNIT_TEST_STATUS=0D +EFIAPI=0D +LockNowPoliciesShouldBeHonored (=0D + IN UNIT_TEST_CONTEXT Context=0D + )=0D +{=0D + SIMPLE_VARIABLE_POLICY_ENTRY ValidationPolicy =3D {=0D + {=0D + VARIABLE_POLICY_ENTRY_REVISION,=0D + sizeof(VARIABLE_POLICY_ENTRY) + sizeof(TEST_VAR_1_NAME),=0D + sizeof(VARIABLE_POLICY_ENTRY),=0D + TEST_GUID_1,=0D + TEST_POLICY_MIN_SIZE_NULL,=0D + TEST_POLICY_MAX_SIZE_NULL,=0D + TEST_POLICY_ATTRIBUTES_NULL,=0D + TEST_POLICY_ATTRIBUTES_NULL,=0D + VARIABLE_POLICY_TYPE_LOCK_NOW=0D + },=0D + TEST_VAR_1_NAME=0D + };=0D + EFI_STATUS PolicyCheck;=0D + UINT8 DummyData[12];=0D +=0D +=0D + // Without a policy, there should be no constraints on variable creation= .=0D + PolicyCheck =3D ValidateSetVariable( TEST_VAR_1_NAME,=0D + &mTestGuid1,=0D + VARIABLE_ATTRIBUTE_BS_RT_AT,=0D + sizeof(DummyData),=0D + DummyData );=0D + UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );=0D +=0D + // Set a policy to test against.=0D + UT_ASSERT_NOT_EFI_ERROR( RegisterVariablePolicy( &ValidationPolicy.Heade= r ) );=0D +=0D + // With a policy, make sure that writes immediately fail.=0D + PolicyCheck =3D ValidateSetVariable( TEST_VAR_1_NAME,=0D + &mTestGuid1,=0D + VARIABLE_ATTRIBUTE_BS_RT_AT,=0D + sizeof(DummyData),=0D + DummyData );=0D + UT_ASSERT_TRUE( EFI_ERROR( PolicyCheck ) );=0D +=0D + return UNIT_TEST_PASSED;=0D +}=0D +=0D +/**=0D + Test Case=0D +*/=0D +UNIT_TEST_STATUS=0D +EFIAPI=0D +LockOnCreatePoliciesShouldBeHonored (=0D + IN UNIT_TEST_CONTEXT Context=0D + )=0D +{=0D + SIMPLE_VARIABLE_POLICY_ENTRY ValidationPolicy =3D {=0D + {=0D + VARIABLE_POLICY_ENTRY_REVISION,=0D + sizeof(VARIABLE_POLICY_ENTRY) + sizeof(TEST_VAR_1_NAME),=0D + sizeof(VARIABLE_POLICY_ENTRY),=0D + TEST_GUID_1,=0D + TEST_POLICY_MIN_SIZE_NULL,=0D + TEST_POLICY_MAX_SIZE_NULL,=0D + TEST_POLICY_ATTRIBUTES_NULL,=0D + TEST_POLICY_ATTRIBUTES_NULL,=0D + VARIABLE_POLICY_TYPE_LOCK_ON_CREATE=0D + },=0D + TEST_VAR_1_NAME=0D + };=0D + EFI_STATUS PolicyCheck;=0D + UINT8 DummyData[12];=0D + UINTN ExpectedDataSize;=0D +=0D +=0D + // Without a policy, there should be no constraints on variable creation= .=0D + PolicyCheck =3D ValidateSetVariable( TEST_VAR_1_NAME,=0D + &mTestGuid1,=0D + VARIABLE_ATTRIBUTE_BS_RT_AT,=0D + sizeof(DummyData),=0D + DummyData );=0D + UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );=0D +=0D + // Set a policy to test against.=0D + UT_ASSERT_NOT_EFI_ERROR( RegisterVariablePolicy( &ValidationPolicy.Heade= r ) );=0D +=0D + // Set consistent expectations on what the calls are looking for.=0D + expect_memory_count( StubGetVariableNull, VariableName, TEST_VAR_1_NAME,= sizeof(TEST_VAR_1_NAME), 2 );=0D + expect_memory_count( StubGetVariableNull, VendorGuid, &mTestGuid1, sizeo= f(mTestGuid1), 2 );=0D + ExpectedDataSize =3D 0;=0D + expect_memory_count( StubGetVariableNull, DataSize, &ExpectedDataSize, s= izeof(ExpectedDataSize), 2 );=0D +=0D + // With a policy, make sure that writes still work, since the variable d= oesn't exist.=0D + will_return( StubGetVariableNull, TEST_POLICY_ATTRIBUTES_NULL ); // A= ttributes=0D + will_return( StubGetVariableNull, 0 ); // S= ize=0D + will_return( StubGetVariableNull, NULL ); // D= ataPtr=0D + will_return( StubGetVariableNull, EFI_NOT_FOUND ); // S= tatus=0D + PolicyCheck =3D ValidateSetVariable( TEST_VAR_1_NAME,=0D + &mTestGuid1,=0D + VARIABLE_ATTRIBUTE_BS_RT_AT,=0D + sizeof(DummyData),=0D + DummyData );=0D + UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );=0D +=0D + // With a policy, make sure that a call with an "existing" variable fail= s.=0D + will_return( StubGetVariableNull, TEST_POLICY_ATTRIBUTES_NULL ); // A= ttributes=0D + will_return( StubGetVariableNull, 10 ); // S= ize=0D + will_return( StubGetVariableNull, NULL ); // D= ataPtr=0D + will_return( StubGetVariableNull, EFI_BUFFER_TOO_SMALL ); // S= tatus=0D + PolicyCheck =3D ValidateSetVariable( TEST_VAR_1_NAME,=0D + &mTestGuid1,=0D + VARIABLE_ATTRIBUTE_BS_RT_AT,=0D + sizeof(DummyData),=0D + DummyData );=0D + UT_ASSERT_TRUE( EFI_ERROR( PolicyCheck ) );=0D +=0D + return UNIT_TEST_PASSED;=0D +}=0D +=0D +/**=0D + Test Case=0D +*/=0D +UNIT_TEST_STATUS=0D +EFIAPI=0D +LockOnStatePoliciesShouldBeHonored (=0D + IN UNIT_TEST_CONTEXT Context=0D + )=0D +{=0D + EXPANDED_VARIABLE_POLICY_ENTRY ValidationPolicy =3D {=0D + {=0D + VARIABLE_POLICY_ENTRY_REVISION,=0D + 0, // Will be populated by init helper.=0D + 0, // Will be populated by init helper.=0D + TEST_GUID_1,=0D + TEST_POLICY_MIN_SIZE_NULL,=0D + TEST_POLICY_MAX_SIZE_NULL,=0D + TEST_POLICY_ATTRIBUTES_NULL,=0D + TEST_POLICY_ATTRIBUTES_NULL,=0D + VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE=0D + },=0D + {=0D + TEST_GUID_2,=0D + 20, // Value=0D + 0 // Padding=0D + },=0D + L"",=0D + L""=0D + };=0D + EFI_STATUS PolicyCheck;=0D + UINT8 DummyData[12];=0D + UINT8 ValidationStateVar;=0D + UINTN ExpectedDataSize;=0D + UT_ASSERT_TRUE( InitExpVarPolicyStrings( &ValidationPolicy, TEST_VAR_1_N= AME, TEST_VAR_2_NAME ) );=0D +=0D +=0D + // Without a policy, there should be no constraints on variable creation= .=0D + PolicyCheck =3D ValidateSetVariable( TEST_VAR_1_NAME,=0D + &mTestGuid1,=0D + VARIABLE_ATTRIBUTE_BS_RT_AT,=0D + sizeof(DummyData),=0D + DummyData );=0D + UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );=0D +=0D + // Set a policy to test against.=0D + UT_ASSERT_NOT_EFI_ERROR( RegisterVariablePolicy( &ValidationPolicy.Heade= r ) );=0D +=0D + // Set consistent expectations on what the calls are looking for.=0D + expect_memory_count( StubGetVariableNull, VariableName, TEST_VAR_2_NAME,= sizeof(TEST_VAR_2_NAME), 5 );=0D + expect_memory_count( StubGetVariableNull, VendorGuid, &mTestGuid2, sizeo= f(mTestGuid2), 5 );=0D + ExpectedDataSize =3D 1;=0D + expect_memory_count( StubGetVariableNull, DataSize, &ExpectedDataSize, s= izeof(ExpectedDataSize), 5 );=0D +=0D + // With a policy, make sure that writes still work, since the variable d= oesn't exist.=0D + will_return( StubGetVariableNull, TEST_POLICY_ATTRIBUTES_NULL ); // A= ttributes=0D + will_return( StubGetVariableNull, 0 ); // S= ize=0D + will_return( StubGetVariableNull, NULL ); // D= ataPtr=0D + will_return( StubGetVariableNull, EFI_NOT_FOUND ); // S= tatus=0D + PolicyCheck =3D ValidateSetVariable( TEST_VAR_1_NAME,=0D + &mTestGuid1,=0D + VARIABLE_ATTRIBUTE_BS_RT_AT,=0D + sizeof(DummyData),=0D + DummyData );=0D + UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );=0D +=0D + // With a policy, make sure that a state variable that's too large doesn= 't lock the variable.=0D + will_return( StubGetVariableNull, TEST_POLICY_ATTRIBUTES_NULL ); // A= ttributes=0D + will_return( StubGetVariableNull, 10 ); // S= ize=0D + will_return( StubGetVariableNull, NULL ); // D= ataPtr=0D + will_return( StubGetVariableNull, EFI_BUFFER_TOO_SMALL ); // S= tatus=0D + PolicyCheck =3D ValidateSetVariable( TEST_VAR_1_NAME,=0D + &mTestGuid1,=0D + VARIABLE_ATTRIBUTE_BS_RT_AT,=0D + sizeof(DummyData),=0D + DummyData );=0D + UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );=0D +=0D + // With a policy, check a state variable with the wrong value.=0D + ValidationStateVar =3D 0;=0D + will_return( StubGetVariableNull, TEST_POLICY_ATTRIBUTES_NULL ); // A= ttributes=0D + will_return( StubGetVariableNull, sizeof(ValidationStateVar) ); // S= ize=0D + will_return( StubGetVariableNull, &ValidationStateVar ); // D= ataPtr=0D + will_return( StubGetVariableNull, EFI_SUCCESS ); // S= tatus=0D + PolicyCheck =3D ValidateSetVariable( TEST_VAR_1_NAME,=0D + &mTestGuid1,=0D + VARIABLE_ATTRIBUTE_BS_RT_AT,=0D + sizeof(DummyData),=0D + DummyData );=0D + UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );=0D +=0D + // With a policy, check a state variable with another wrong value.=0D + ValidationStateVar =3D 10;=0D + will_return( StubGetVariableNull, TEST_POLICY_ATTRIBUTES_NULL ); // A= ttributes=0D + will_return( StubGetVariableNull, sizeof(ValidationStateVar) ); // S= ize=0D + will_return( StubGetVariableNull, &ValidationStateVar ); // D= ataPtr=0D + will_return( StubGetVariableNull, EFI_SUCCESS ); // S= tatus=0D + PolicyCheck =3D ValidateSetVariable( TEST_VAR_1_NAME,=0D + &mTestGuid1,=0D + VARIABLE_ATTRIBUTE_BS_RT_AT,=0D + sizeof(DummyData),=0D + DummyData );=0D + UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );=0D +=0D + // With a policy, make sure that a call with a correct state variable fa= ils.=0D + ValidationStateVar =3D 20;=0D + will_return( StubGetVariableNull, TEST_POLICY_ATTRIBUTES_NULL ); // A= ttributes=0D + will_return( StubGetVariableNull, sizeof(ValidationStateVar) ); // S= ize=0D + will_return( StubGetVariableNull, &ValidationStateVar ); // D= ataPtr=0D + will_return( StubGetVariableNull, EFI_SUCCESS ); // S= tatus=0D + PolicyCheck =3D ValidateSetVariable( TEST_VAR_1_NAME,=0D + &mTestGuid1,=0D + VARIABLE_ATTRIBUTE_BS_RT_AT,=0D + sizeof(DummyData),=0D + DummyData );=0D + UT_ASSERT_TRUE( EFI_ERROR( PolicyCheck ) );=0D +=0D + return UNIT_TEST_PASSED;=0D +}=0D +=0D +/**=0D + Test Case=0D +*/=0D +UNIT_TEST_STATUS=0D +EFIAPI=0D +LockOnStatePoliciesShouldApplyToNamespaces (=0D + IN UNIT_TEST_CONTEXT Context=0D + )=0D +{=0D + EXPANDED_VARIABLE_POLICY_ENTRY ValidationPolicy =3D {=0D + {=0D + VARIABLE_POLICY_ENTRY_REVISION,=0D + 0, // Will be populated by init helper.=0D + 0, // Will be populated by init helper.=0D + TEST_GUID_1,=0D + TEST_POLICY_MIN_SIZE_NULL,=0D + TEST_POLICY_MAX_SIZE_NULL,=0D + TEST_POLICY_ATTRIBUTES_NULL,=0D + TEST_POLICY_ATTRIBUTES_NULL,=0D + VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE=0D + },=0D + {=0D + TEST_GUID_2,=0D + 20, // Value=0D + 0 // Padding=0D + },=0D + L"",=0D + L""=0D + };=0D + EFI_STATUS PolicyCheck;=0D + UINT8 DummyData[12];=0D + UINT8 ValidationStateVar;=0D + UINTN ExpectedDataSize;=0D + UT_ASSERT_TRUE( InitExpVarPolicyStrings( &ValidationPolicy, NULL, TEST_V= AR_2_NAME ) );=0D +=0D +=0D + // Without a policy, there should be no constraints on variable creation= .=0D + PolicyCheck =3D ValidateSetVariable( TEST_VAR_1_NAME,=0D + &mTestGuid1,=0D + VARIABLE_ATTRIBUTE_BS_RT_AT,=0D + sizeof(DummyData),=0D + DummyData );=0D + UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );=0D + PolicyCheck =3D ValidateSetVariable( TEST_VAR_3_NAME,=0D + &mTestGuid1,=0D + VARIABLE_ATTRIBUTE_BS_RT_AT,=0D + sizeof(DummyData),=0D + DummyData );=0D + UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );=0D +=0D + // Set a policy to test against.=0D + UT_ASSERT_NOT_EFI_ERROR( RegisterVariablePolicy( &ValidationPolicy.Heade= r ) );=0D +=0D + // Set consistent expectations on what the calls are looking for.=0D + expect_memory_count( StubGetVariableNull, VariableName, TEST_VAR_2_NAME,= sizeof(TEST_VAR_2_NAME), 4 );=0D + expect_memory_count( StubGetVariableNull, VendorGuid, &mTestGuid2, sizeo= f(mTestGuid2), 4 );=0D + ExpectedDataSize =3D 1;=0D + expect_memory_count( StubGetVariableNull, DataSize, &ExpectedDataSize, s= izeof(ExpectedDataSize), 4 );=0D +=0D + // With a policy, make sure that writes still work, since the variable d= oesn't exist.=0D + will_return( StubGetVariableNull, TEST_POLICY_ATTRIBUTES_NULL ); // A= ttributes=0D + will_return( StubGetVariableNull, 0 ); // S= ize=0D + will_return( StubGetVariableNull, NULL ); // D= ataPtr=0D + will_return( StubGetVariableNull, EFI_NOT_FOUND ); // S= tatus=0D + PolicyCheck =3D ValidateSetVariable( TEST_VAR_1_NAME,=0D + &mTestGuid1,=0D + VARIABLE_ATTRIBUTE_BS_RT_AT,=0D + sizeof(DummyData),=0D + DummyData );=0D + UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );=0D + will_return( StubGetVariableNull, TEST_POLICY_ATTRIBUTES_NULL ); // A= ttributes=0D + will_return( StubGetVariableNull, 0 ); // S= ize=0D + will_return( StubGetVariableNull, NULL ); // D= ataPtr=0D + will_return( StubGetVariableNull, EFI_NOT_FOUND ); // S= tatus=0D + PolicyCheck =3D ValidateSetVariable( TEST_VAR_3_NAME,=0D + &mTestGuid1,=0D + VARIABLE_ATTRIBUTE_BS_RT_AT,=0D + sizeof(DummyData),=0D + DummyData );=0D + UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );=0D +=0D + // With a policy, make sure that a call with a correct state variable fa= ils.=0D + ValidationStateVar =3D 20;=0D + will_return( StubGetVariableNull, TEST_POLICY_ATTRIBUTES_NULL ); // A= ttributes=0D + will_return( StubGetVariableNull, sizeof(ValidationStateVar) ); // S= ize=0D + will_return( StubGetVariableNull, &ValidationStateVar ); // D= ataPtr=0D + will_return( StubGetVariableNull, EFI_SUCCESS ); // S= tatus=0D + PolicyCheck =3D ValidateSetVariable( TEST_VAR_1_NAME,=0D + &mTestGuid1,=0D + VARIABLE_ATTRIBUTE_BS_RT_AT,=0D + sizeof(DummyData),=0D + DummyData );=0D + UT_ASSERT_TRUE( EFI_ERROR( PolicyCheck ) );=0D + will_return( StubGetVariableNull, TEST_POLICY_ATTRIBUTES_NULL ); // A= ttributes=0D + will_return( StubGetVariableNull, sizeof(ValidationStateVar) ); // S= ize=0D + will_return( StubGetVariableNull, &ValidationStateVar ); // D= ataPtr=0D + will_return( StubGetVariableNull, EFI_SUCCESS ); // S= tatus=0D + PolicyCheck =3D ValidateSetVariable( TEST_VAR_3_NAME,=0D + &mTestGuid1,=0D + VARIABLE_ATTRIBUTE_BS_RT_AT,=0D + sizeof(DummyData),=0D + DummyData );=0D + UT_ASSERT_TRUE( EFI_ERROR( PolicyCheck ) );=0D +=0D + return UNIT_TEST_PASSED;=0D +}=0D +=0D +/**=0D + Test Case=0D +*/=0D +UNIT_TEST_STATUS=0D +EFIAPI=0D +LockOnStateShouldHandleErrorsGracefully (=0D + IN UNIT_TEST_CONTEXT Context=0D + )=0D +{=0D + EXPANDED_VARIABLE_POLICY_ENTRY ValidationPolicy =3D {=0D + {=0D + VARIABLE_POLICY_ENTRY_REVISION,=0D + 0, // Will be populated by init helper.=0D + 0, // Will be populated by init helper.=0D + TEST_GUID_1,=0D + TEST_POLICY_MIN_SIZE_NULL,=0D + TEST_POLICY_MAX_SIZE_NULL,=0D + TEST_POLICY_ATTRIBUTES_NULL,=0D + TEST_POLICY_ATTRIBUTES_NULL,=0D + VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE=0D + },=0D + {=0D + TEST_GUID_2,=0D + 20, // Value=0D + 0 // Padding=0D + },=0D + L"",=0D + L""=0D + };=0D + EFI_STATUS PolicyCheck;=0D + UINT8 DummyData[12];=0D + UT_ASSERT_TRUE( InitExpVarPolicyStrings( &ValidationPolicy, TEST_VAR_1_N= AME, TEST_VAR_2_NAME ) );=0D +=0D +=0D + // Without a policy, there should be no constraints on variable creation= .=0D + PolicyCheck =3D ValidateSetVariable( TEST_VAR_1_NAME,=0D + &mTestGuid1,=0D + VARIABLE_ATTRIBUTE_BS_RT_AT,=0D + sizeof(DummyData),=0D + DummyData );=0D + UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );=0D +=0D + // Set a policy to test against.=0D + UT_ASSERT_NOT_EFI_ERROR( RegisterVariablePolicy( &ValidationPolicy.Heade= r ) );=0D +=0D + // Configure the stub to not care about parameters. We're testing errors= .=0D + expect_any_always( StubGetVariableNull, VariableName );=0D + expect_any_always( StubGetVariableNull, VendorGuid );=0D + expect_any_always( StubGetVariableNull, DataSize );=0D +=0D + // With a policy, make sure that writes still work, since the variable d= oesn't exist.=0D + will_return( StubGetVariableNull, TEST_POLICY_ATTRIBUTES_NULL ); // A= ttributes=0D + will_return( StubGetVariableNull, 0 ); // S= ize=0D + will_return( StubGetVariableNull, NULL ); // D= ataPtr=0D + will_return( StubGetVariableNull, EFI_NOT_FOUND ); // S= tatus=0D + PolicyCheck =3D ValidateSetVariable( TEST_VAR_1_NAME,=0D + &mTestGuid1,=0D + VARIABLE_ATTRIBUTE_BS_RT_AT,=0D + sizeof(DummyData),=0D + DummyData );=0D + UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );=0D +=0D + // Verify that state variables that are the wrong size won't lock the va= riable.=0D + will_return( StubGetVariableNull, TEST_POLICY_ATTRIBUTES_NULL ); // A= ttributes=0D + will_return( StubGetVariableNull, 0 ); // S= ize=0D + will_return( StubGetVariableNull, NULL ); // D= ataPtr=0D + will_return( StubGetVariableNull, EFI_BUFFER_TOO_SMALL ); // S= tatus=0D + PolicyCheck =3D ValidateSetVariable( TEST_VAR_1_NAME,=0D + &mTestGuid1,=0D + VARIABLE_ATTRIBUTE_BS_RT_AT,=0D + sizeof(DummyData),=0D + DummyData );=0D + UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );=0D +=0D + // Verify that unexpected errors default to locked.=0D + will_return( StubGetVariableNull, TEST_POLICY_ATTRIBUTES_NULL ); // A= ttributes=0D + will_return( StubGetVariableNull, 0 ); // S= ize=0D + will_return( StubGetVariableNull, NULL ); // D= ataPtr=0D + will_return( StubGetVariableNull, EFI_UNSUPPORTED ); // S= tatus=0D + PolicyCheck =3D ValidateSetVariable( TEST_VAR_1_NAME,=0D + &mTestGuid1,=0D + VARIABLE_ATTRIBUTE_BS_RT_AT,=0D + sizeof(DummyData),=0D + DummyData );=0D + UT_ASSERT_TRUE( EFI_ERROR( PolicyCheck ) );=0D +=0D + will_return( StubGetVariableNull, TEST_POLICY_ATTRIBUTES_NULL ); // A= ttributes=0D + will_return( StubGetVariableNull, 0 ); // S= ize=0D + will_return( StubGetVariableNull, NULL ); // D= ataPtr=0D + will_return( StubGetVariableNull, EFI_NOT_READY ); // S= tatus=0D + PolicyCheck =3D ValidateSetVariable( TEST_VAR_1_NAME,=0D + &mTestGuid1,=0D + VARIABLE_ATTRIBUTE_BS_RT_AT,=0D + sizeof(DummyData),=0D + DummyData );=0D + UT_ASSERT_TRUE( EFI_ERROR( PolicyCheck ) );=0D +=0D + return UNIT_TEST_PASSED;=0D +}=0D +=0D +/**=0D + Test Case=0D +*/=0D +UNIT_TEST_STATUS=0D +EFIAPI=0D +BestMatchPriorityShouldBeObeyed (=0D + IN UNIT_TEST_CONTEXT Context=0D + )=0D +{=0D + SIMPLE_VARIABLE_POLICY_ENTRY ValidationPolicy =3D {=0D + {=0D + VARIABLE_POLICY_ENTRY_REVISION,=0D + sizeof(VARIABLE_POLICY_ENTRY) + sizeof(L"Wild12Card34Placeholder"),= =0D + sizeof(VARIABLE_POLICY_ENTRY),=0D + TEST_GUID_1,=0D + TEST_POLICY_MIN_SIZE_NULL,=0D + TEST_POLICY_MAX_SIZE_NULL,=0D + TEST_POLICY_ATTRIBUTES_NULL,=0D + TEST_POLICY_ATTRIBUTES_NULL,=0D + VARIABLE_POLICY_TYPE_NO_LOCK=0D + },=0D + L"Wild12Card34Placeholder"=0D + };=0D + EFI_STATUS PolicyCheck;=0D + UINT8 DummyData[70];=0D + CHAR16 *PolicyName =3D (CHAR16*)((UINT8*)&ValidationPolicy + sizeof= (VARIABLE_POLICY_ENTRY));=0D + UINTN PolicyNameSize =3D sizeof(L"Wild12Card34Placeholder");=0D + CHAR16 *FourWildcards =3D L"Wild##Card##Placeholder";=0D + CHAR16 *ThreeWildcards =3D L"Wild##Card#4Placeholder";=0D + CHAR16 *TwoWildcards =3D L"Wild##Card34Placeholder";=0D + CHAR16 *OneWildcard =3D L"Wild#2Card34Placeholder";=0D + CHAR16 *NoWildcards =3D L"Wild12Card34Placeholder";=0D +=0D + // Create all of the policies from least restrictive to most restrictive= .=0D + // NoWildcards should be the most restrictive.=0D + ValidationPolicy.Header.MaxSize =3D 60;=0D + ValidationPolicy.Header.Size =3D ValidationPolicy.Header.OffsetToName;=0D + UT_ASSERT_NOT_EFI_ERROR( RegisterVariablePolicy( &ValidationPolicy.Heade= r ) );=0D + ValidationPolicy.Header.Size +=3D (UINT16)PolicyNameSize;=0D + ValidationPolicy.Header.MaxSize =3D 50;=0D + CopyMem( PolicyName, FourWildcards, PolicyNameSize );=0D + UT_ASSERT_NOT_EFI_ERROR( RegisterVariablePolicy( &ValidationPolicy.Heade= r ) );=0D + ValidationPolicy.Header.MaxSize =3D 40;=0D + CopyMem( PolicyName, ThreeWildcards, PolicyNameSize );=0D + UT_ASSERT_NOT_EFI_ERROR( RegisterVariablePolicy( &ValidationPolicy.Heade= r ) );=0D + ValidationPolicy.Header.MaxSize =3D 30;=0D + CopyMem( PolicyName, TwoWildcards, PolicyNameSize );=0D + UT_ASSERT_NOT_EFI_ERROR( RegisterVariablePolicy( &ValidationPolicy.Heade= r ) );=0D + ValidationPolicy.Header.MaxSize =3D 20;=0D + CopyMem( PolicyName, OneWildcard, PolicyNameSize );=0D + UT_ASSERT_NOT_EFI_ERROR( RegisterVariablePolicy( &ValidationPolicy.Heade= r ) );=0D + ValidationPolicy.Header.MaxSize =3D 10;=0D + CopyMem( PolicyName, NoWildcards, PolicyNameSize );=0D + UT_ASSERT_NOT_EFI_ERROR( RegisterVariablePolicy( &ValidationPolicy.Heade= r ) );=0D +=0D + // Verify that variables only matching the namespace have the most flexi= ble policy.=0D + PolicyCheck =3D ValidateSetVariable( L"ArbitraryName",=0D + &mTestGuid1,=0D + VARIABLE_ATTRIBUTE_BS_RT_AT,=0D + 65,=0D + DummyData );=0D + UT_ASSERT_TRUE( EFI_ERROR( PolicyCheck ) );=0D + PolicyCheck =3D ValidateSetVariable( L"ArbitraryName",=0D + &mTestGuid1,=0D + VARIABLE_ATTRIBUTE_BS_RT_AT,=0D + 55,=0D + DummyData );=0D + UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );=0D +=0D + // Verify that variables matching increasing characters get increasing p= olicy restrictions.=0D + PolicyCheck =3D ValidateSetVariable( L"Wild77Card77Placeholder",=0D + &mTestGuid1,=0D + VARIABLE_ATTRIBUTE_BS_RT_AT,=0D + 55,=0D + DummyData );=0D + UT_ASSERT_TRUE( EFI_ERROR( PolicyCheck ) );=0D + PolicyCheck =3D ValidateSetVariable( L"Wild77Card77Placeholder",=0D + &mTestGuid1,=0D + VARIABLE_ATTRIBUTE_BS_RT_AT,=0D + 45,=0D + DummyData );=0D + UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );=0D +=0D + PolicyCheck =3D ValidateSetVariable( L"Wild77Card74Placeholder",=0D + &mTestGuid1,=0D + VARIABLE_ATTRIBUTE_BS_RT_AT,=0D + 45,=0D + DummyData );=0D + UT_ASSERT_TRUE( EFI_ERROR( PolicyCheck ) );=0D + PolicyCheck =3D ValidateSetVariable( L"Wild77Card74Placeholder",=0D + &mTestGuid1,=0D + VARIABLE_ATTRIBUTE_BS_RT_AT,=0D + 35,=0D + DummyData );=0D + UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );=0D +=0D + PolicyCheck =3D ValidateSetVariable( L"Wild77Card34Placeholder",=0D + &mTestGuid1,=0D + VARIABLE_ATTRIBUTE_BS_RT_AT,=0D + 35,=0D + DummyData );=0D + UT_ASSERT_TRUE( EFI_ERROR( PolicyCheck ) );=0D + PolicyCheck =3D ValidateSetVariable( L"Wild77Card34Placeholder",=0D + &mTestGuid1,=0D + VARIABLE_ATTRIBUTE_BS_RT_AT,=0D + 25,=0D + DummyData );=0D + UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );=0D +=0D + PolicyCheck =3D ValidateSetVariable( L"Wild72Card34Placeholder",=0D + &mTestGuid1,=0D + VARIABLE_ATTRIBUTE_BS_RT_AT,=0D + 25,=0D + DummyData );=0D + UT_ASSERT_TRUE( EFI_ERROR( PolicyCheck ) );=0D + PolicyCheck =3D ValidateSetVariable( L"Wild72Card34Placeholder",=0D + &mTestGuid1,=0D + VARIABLE_ATTRIBUTE_BS_RT_AT,=0D + 15,=0D + DummyData );=0D + UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );=0D +=0D + PolicyCheck =3D ValidateSetVariable( L"Wild12Card34Placeholder",=0D + &mTestGuid1,=0D + VARIABLE_ATTRIBUTE_BS_RT_AT,=0D + 15,=0D + DummyData );=0D + UT_ASSERT_TRUE( EFI_ERROR( PolicyCheck ) );=0D + PolicyCheck =3D ValidateSetVariable( L"Wild12Card34Placeholder",=0D + &mTestGuid1,=0D + VARIABLE_ATTRIBUTE_BS_RT_AT,=0D + 5,=0D + DummyData );=0D + UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );=0D +=0D + return UNIT_TEST_PASSED;=0D +}=0D +=0D +=0D +///=3D=3D=3D POLICY UTILITY SUITE =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=0D +=0D +/**=0D + Test Case=0D +*/=0D +UNIT_TEST_STATUS=0D +EFIAPI=0D +ShouldBeAbleToLockInterface (=0D + IN UNIT_TEST_CONTEXT Context=0D + )=0D +{=0D + SIMPLE_VARIABLE_POLICY_ENTRY TestPolicy =3D {=0D + {=0D + VARIABLE_POLICY_ENTRY_REVISION,=0D + sizeof(VARIABLE_POLICY_ENTRY) + sizeof(TEST_VAR_1_NAME),=0D + sizeof(VARIABLE_POLICY_ENTRY),=0D + TEST_GUID_1,=0D + TEST_POLICY_MIN_SIZE_NULL,=0D + TEST_POLICY_MAX_SIZE_NULL,=0D + TEST_POLICY_ATTRIBUTES_NULL,=0D + TEST_POLICY_ATTRIBUTES_NULL,=0D + VARIABLE_POLICY_TYPE_NO_LOCK=0D + },=0D + TEST_VAR_1_NAME=0D + };=0D +=0D + // Make sure it's not already locked.=0D + UT_ASSERT_FALSE( IsVariablePolicyInterfaceLocked() );=0D + // Lock it.=0D + UT_ASSERT_NOT_EFI_ERROR( LockVariablePolicy() );=0D + // Verify that it's locked.=0D + UT_ASSERT_TRUE( IsVariablePolicyInterfaceLocked() );=0D +=0D + // Verify that all state-changing commands fail.=0D + UT_ASSERT_TRUE( EFI_ERROR( LockVariablePolicy() ) );=0D + UT_ASSERT_TRUE( EFI_ERROR( DisableVariablePolicy() ) );=0D + UT_ASSERT_TRUE( EFI_ERROR( RegisterVariablePolicy( &TestPolicy.Header ) = ) );=0D +=0D + return UNIT_TEST_PASSED;=0D +}=0D +=0D +/**=0D + Test Case=0D +*/=0D +UNIT_TEST_STATUS=0D +EFIAPI=0D +ShouldBeAbleToDisablePolicyEnforcement (=0D + IN UNIT_TEST_CONTEXT Context=0D + )=0D +{=0D + SIMPLE_VARIABLE_POLICY_ENTRY TestPolicy =3D {=0D + {=0D + VARIABLE_POLICY_ENTRY_REVISION,=0D + sizeof(VARIABLE_POLICY_ENTRY) + sizeof(TEST_VAR_1_NAME),=0D + sizeof(VARIABLE_POLICY_ENTRY),=0D + TEST_GUID_1,=0D + TEST_POLICY_MIN_SIZE_10,=0D + TEST_POLICY_MAX_SIZE_200,=0D + TEST_POLICY_ATTRIBUTES_NULL,=0D + TEST_POLICY_ATTRIBUTES_NULL,=0D + VARIABLE_POLICY_TYPE_NO_LOCK=0D + },=0D + TEST_VAR_1_NAME=0D + };=0D + EFI_STATUS PolicyCheck;=0D + UINT8 DummyData[TEST_POLICY_MIN_SIZE_10-1];=0D +=0D + // Make sure that the policy enforcement is currently enabled.=0D + UT_ASSERT_TRUE( IsVariablePolicyEnabled() );=0D + // Add a policy before it's disabled.=0D + UT_ASSERT_NOT_EFI_ERROR( RegisterVariablePolicy( &TestPolicy.Header ) );= =0D + // Disable the policy enforcement.=0D + UT_ASSERT_NOT_EFI_ERROR( DisableVariablePolicy() );=0D + // Make sure that the policy enforcement is currently disabled.=0D + UT_ASSERT_FALSE( IsVariablePolicyEnabled() );=0D +=0D + // Check to make sure that a policy violation still passes.=0D + PolicyCheck =3D ValidateSetVariable( TEST_VAR_1_NAME,=0D + &mTestGuid1,=0D + VARIABLE_ATTRIBUTE_NV_BS,=0D + sizeof(DummyData),=0D + DummyData );=0D + UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );=0D +=0D + return UNIT_TEST_PASSED;=0D +}=0D +=0D +/**=0D + Test Case=0D +*/=0D +UNIT_TEST_STATUS=0D +EFIAPI=0D +ShouldNotBeAbleToDisablePoliciesTwice (=0D + IN UNIT_TEST_CONTEXT Context=0D + )=0D +{=0D + // Make sure that the policy enforcement is currently enabled.=0D + UT_ASSERT_TRUE( IsVariablePolicyEnabled() );=0D + // Disable the policy enforcement.=0D + UT_ASSERT_NOT_EFI_ERROR( DisableVariablePolicy() );=0D + // Make sure that the policy enforcement is currently disabled.=0D + UT_ASSERT_FALSE( IsVariablePolicyEnabled() );=0D + // Try to disable again and verify failure.=0D + UT_ASSERT_TRUE( EFI_ERROR( DisableVariablePolicy() ) );=0D +=0D + return UNIT_TEST_PASSED;=0D +}=0D +=0D +/**=0D + Test Case=0D +*/=0D +UNIT_TEST_STATUS=0D +EFIAPI=0D +ShouldBeAbleToAddNewPoliciesAfterDisabled (=0D + IN UNIT_TEST_CONTEXT Context=0D + )=0D +{=0D + SIMPLE_VARIABLE_POLICY_ENTRY TestPolicy =3D {=0D + {=0D + VARIABLE_POLICY_ENTRY_REVISION,=0D + sizeof(VARIABLE_POLICY_ENTRY) + sizeof(TEST_VAR_1_NAME),=0D + sizeof(VARIABLE_POLICY_ENTRY),=0D + TEST_GUID_1,=0D + TEST_POLICY_MIN_SIZE_10,=0D + TEST_POLICY_MAX_SIZE_200,=0D + TEST_POLICY_ATTRIBUTES_NULL,=0D + TEST_POLICY_ATTRIBUTES_NULL,=0D + VARIABLE_POLICY_TYPE_NO_LOCK=0D + },=0D + TEST_VAR_1_NAME=0D + };=0D + EFI_STATUS PolicyCheck;=0D +=0D + // Make sure that the policy enforcement is currently enabled.=0D + UT_ASSERT_TRUE( IsVariablePolicyEnabled() );=0D + // Disable the policy enforcement.=0D + UT_ASSERT_NOT_EFI_ERROR( DisableVariablePolicy() );=0D +=0D + // Make sure that new policy creation still works, it just won't be enfo= rced.=0D + PolicyCheck =3D RegisterVariablePolicy( &TestPolicy.Header );=0D + UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );=0D +=0D + return UNIT_TEST_PASSED;=0D +}=0D +=0D +/**=0D + Test Case=0D +*/=0D +UNIT_TEST_STATUS=0D +EFIAPI=0D +ShouldBeAbleToLockAfterDisabled (=0D + IN UNIT_TEST_CONTEXT Context=0D + )=0D +{=0D + // Make sure that the policy enforcement is currently enabled.=0D + UT_ASSERT_TRUE( IsVariablePolicyEnabled() );=0D + // Disable the policy enforcement.=0D + UT_ASSERT_NOT_EFI_ERROR( DisableVariablePolicy() );=0D +=0D + // Make sure that we can lock in this state.=0D + UT_ASSERT_FALSE( IsVariablePolicyInterfaceLocked() );=0D + UT_ASSERT_NOT_EFI_ERROR( LockVariablePolicy() );=0D + UT_ASSERT_TRUE( IsVariablePolicyInterfaceLocked() );=0D +=0D + return UNIT_TEST_PASSED;=0D +}=0D +=0D +/**=0D + Test Case=0D +*/=0D +UNIT_TEST_STATUS=0D +EFIAPI=0D +ShouldBeAbleToDumpThePolicyTable (=0D + IN UNIT_TEST_CONTEXT Context=0D + )=0D +{=0D + SIMPLE_VARIABLE_POLICY_ENTRY TestPolicy =3D {=0D + {=0D + VARIABLE_POLICY_ENTRY_REVISION,=0D + sizeof(VARIABLE_POLICY_ENTRY) + sizeof(TEST_VAR_1_NAME),=0D + sizeof(VARIABLE_POLICY_ENTRY),=0D + TEST_GUID_1,=0D + TEST_POLICY_MIN_SIZE_10,=0D + TEST_POLICY_MAX_SIZE_200,=0D + TEST_POLICY_ATTRIBUTES_NULL,=0D + TEST_POLICY_ATTRIBUTES_NULL,=0D + VARIABLE_POLICY_TYPE_NO_LOCK=0D + },=0D + TEST_VAR_1_NAME=0D + };=0D + EFI_STATUS PolicyCheck;=0D + UINT32 DumpSize;=0D + UINT32 BufferSize;=0D + VOID *DumpBuffer;=0D +=0D + // For good measure, test some parameter validation.=0D + UT_ASSERT_STATUS_EQUAL( DumpVariablePolicy( NULL, NULL ), EFI_INVALID_PA= RAMETER );=0D + DumpSize =3D 10;=0D + UT_ASSERT_STATUS_EQUAL( DumpVariablePolicy( NULL, &DumpSize ), EFI_INVAL= ID_PARAMETER );=0D +=0D + // Now for the actual test case.=0D +=0D + // Allocate a buffer to hold the output.=0D + BufferSize =3D sizeof(VARIABLE_POLICY_ENTRY) + sizeof(TEST_VAR_1_NAME);= =0D + DumpBuffer =3D AllocatePool( BufferSize );=0D + UT_ASSERT_NOT_EQUAL( DumpBuffer, NULL );=0D +=0D + // Verify that the current table size is 0.=0D + DumpSize =3D BufferSize;=0D + UT_ASSERT_NOT_EFI_ERROR( DumpVariablePolicy( DumpBuffer, &DumpSize ) );= =0D + UT_ASSERT_EQUAL( DumpSize, 0 );=0D +=0D + // Now, set a new policy.=0D + UT_ASSERT_NOT_EFI_ERROR( RegisterVariablePolicy( &TestPolicy.Header ) );= =0D +=0D + // Make sure that the new return is non-zero and fails as expected.=0D + DumpSize =3D 0;=0D + PolicyCheck =3D DumpVariablePolicy( NULL, &DumpSize );=0D + UT_ASSERT_STATUS_EQUAL( PolicyCheck, EFI_BUFFER_TOO_SMALL );=0D + UT_ASSERT_EQUAL( DumpSize, BufferSize );=0D +=0D + // Now verify that we can fetch the dump.=0D + DumpSize =3D BufferSize;=0D + UT_ASSERT_NOT_EFI_ERROR( DumpVariablePolicy( DumpBuffer, &DumpSize ) );= =0D + UT_ASSERT_EQUAL( DumpSize, BufferSize );=0D + UT_ASSERT_MEM_EQUAL( &TestPolicy, DumpBuffer, BufferSize );=0D +=0D + // Always put away your toys.=0D + FreePool( DumpBuffer );=0D +=0D + return UNIT_TEST_PASSED;=0D +}=0D +=0D +/**=0D + Test Case=0D +*/=0D +UNIT_TEST_STATUS=0D +EFIAPI=0D +ShouldBeAbleToDumpThePolicyTableAfterDisabled (=0D + IN UNIT_TEST_CONTEXT Context=0D + )=0D +{=0D + SIMPLE_VARIABLE_POLICY_ENTRY TestPolicy =3D {=0D + {=0D + VARIABLE_POLICY_ENTRY_REVISION,=0D + sizeof(VARIABLE_POLICY_ENTRY) + sizeof(TEST_VAR_1_NAME),=0D + sizeof(VARIABLE_POLICY_ENTRY),=0D + TEST_GUID_1,=0D + TEST_POLICY_MIN_SIZE_10,=0D + TEST_POLICY_MAX_SIZE_200,=0D + TEST_POLICY_ATTRIBUTES_NULL,=0D + TEST_POLICY_ATTRIBUTES_NULL,=0D + VARIABLE_POLICY_TYPE_NO_LOCK=0D + },=0D + TEST_VAR_1_NAME=0D + };=0D + SIMPLE_VARIABLE_POLICY_ENTRY TestPolicy2 =3D {=0D + {=0D + VARIABLE_POLICY_ENTRY_REVISION,=0D + sizeof(VARIABLE_POLICY_ENTRY) + sizeof(TEST_VAR_2_NAME),=0D + sizeof(VARIABLE_POLICY_ENTRY),=0D + TEST_GUID_2,=0D + TEST_POLICY_MIN_SIZE_10,=0D + TEST_POLICY_MAX_SIZE_200,=0D + TEST_POLICY_ATTRIBUTES_NULL,=0D + TEST_POLICY_ATTRIBUTES_NULL,=0D + VARIABLE_POLICY_TYPE_NO_LOCK=0D + },=0D + TEST_VAR_2_NAME=0D + };=0D + EFI_STATUS PolicyCheck;=0D + UINT32 DumpSize;=0D + VOID *DumpBuffer;=0D +=0D + DumpBuffer =3D NULL;=0D + DumpSize =3D 0;=0D +=0D + // Register a new policy.=0D + UT_ASSERT_NOT_EFI_ERROR( RegisterVariablePolicy( &TestPolicy.Header ) );= =0D + // Make sure that we can dump the policy.=0D + PolicyCheck =3D DumpVariablePolicy( DumpBuffer, &DumpSize );=0D + UT_ASSERT_STATUS_EQUAL( PolicyCheck, EFI_BUFFER_TOO_SMALL );=0D + DumpBuffer =3D AllocatePool( DumpSize );=0D + UT_ASSERT_NOT_EFI_ERROR( DumpVariablePolicy( DumpBuffer, &DumpSize ) );= =0D + UT_ASSERT_MEM_EQUAL( DumpBuffer, &TestPolicy, DumpSize );=0D +=0D + // Clean up from this step.=0D + FreePool( DumpBuffer );=0D + DumpBuffer =3D NULL;=0D + DumpSize =3D 0;=0D +=0D + // Now disable the engine.=0D + DisableVariablePolicy();=0D +=0D + // Now register a new policy and make sure that both can be dumped.=0D + UT_ASSERT_NOT_EFI_ERROR( RegisterVariablePolicy( &TestPolicy2.Header ) )= ;=0D + // Make sure that we can dump the policy.=0D + PolicyCheck =3D DumpVariablePolicy( DumpBuffer, &DumpSize );=0D + UT_ASSERT_STATUS_EQUAL( PolicyCheck, EFI_BUFFER_TOO_SMALL );=0D + DumpBuffer =3D AllocatePool( DumpSize );=0D + UT_ASSERT_NOT_EFI_ERROR( DumpVariablePolicy( DumpBuffer, &DumpSize ) );= =0D +=0D + // Finally, make sure that both policies are in the dump.=0D + UT_ASSERT_MEM_EQUAL( DumpBuffer, &TestPolicy, TestPolicy.Header.Size );= =0D + UT_ASSERT_MEM_EQUAL( (UINT8*)DumpBuffer + TestPolicy.Header.Size,=0D + &TestPolicy2,=0D + TestPolicy2.Header.Size );=0D +=0D + // Always put away your toys.=0D + FreePool( DumpBuffer );=0D +=0D + return UNIT_TEST_PASSED;=0D +}=0D +=0D +=0D +///=3D=3D=3D TEST ENGINE =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=0D +=0D +/**=0D + SampleUnitTestApp=0D +=0D + @param[in] ImageHandle The firmware allocated handle for the EFI image.= =0D + @param[in] SystemTable A pointer to the EFI System Table.=0D +=0D + @retval EFI_SUCCESS The entry point executed successfully.=0D + @retval other Some error occured when executing this entry poi= nt.=0D +=0D +**/=0D +int=0D +main (=0D + )=0D +{=0D + EFI_STATUS Status;=0D + UNIT_TEST_FRAMEWORK_HANDLE Framework =3D NULL;=0D + UNIT_TEST_SUITE_HANDLE ArchTests;=0D + UNIT_TEST_SUITE_HANDLE PolicyTests;=0D + UNIT_TEST_SUITE_HANDLE UtilityTests;=0D +#ifdef INTERNAL_UNIT_TEST=0D + UNIT_TEST_SUITE_HANDLE InternalTests;=0D +#endif // INTERNAL_UNIT_TEST=0D +=0D + DEBUG(( DEBUG_INFO, "%a v%a\n", UNIT_TEST_NAME, UNIT_TEST_VERSION ));=0D +=0D + //=0D + // Start setting up the test framework for running the tests.=0D + //=0D + Status =3D InitUnitTestFramework( &Framework, UNIT_TEST_NAME, gEfiCaller= BaseName, UNIT_TEST_VERSION );=0D + if (EFI_ERROR( Status ))=0D + {=0D + DEBUG((DEBUG_ERROR, "Failed in InitUnitTestFramework. Status =3D %r\n"= , Status));=0D + goto EXIT;=0D + }=0D +=0D +=0D + //=0D + // Add all test suites and tests.=0D + //=0D + Status =3D CreateUnitTestSuite( &ArchTests, Framework, "Variable Policy = Architectural Tests", "VarPolicy.Arch", NULL, NULL );=0D + if (EFI_ERROR( Status ))=0D + {=0D + DEBUG((DEBUG_ERROR, "Failed in CreateUnitTestSuite for ArchTests\n"));= =0D + Status =3D EFI_OUT_OF_RESOURCES;=0D + goto EXIT;=0D + }=0D + AddTestCase( ArchTests,=0D + "Deinitialization should fail if not previously initialize= d", "VarPolicy.Arch.OnlyDeinit",=0D + ShouldFailDeinitWithoutInit, NULL, NULL, NULL );=0D + AddTestCase( ArchTests,=0D + "Initialization followed by deinitialization should succee= d", "VarPolicy.Arch.InitDeinit",=0D + ShouldBeAbleToInitAndDeinitTheLibrary, NULL, NULL, NULL );= =0D + AddTestCase( ArchTests,=0D + "The initialization function fail if called twice without = a deinit", "VarPolicy.Arch.InitTwice",=0D + ShouldNotBeAbleToInitializeTheLibraryTwice, NULL, LibClean= up, NULL );=0D + AddTestCase( ArchTests,=0D + "API functions should be unavailable until library is init= ialized", "VarPolicy.Arch.UninitApiOff",=0D + ApiCommandsShouldNotRespondIfLibIsUninitialized, NULL, Lib= Cleanup, NULL );=0D +=0D +#ifdef INTERNAL_UNIT_TEST=0D + Status =3D CreateUnitTestSuite( &InternalTests, Framework, "Variable Pol= icy Internal Tests", "VarPolicy.Internal", NULL, NULL );=0D + if (EFI_ERROR( Status ))=0D + {=0D + DEBUG((DEBUG_ERROR, "Failed in CreateUnitTestSuite for InternalTests\n= "));=0D + Status =3D EFI_OUT_OF_RESOURCES;=0D + goto EXIT;=0D + }=0D + AddTestCase( InternalTests,=0D + "Policy matching should use name and GUID", "VarPolicy.Int= ernal.NameGuid",=0D + PoliciesShouldMatchByNameAndGuid, LibInitMocked, LibCleanu= p, NULL );=0D + AddTestCase( InternalTests,=0D + "# sign wildcards should match digits", "VarPolicy.Interna= l.WildDigits",=0D + WildcardPoliciesShouldMatchDigits, LibInitMocked, LibClean= up, NULL );=0D + AddTestCase( InternalTests,=0D + "Digit wildcards should check edge cases", "VarPolicy.Inte= rnal.WildDigitsAdvanced",=0D + WildcardPoliciesShouldMatchDigitsAdvanced, LibInitMocked, = LibCleanup, NULL );=0D + AddTestCase( InternalTests,=0D + "Empty names should match an entire namespace", "VarPolicy= .Internal.WildNamespace",=0D + WildcardPoliciesShouldMatchNamespaces, LibInitMocked, LibC= leanup, NULL );=0D + AddTestCase( InternalTests,=0D + "Match priority should weight correctly based on wildcards= ", "VarPolicy.Internal.Priorities",=0D + MatchPrioritiesShouldFollowRules, LibInitMocked, LibCleanu= p, NULL );=0D +#endif // INTERNAL_UNIT_TEST=0D +=0D + Status =3D CreateUnitTestSuite( &PolicyTests, Framework, "Variable Polic= y Manipulation Tests", "VarPolicy.Policy", NULL, NULL );=0D + if (EFI_ERROR( Status ))=0D + {=0D + DEBUG((DEBUG_ERROR, "Failed in CreateUnitTestSuite for PolicyTests\n")= );=0D + Status =3D EFI_OUT_OF_RESOURCES;=0D + goto EXIT;=0D + }=0D + AddTestCase( PolicyTests,=0D + "RegisterShouldAllowNamespaceWildcards", "VarPolicy.Policy= .AllowNamespace",=0D + RegisterShouldAllowNamespaceWildcards, LibInitMocked, LibC= leanup, NULL );=0D + AddTestCase( PolicyTests,=0D + "RegisterShouldAllowStateVarsForNamespaces", "VarPolicy.Po= licy.AllowStateNamespace",=0D + RegisterShouldAllowStateVarsForNamespaces, LibInitMocked, = LibCleanup, NULL );=0D + AddTestCase( PolicyTests,=0D + "RegisterShouldRejectNullPointers", "VarPolicy.Policy.Null= Pointers",=0D + RegisterShouldRejectNullPointers, LibInitMocked, LibCleanu= p, NULL );=0D + AddTestCase( PolicyTests,=0D + "RegisterShouldRejectBadRevisions", "VarPolicy.Policy.BadR= evisions",=0D + RegisterShouldRejectBadRevisions, LibInitMocked, LibCleanu= p, NULL );=0D + AddTestCase( PolicyTests,=0D + "RegisterShouldRejectBadSizes", "VarPolicy.Policy.BadSizes= ",=0D + RegisterShouldRejectBadSizes, LibInitMocked, LibCleanup, N= ULL );=0D + AddTestCase( PolicyTests,=0D + "RegisterShouldRejectBadOffsets", "VarPolicy.Policy.BadOff= sets",=0D + RegisterShouldRejectBadOffsets, LibInitMocked, LibCleanup,= NULL );=0D + AddTestCase( PolicyTests,=0D + "RegisterShouldRejectMissingStateStrings", "VarPolicy.Poli= cy.MissingStateString",=0D + RegisterShouldRejectMissingStateStrings, LibInitMocked, Li= bCleanup, NULL );=0D + AddTestCase( PolicyTests,=0D + "RegisterShouldRejectStringsMissingNull", "VarPolicy.Polic= y.MissingNull",=0D + RegisterShouldRejectStringsMissingNull, LibInitMocked, Lib= Cleanup, NULL );=0D + AddTestCase( PolicyTests,=0D + "RegisterShouldRejectMalformedStrings", "VarPolicy.Policy.= MalformedStrings",=0D + RegisterShouldRejectMalformedStrings, LibInitMocked, LibCl= eanup, NULL );=0D + AddTestCase( PolicyTests,=0D + "RegisterShouldRejectUnpackedPolicies", "VarPolicy.Policy.= PolicyPacking",=0D + RegisterShouldRejectUnpackedPolicies, LibInitMocked, LibCl= eanup, NULL );=0D + AddTestCase( PolicyTests,=0D + "RegisterShouldRejectInvalidNameCharacters", "VarPolicy.Po= licy.InvalidCharacters",=0D + RegisterShouldRejectInvalidNameCharacters, LibInitMocked, = LibCleanup, NULL );=0D + AddTestCase( PolicyTests,=0D + "RegisterShouldRejectBadPolicyConstraints", "VarPolicy.Pol= icy.BadConstraints",=0D + RegisterShouldRejectBadPolicyConstraints, LibInitMocked, L= ibCleanup, NULL );=0D + AddTestCase( PolicyTests,=0D + "RegisterShouldRejectUnknownLockPolicies", "VarPolicy.Poli= cy.BadLocks",=0D + RegisterShouldRejectUnknownLockPolicies, LibInitMocked, Li= bCleanup, NULL );=0D + AddTestCase( PolicyTests,=0D + "RegisterShouldRejectPolicesWithTooManyWildcards", "VarPol= icy.Policy.TooManyWildcards",=0D + RegisterShouldRejectPolicesWithTooManyWildcards, LibInitMo= cked, LibCleanup, NULL );=0D + AddTestCase( PolicyTests,=0D + "RegisterShouldRejectDuplicatePolicies", "VarPolicy.Policy= .DuplicatePolicies",=0D + RegisterShouldRejectDuplicatePolicies, LibInitMocked, LibC= leanup, NULL );=0D + AddTestCase( PolicyTests,=0D + "Variables that exceed min or max sizes should be rejected= ", "VarPolicy.Policy.MinMax",=0D + MinAndMaxSizePoliciesShouldBeHonored, LibInitMocked, LibCl= eanup, NULL );=0D + AddTestCase( PolicyTests,=0D + "AttributeMustPoliciesShouldBeHonored", "VarPolicy.Policy.= AttrMust",=0D + AttributeMustPoliciesShouldBeHonored, LibInitMocked, LibCl= eanup, NULL );=0D + AddTestCase( PolicyTests,=0D + "AttributeCantPoliciesShouldBeHonored", "VarPolicy.Policy.= AttrCant",=0D + AttributeCantPoliciesShouldBeHonored, LibInitMocked, LibCl= eanup, NULL );=0D + AddTestCase( PolicyTests,=0D + "VariablesShouldBeDeletableRegardlessOfSize", "VarPolicy.P= olicy.DeleteIgnoreSize",=0D + VariablesShouldBeDeletableRegardlessOfSize, LibInitMocked,= LibCleanup, NULL );=0D + AddTestCase( PolicyTests,=0D + "LockNowPoliciesShouldBeHonored", "VarPolicy.Policy.VARIAB= LE_POLICY_TYPE_LOCK_NOW",=0D + LockNowPoliciesShouldBeHonored, LibInitMocked, LibCleanup,= NULL );=0D + AddTestCase( PolicyTests,=0D + "LockOnCreatePoliciesShouldBeHonored", "VarPolicy.Policy.V= ARIABLE_POLICY_TYPE_LOCK_ON_CREATE",=0D + LockOnCreatePoliciesShouldBeHonored, LibInitMocked, LibCle= anup, NULL );=0D + AddTestCase( PolicyTests,=0D + "LockOnStatePoliciesShouldBeHonored", "VarPolicy.Policy.Lo= ckState",=0D + LockOnStatePoliciesShouldBeHonored, LibInitMocked, LibClea= nup, NULL );=0D + AddTestCase( PolicyTests,=0D + "LockOnStatePoliciesShouldApplyToNamespaces", "VarPolicy.P= olicy.NamespaceLockState",=0D + LockOnStatePoliciesShouldApplyToNamespaces, LibInitMocked,= LibCleanup, NULL );=0D + AddTestCase( PolicyTests,=0D + "LockOnStateShouldHandleErrorsGracefully", "VarPolicy.Poli= cy.LockStateErrors",=0D + LockOnStateShouldHandleErrorsGracefully, LibInitMocked, Li= bCleanup, NULL );=0D + AddTestCase( PolicyTests,=0D + "BestMatchPriorityShouldBeObeyed", "VarPolicy.Policy.BestM= atch",=0D + BestMatchPriorityShouldBeObeyed, LibInitMocked, LibCleanup= , NULL );=0D +=0D + Status =3D CreateUnitTestSuite( &UtilityTests, Framework, "Variable Poli= cy Utility Tests", "VarPolicy.Utility", NULL, NULL );=0D + if (EFI_ERROR( Status ))=0D + {=0D + DEBUG((DEBUG_ERROR, "Failed in CreateUnitTestSuite for UtilityTests\n"= ));=0D + Status =3D EFI_OUT_OF_RESOURCES;=0D + goto EXIT;=0D + }=0D + AddTestCase( UtilityTests,=0D + "API commands that change state should not respond after i= nterface is locked", "VarPolicy.Utility.InterfaceLock",=0D + ShouldBeAbleToLockInterface, LibInitMocked, LibCleanup, NU= LL );=0D + AddTestCase( UtilityTests,=0D + "All policies should pass once enforcement is disabled", "= VarPolicy.Utility.DisableEnforcement",=0D + ShouldBeAbleToDisablePolicyEnforcement, LibInitMocked, Lib= Cleanup, NULL );=0D + AddTestCase( UtilityTests,=0D + "Disabling enforcement twice should produce an error", "Va= rPolicy.Utility.DisableEnforcementTwice",=0D + ShouldNotBeAbleToDisablePoliciesTwice, LibInitMocked, LibC= leanup, NULL );=0D + AddTestCase( UtilityTests,=0D + "ShouldBeAbleToAddNewPoliciesAfterDisabled", "VarPolicy.Ut= ility.AddAfterDisable",=0D + ShouldBeAbleToAddNewPoliciesAfterDisabled, LibInitMocked, = LibCleanup, NULL );=0D + AddTestCase( UtilityTests,=0D + "ShouldBeAbleToLockAfterDisabled", "VarPolicy.Utility.Lock= AfterDisable",=0D + ShouldBeAbleToLockAfterDisabled, LibInitMocked, LibCleanup= , NULL );=0D + AddTestCase( UtilityTests,=0D + "Should be able to dump the policy table", "VarPolicy.Util= ity.DumpTable",=0D + ShouldBeAbleToDumpThePolicyTable, LibInitMocked, LibCleanu= p, NULL );=0D + AddTestCase( UtilityTests,=0D + "ShouldBeAbleToDumpThePolicyTableAfterDisabled", "VarPolic= y.Utility.DumpTableAfterDisable",=0D + ShouldBeAbleToDumpThePolicyTableAfterDisabled, LibInitMock= ed, LibCleanup, NULL );=0D +=0D +=0D + //=0D + // Execute the tests.=0D + //=0D + Status =3D RunAllTestSuites( Framework );=0D +=0D +EXIT:=0D + if (Framework !=3D NULL)=0D + {=0D + FreeUnitTestFramework( Framework );=0D + }=0D +=0D + return Status;=0D +}=0D diff --git a/MdeModulePkg/Include/Library/VariablePolicyLib.h b/MdeModulePk= g/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=0D +Business logic for Variable Policy enforcement.=0D +=0D +Copyright (c) Microsoft Corporation.=0D +SPDX-License-Identifier: BSD-2-Clause-Patent=0D +=0D +**/=0D +=0D +#ifndef _VARIABLE_POLICY_LIB_H_=0D +#define _VARIABLE_POLICY_LIB_H_=0D +=0D +#include =0D +=0D +/**=0D + This API function validates and registers a new policy with=0D + the policy enforcement engine.=0D +=0D + @param[in] NewPolicy Pointer to the incoming policy structure.=0D +=0D + @retval EFI_SUCCESS=0D + @retval EFI_INVALID_PARAMETER NewPolicy is NULL or is internally i= nconsistent.=0D + @retval EFI_ALREADY_STARTED An identical matching policy already= exists.=0D + @retval EFI_WRITE_PROTECTED The interface has been locked until = the next reboot.=0D + @retval EFI_UNSUPPORTED Policy enforcement has been disabled= . No reason to add more policies.=0D + @retval EFI_ABORTED A calculation error has prevented th= is function from completing.=0D + @retval EFI_OUT_OF_RESOURCES Cannot grow the table to hold any mo= re policies.=0D + @retval EFI_NOT_READY Library has not yet been initialized= .=0D +=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +RegisterVariablePolicy (=0D + IN CONST VARIABLE_POLICY_ENTRY *NewPolicy=0D + );=0D +=0D +=0D +/**=0D + This API function checks to see whether the parameters to SetVariable wo= uld=0D + be allowed according to the current variable policies.=0D +=0D + @param[in] VariableName Same as EFI_SET_VARIABLE.=0D + @param[in] VendorGuid Same as EFI_SET_VARIABLE.=0D + @param[in] Attributes Same as EFI_SET_VARIABLE.=0D + @param[in] DataSize Same as EFI_SET_VARIABLE.=0D + @param[in] Data Same as EFI_SET_VARIABLE.=0D +=0D + @retval EFI_SUCCESS A matching policy allows this update= .=0D + @retval EFI_SUCCESS There are currently no policies that= restrict this update.=0D + @retval EFI_SUCCESS The protections have been disable un= til the next reboot.=0D + @retval EFI_WRITE_PROTECTED Variable is currently locked.=0D + @retval EFI_INVALID_PARAMETER Attributes or size are invalid.=0D + @retval EFI_ABORTED A lock policy exists, but an error p= revented evaluation.=0D + @retval EFI_NOT_READY Library has not been initialized.=0D +=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +ValidateSetVariable (=0D + IN CHAR16 *VariableName,=0D + IN EFI_GUID *VendorGuid,=0D + IN UINT32 Attributes,=0D + IN UINTN DataSize,=0D + IN VOID *Data=0D + );=0D +=0D +=0D +/**=0D + This API function disables the variable policy enforcement. If it's=0D + already been called once, will return EFI_ALREADY_STARTED.=0D +=0D + @retval EFI_SUCCESS=0D + @retval EFI_ALREADY_STARTED Has already been called once this boot= .=0D + @retval EFI_WRITE_PROTECTED Interface has been locked until reboot= .=0D + @retval EFI_WRITE_PROTECTED Interface option is disabled by platfo= rm PCD.=0D + @retval EFI_NOT_READY Library has not yet been initialized.=0D +=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +DisableVariablePolicy (=0D + VOID=0D + );=0D +=0D +=0D +/**=0D + This API function will dump the entire contents of the variable policy t= able.=0D +=0D + Similar to GetVariable, the first call can be made with a 0 size and it = will return=0D + the size of the buffer required to hold the entire table.=0D +=0D + @param[out] Policy Pointer to the policy buffer. Can be NULL if Siz= e is 0.=0D + @param[in,out] Size On input, the size of the output buffer. On outp= ut, the size=0D + of the data returned.=0D +=0D + @retval EFI_SUCCESS Policy data is in the output buffer = and Size has been updated.=0D + @retval EFI_INVALID_PARAMETER Size is NULL, or Size is non-zero an= d Policy is NULL.=0D + @retval EFI_BUFFER_TOO_SMALL Size is insufficient to hold policy.= Size updated with required size.=0D + @retval EFI_NOT_READY Library has not yet been initialized= .=0D +=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +DumpVariablePolicy (=0D + OUT UINT8 *Policy,=0D + IN OUT UINT32 *Size=0D + );=0D +=0D +=0D +/**=0D + This API function returns whether or not the policy engine is=0D + currently being enforced.=0D +=0D + @retval TRUE=0D + @retval FALSE=0D + @retval FALSE Library has not yet been initialized.=0D +=0D +**/=0D +BOOLEAN=0D +EFIAPI=0D +IsVariablePolicyEnabled (=0D + VOID=0D + );=0D +=0D +=0D +/**=0D + This API function locks the interface so that no more policy updates=0D + can be performed or changes made to the enforcement until the next boot.= =0D +=0D + @retval EFI_SUCCESS=0D + @retval EFI_NOT_READY Library has not yet been initialized.=0D +=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +LockVariablePolicy (=0D + VOID=0D + );=0D +=0D +=0D +/**=0D + This API function returns whether or not the policy interface is locked= =0D + for the remainder of the boot.=0D +=0D + @retval TRUE=0D + @retval FALSE=0D + @retval FALSE Library has not yet been initialized.=0D +=0D +**/=0D +BOOLEAN=0D +EFIAPI=0D +IsVariablePolicyInterfaceLocked (=0D + VOID=0D + );=0D +=0D +=0D +/**=0D + This helper function initializes the library and sets=0D + up any required internal structures or handlers.=0D +=0D + Also registers the internal pointer for the GetVariable helper.=0D +=0D + @param[in] GetVariableHelper A function pointer matching the EFI_GET_VA= RIABLE prototype that will be used to=0D + check policy criteria that involve the existence of othe= r variables.=0D +=0D + @retval EFI_SUCCESS=0D + @retval EFI_ALREADY_STARTED The initialize function has been calle= d more than once without a call to=0D + deinitialize.=0D +=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +InitVariablePolicyLib (=0D + IN EFI_GET_VARIABLE GetVariableHelper=0D + );=0D +=0D +=0D +/**=0D + This helper function returns whether or not the library is currently ini= tialized.=0D +=0D + @retval TRUE=0D + @retval FALSE=0D +=0D +**/=0D +BOOLEAN=0D +EFIAPI=0D +IsVariablePolicyLibInitialized (=0D + VOID=0D + );=0D +=0D +=0D +/**=0D + This helper function tears down the library.=0D +=0D + Should generally only be used for test harnesses.=0D +=0D + @retval EFI_SUCCESS=0D + @retval EFI_NOT_READY Deinitialize was called without first call= ing initialize.=0D +=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +DeinitVariablePolicyLib (=0D + VOID=0D + );=0D +=0D +=0D +#endif // _VARIABLE_POLICY_LIB_H_=0D diff --git a/MdeModulePkg/Library/VariablePolicyLib/ReadMe.md b/MdeModulePk= g/Library/VariablePolicyLib/ReadMe.md new file mode 100644 index 000000000000..9e87b2e25f7d --- /dev/null +++ b/MdeModulePkg/Library/VariablePolicyLib/ReadMe.md @@ -0,0 +1,410 @@ +---=0D +title: UEFI Variable Policy Whitepaper=0D +version: 1.0=0D +copyright: Copyright (c) Microsoft Corporation.=0D +---=0D +=0D +# UEFI Variable Policy=0D +=0D +## Summary=0D +=0D +UEFI Variable Policy spec aims to describe the DXE protocol interface=0D +which allows enforcing certain rules on certain UEFI variables. The=0D +protocol allows communication with the Variable Policy Engine which=0D +performs the policy enforcement.=0D +=0D +The Variable Policy is comprised of a set of policy entries which=0D +describe, per UEFI variable (identified by namespace GUID and variable=0D +name) the following rules:=0D +=0D +- Required variable attributes=0D +- Prohibited variable attributes=0D +- Minimum variable size=0D +- Maximum variable size=0D +- Locking:=0D + - Locking "immediately"=0D + - Locking on creation=0D + - Locking based on a state of another variable=0D +=0D +The spec assumes that the Variable Policy Engine runs in a trusted=0D +enclave, potentially off the main CPU that runs UEFI. For that reason,=0D +it is assumed that the Variable Policy Engine has no concept of UEFI=0D +events, and that the communication from the DXE driver to the trusted=0D +enclave is proprietary.=0D +=0D +At power-on, the Variable Policy Engine is:=0D +=0D +- Enabled -- present policy entries are evaluated on variable access=0D + calls.=0D +- Unlocked -- new policy entries can be registered.=0D +=0D +Policy is expected to be clear on power-on. Policy is volatile and not=0D +preserved across system reset.=0D +=0D +## DXE Protocol=0D +=0D +```h=0D +typedef struct {=0D + UINT64 Revision;=0D + DISABLE_VARIABLE_POLICY DisableVariablePolicy;=0D + IS_VARIABLE_POLICY_ENABLED IsVariablePolicyEnabled;=0D + REGISTER_VARIABLE_POLICY RegisterVariablePolicy;=0D + DUMP_VARIABLE_POLICY DumpVariablePolicy;=0D + LOCK_VARIABLE_POLICY LockVariablePolicy;=0D +} _VARIABLE_POLICY_PROTOCOL;=0D +=0D +typedef _VARIABLE_POLICY_PROTOCOL VARIABLE_POLICY_PROTOCOL;=0D +=0D +extern EFI_GUID gVariablePolicyProtocolGuid;=0D +```=0D +=0D +```text=0D +## Include/Protocol/VariablePolicy.h=0D + gVariablePolicyProtocolGuid =3D { 0x81D1675C, 0x86F6, 0x48DF, { 0xBD, 0x= 95, 0x9A, 0x6E, 0x4F, 0x09, 0x25, 0xC3 } }=0D +```=0D +=0D +### DisableVariablePolicy=0D +=0D +Function prototype:=0D +=0D +```c=0D +EFI_STATUS=0D +EFIAPI=0D +DisableVariablePolicy (=0D + VOID=0D + );=0D +```=0D +=0D +`DisableVariablePolicy` call disables the Variable Policy Engine, so=0D +that the present policy entries are no longer taken into account on=0D +variable access calls. This call effectively turns off the variable=0D +policy verification for this boot. This also disables UEFI=0D +Authenticated Variable protections including Secure Boot.=0D +`DisableVariablePolicy` can only be called once during boot. If called=0D +more than once, it will return `EFI_ALREADY_STARTED`. Note, this process=0D +is irreversible until the next system reset -- there is no=0D +"EnablePolicy" protocol function.=0D +=0D +_IMPORTANT NOTE:_ It is strongly recommended that VariablePolicy *NEVER*=0D +be disabled in "normal, production boot conditions". It is expected to alw= ays=0D +be enforced. The most likely reasons to disable are for Manufacturing and= =0D +Refurbishing scenarios. If in doubt, leave the `gEfiMdeModulePkgTokenSpace= Guid.PcdAllowVariablePolicyEnforcementDisable`=0D +PCD set to `FALSE` and VariablePolicy will always be enabled.=0D +=0D +### IsVariablePolicyEnabled=0D +=0D +Function prototype:=0D +=0D +```c=0D +EFI_STATUS=0D +EFIAPI=0D +IsVariablePolicyEnabled (=0D + OUT BOOLEAN *State=0D + );=0D +```=0D +=0D +`IsVariablePolicyEnabled` accepts a pointer to a Boolean in which it=0D +will store `TRUE` if Variable Policy Engine is enabled, or `FALSE` if=0D +Variable Policy Engine is disabled. The function returns `EFI_SUCCESS`.=0D +=0D +### RegisterVariablePolicy=0D +=0D +Function prototype:=0D +=0D +```c=0D +EFI_STATUS=0D +EFIAPI=0D +RegisterVariablePolicy (=0D + IN CONST VARIABLE_POLICY_ENTRY *PolicyEntry=0D + );=0D +```=0D +=0D +`RegisterVariablePolicy` call accepts a pointer to a policy entry=0D +structure and returns the status of policy registration. If the=0D +Variable Policy Engine is not locked and the policy structures are=0D +valid, the function will return `EFI_SUCCESS`. If the Variable Policy=0D +Engine is locked, `RegisterVariablePolicy` call will return=0D +`EFI_WRITE_PROTECTED` and will not register the policy entry. Bulk=0D +registration is not supported at this time due to the requirements=0D +around error handling on each policy registration.=0D +=0D +Upon successful registration of a policy entry, Variable Policy Engine=0D +will then evaluate this entry on subsequent variable access calls (as=0D +long as Variable Policy Engine hasn't been disabled).=0D +=0D +### DumpVariablePolicy=0D +=0D +Function prototype:=0D +=0D +```c=0D +EFI_STATUS=0D +EFIAPI=0D +DumpVariablePolicy (=0D + OUT UINT8 *Policy,=0D + IN OUT UINT32 *Size=0D + );=0D +```=0D +=0D +`DumpVariablePolicy` call accepts a pointer to a buffer and a pointer to=0D +the size of the buffer as parameters and returns the status of placing=0D +the policy into the buffer. On first call to `DumpVariablePolicy` one=0D +should pass `NULL` as the buffer and a pointer to 0 as the `Size` variable= =0D +and `DumpVariablePolicy` will return `EFI_BUFFER_TOO_SMALL` and will=0D +populate the `Size` parameter with the size of the needed buffer to=0D +store the policy. This way, the caller can allocate the buffer of=0D +correct size and call `DumpVariablePolicy` again. The function will=0D +populate the buffer with policy and return `EFI_SUCCESS`.=0D +=0D +### LockVariablePolicy=0D +=0D +Function prototype:=0D +=0D +```c=0D +EFI_STATUS=0D +EFIAPI=0D +LockVariablePolicy (=0D + VOID=0D + );=0D +```=0D +=0D +`LockVariablePolicy` locks the Variable Policy Engine, i.e. prevents any=0D +new policy entries from getting registered in this boot=0D +(`RegisterVariablePolicy` calls will fail with `EFI_WRITE_PROTECTED`=0D +status code returned).=0D +=0D +## Policy Structure=0D +=0D +The structure below is meant for the DXE protocol calling interface,=0D +when communicating to the Variable Policy Engine, thus the pragma pack=0D +directive. How these policies are stored in memory is up to the=0D +implementation.=0D +=0D +```c=0D +#pragma pack(1)=0D +typedef struct {=0D + UINT32 Version;=0D + UINT16 Size;=0D + UINT16 OffsetToName;=0D + EFI_GUID Namespace;=0D + UINT32 MinSize;=0D + UINT32 MaxSize;=0D + UINT32 AttributesMustHave;=0D + UINT32 AttributesCantHave;=0D + UINT8 LockPolicyType;=0D + UINT8 Reserved[3];=0D + // UINT8 LockPolicy[]; // Variable Length Field=0D + // CHAR16 Name[]; // Variable Length Field=0D +} VARIABLE_POLICY_ENTRY;=0D +```=0D +=0D +The struct `VARIABLE_POLICY_ENTRY` above describes the layout for a policy= =0D +entry. The first element, `Size`, is the size of the policy entry, then=0D +followed by `OffsetToName` -- the number of bytes from the beginning of=0D +the struct to the name of the UEFI variable targeted by the policy=0D +entry. The name can contain wildcards to match more than one variable,=0D +more on this in the Wildcards section. The rest of the struct elements=0D +are self-explanatory.=0D +=0D +```cpp=0D +#define VARIABLE_POLICY_TYPE_NO_LOCK 0=0D +#define VARIABLE_POLICY_TYPE_LOCK_NOW 1=0D +#define VARIABLE_POLICY_TYPE_LOCK_ON_CREATE 2=0D +#define VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE 3=0D +```=0D +=0D +`LockPolicyType` can have the following values:=0D +=0D +- `VARIABLE_POLICY_TYPE_NO_LOCK` -- means that no variable locking is pe= rformed. However,=0D + the attribute and size constraints are still enforced. LockPolicy=0D + field is size 0.=0D +- `VARIABLE_POLICY_TYPE_LOCK_NOW` -- means that the variable starts bein= g locked=0D + immediately after policy entry registration. If the variable doesn't=0D + exist at this point, being LockedNow means it cannot be created on=0D + this boot. LockPolicy field is size 0.=0D +- `VARIABLE_POLICY_TYPE_LOCK_ON_CREATE` -- means that the variable start= s being locked=0D + after it is created. This allows for variable creation and=0D + protection after LockVariablePolicy() function has been called. The=0D + LockPolicy field is size 0.=0D +- `VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE` -- means that the Variable Po= licy Engine will=0D + examine the state/contents of another variable to determine if the=0D + variable referenced in the policy entry is locked.=0D +=0D +```c=0D +typedef struct {=0D + EFI_GUID Namespace;=0D + UINT8 Value;=0D + UINT8 Reserved;=0D + // CHAR16 Name[]; // Variable Length Field=0D +} VARIABLE_LOCK_ON_VAR_STATE_POLICY;=0D +```=0D +=0D +If `LockPolicyType` is `VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE`, then the = final element in the=0D +policy entry struct is of type `VARIABLE_LOCK_ON_VAR_STATE_POLICY`, which= =0D +lists the namespace GUID, name (no wildcards here), and value of the=0D +variable which state determines the locking of the variable referenced=0D +in the policy entry. The "locking" variable must be 1 byte in terms of=0D +payload size. If the Referenced variable contents match the Value of the=0D +`VARIABLE_LOCK_ON_VAR_STATE_POLICY` structure, the lock will be considered= =0D +active and the target variable will be locked. If the Reference variable=0D +does not exist (ie. returns `EFI_NOT_FOUND`), this policy will be=0D +considered inactive.=0D +=0D +## Variable Name Wildcards=0D +=0D +Two types of wildcards can be used in the UEFI variable name field in a=0D +policy entry:=0D +=0D +1. If the Name is a zero-length array (easily checked by comparing=0D + fields `Size` and `OffsetToName` -- if they're the same, then the=0D + `Name` is zero-length), then all variables in the namespace specified= =0D + by the provided GUID are targeted by the policy entry.=0D +2. Character "#" in the `Name` corresponds to one numeric character=0D + (0-9, A-F, a-f). For example, string "Boot####" in the `Name`=0D + field of the policy entry will make it so that the policy entry will=0D + target variables named "Boot0001", "Boot0002", etc.=0D +=0D +Given the above two types of wildcards, one variable can be targeted by=0D +more than one policy entry, thus there is a need to establish the=0D +precedence rule: a more specific match is applied. When a variable=0D +access operation is performed, Variable Policy Engine should first check=0D +the variable being accessed against the policy entries without=0D +wildcards, then with 1 wildcard, then with 2 wildcards, etc., followed=0D +in the end by policy entries that match the whole namespace. One can=0D +still imagine a situation where two policy entries with the same number=0D +of wildcards match the same variable -- for example, policy entries with=0D +Names "Boot00##" and "Boot##01" will both match variable "Boot0001".=0D +Such situation can (and should) be avoided by designing mutually=0D +exclusive Name strings with wildcards, however, if it occurs, then the=0D +policy entry that was registered first will be used. After the most=0D +specific match is selected, all other policies are ignored.=0D +=0D +## Available Testing=0D +=0D +This functionality is current supported by two kinds of tests: there is a = host-based=0D +unit test for the core business logic (this test accompanies the `Variable= PolicyLib`=0D +implementation that lives in `MdeModulePkg/Library`) and there is a functi= onal test=0D +for the protocol and its interfaces (this test lives in the `MdeModulePkg/= Test/ShellTest`=0D +directory).=0D +=0D +### Host-Based Unit Test=0D +=0D +This test:=0D +=0D +`MdeModulePkg\Library\VariablePolicyLib\VariablePolicyUnitTest\VariablePol= icyUnitTest.inf`=0D +=0D +can be run as part of the Host-Based Unit Testing infrastructure provided = by EDK2=0D +PyTools (documented elsewhere). It will test all internal guarantees and i= s=0D +where you will find test cases for most of the policy matching and securit= y of the=0D +Variable Policy Engine.=0D +=0D +### Shell-Based Functional Test=0D +=0D +This test -- [Variable Policy Functional Unit Test](https://github.com/mic= rosoft/mu_plus/tree/release/202005/UefiTestingPkg/FunctionalSystemTests/Var= PolicyUnitTestApp) -- can be built as a=0D +UEFI Shell application and run to validate that the Variable Policy Engine= =0D +is correctly installed and enforcing policies on the target system.=0D +=0D +NOTE: This test _must_ be run prior to calling `DisableVariablePolicy` for= all=0D +test cases to pass. For this reason, it is recommended to run this on a te= st-built=0D +FW for complete results, and then again on a production-built FW for relea= se=0D +results.=0D +=0D +## Use Cases=0D +=0D +The below examples are hypothetical scenarios based on real-world requirem= ents=0D +that demonstrate how Variable Policies could be constructed to solve vario= us=0D +problems.=0D +=0D +### UEFI Setup Variables (Example 1)=0D +=0D +Variables containing values of the setup options exposed via UEFI=0D +menu (setup variables). These would be locked based on a state of=0D +another variable, "ReadyToBoot", which would be set to 1 at the=0D +ReadyToBoot event. Thus, the policy for the setup variables would be=0D +of type `LockOnVarState`, with the "ReadyToBoot" listed as the name of=0D +the variable, appropriate GUID listed as the namespace, and 1 as=0D +value. Entry into the trusted UEFI menu app doesn't signal=0D +ReadyToBoot, but booting to any device does, and the setup variables=0D +are write-protected. The "ReadyToBoot" variable would need to be=0D +locked-on-create. *(THIS IS ESSENTIALLY LOCK ON EVENT, BUT SINCE THE=0D +POLICY ENGINE IS NOT IN THE UEFI ENVIRONMENT VARIABLES ARE USED)*=0D +=0D +For example, "AllowPXEBoot" variable locked by "ReadyToBoot" variable.=0D +=0D +(NOTE: In the below example, the emphasized fields ('Namespace', 'Value', = and 'Name')=0D +are members of the `VARIABLE_LOCK_ON_VAR_STATE_POLICY` structure.)=0D +=0D +Size | ...=0D +---- | ---=0D +OffsetToName | ...=0D +NameSpace | ...=0D +MinSize | ...=0D +MaxSize | ...=0D +AttributesMustHave | ...=0D +AttributesCantHave | ...=0D +LockPolicyType | `VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE`=0D +_Namespace_ | ...=0D +_Value_ | 1=0D +_Name_ | "ReadyToBoot"=0D +//Name | "AllowPXEBoot"=0D +=0D +### Manufacturing VPD (Example 2)=0D +=0D +Manufacturing Variable Provisioning Data (VPD) is stored in=0D +variables and is created while in Manufacturing (MFG) Mode. In MFG=0D +Mode Variable Policy Engine is disabled, thus these VPD variables=0D +can be created. These variables are locked with lock policy type=0D +`LockNow`, so that these variables can't be tampered with in Customer=0D +Mode. To overwrite or clear VPD, the device would need to MFG mode,=0D +which is standard practice for refurbishing/remanufacturing=0D +scenarios.=0D +=0D +Example: "DisplayPanelCalibration" variable...=0D +=0D +Size | ...=0D +---- | ---=0D +OffsetToName | ...=0D +NameSpace | ...=0D +MinSize | ...=0D +MaxSize | ...=0D +AttributesMustHave | ...=0D +AttributesCantHave | ...=0D +LockPolicyType | `VARIABLE_POLICY_TYPE_LOCK_NOW`=0D +// Name | "DisplayPanelCalibration"=0D +=0D +### 3rd Party Calibration Data (Example 3)=0D +=0D +Bluetooth pre-pairing variables are locked-on-create because these=0D +get created by an OS application when Variable Policy is in effect.=0D +=0D +Example: "KeyboardBTPairing" variable=0D +=0D +Size | ...=0D +---- | ---=0D +OffsetToName | ...=0D +NameSpace | ...=0D +MinSize | ...=0D +MaxSize | ...=0D +AttributesMustHave | ...=0D +AttributesCantHave | ...=0D +LockPolicyType | `VARIABLE_POLICY_TYPE_LOCK_ON_CREATE`=0D +// Name | "KeyboardBTPairing"=0D +=0D +### Software-based Variable Policy (Example 4)=0D +=0D +Example: "Boot####" variables (a name string with wildcards that=0D +will match variables "Boot0000" to "BootFFFF") locked by "LockBootOrder"=0D +variable.=0D +=0D +Size | ...=0D +---- | ---=0D +OffsetToName | ...=0D +NameSpace | ...=0D +MinSize | ...=0D +MaxSize | ...=0D +AttributesMustHave | ...=0D +AttributesCantHave | ...=0D +LockPolicyType | `VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE`=0D +_Namespace_ | ...=0D +_Value_ | 1=0D +_Name_ | "LockBootOrder"=0D +//Name | "Boot####"=0D diff --git a/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.inf b= /MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.inf new file mode 100644 index 000000000000..f35826a4b9d7 --- /dev/null +++ b/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.inf @@ -0,0 +1,49 @@ +## @file VariablePolicyLib.inf=0D +# Business logic for Variable Policy enforcement.=0D +#=0D +##=0D +# Copyright (c) Microsoft Corporation.=0D +# SPDX-License-Identifier: BSD-2-Clause-Patent=0D +##=0D +=0D +=0D +[Defines]=0D + INF_VERSION =3D 0x00010017=0D + BASE_NAME =3D VariablePolicyLib=0D + FILE_GUID =3D E9ECD342-159A-4F24-9FDF-65724027C594=0D + VERSION_STRING =3D 1.0=0D + MODULE_TYPE =3D DXE_DRIVER=0D + LIBRARY_CLASS =3D VariablePolicyLib|DXE_DRIVER DXE_SMM_DRIVER MM_S= TANDALONE=0D +=0D +#=0D +# The following information is for reference only and not required by the = build tools.=0D +#=0D +# VALID_ARCHITECTURES =3D ANY=0D +#=0D +=0D +=0D +[Sources]=0D + VariablePolicyLib.c=0D + VariablePolicyExtraInitNull.c=0D +=0D +=0D +[Packages]=0D + MdePkg/MdePkg.dec=0D + MdeModulePkg/MdeModulePkg.dec=0D +=0D +=0D +[LibraryClasses]=0D + DebugLib=0D + BaseMemoryLib=0D + MemoryAllocationLib=0D + SafeIntLib=0D + PcdLib=0D +=0D +=0D +[Pcd]=0D + gEfiMdeModulePkgTokenSpaceGuid.PcdAllowVariablePolicyEnforcementDisable = ## CONSUMES=0D +=0D +=0D +[BuildOptions]=0D + MSFT:NOOPT_*_*_CC_FLAGS =3D -DINTERNAL_UNIT_TEST=0D + GCC:NOOPT_*_*_CC_FLAGS =3D -DINTERNAL_UNIT_TEST=0D 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=0D +// VariablePolicyLib.uni=0D +//=0D +// Copyright (c) Microsoft Corporation.=0D +// SPDX-License-Identifier: BSD-2-Clause-Patent=0D +//=0D +// **/=0D +=0D +=0D +#string STR_MODULE_ABSTRACT #language en-US "Library containin= g the business logic for the VariablePolicy engine"=0D +=0D +#string STR_MODULE_DESCRIPTION #language en-US "Library containin= g the business logic for the VariablePolicy engine"=0D diff --git a/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLibRuntim= eDxe.inf b/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLibRuntimeD= xe.inf new file mode 100644 index 000000000000..8b8365741864 --- /dev/null +++ b/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLibRuntimeDxe.inf @@ -0,0 +1,51 @@ +## @file VariablePolicyLibRuntimeDxe.inf=0D +# Business logic for Variable Policy enforcement.=0D +# This instance is specifically for RuntimeDxe and contains=0D +# extra routines to register for VirtualAddressChangeEvents.=0D +#=0D +# Copyright (c) Microsoft Corporation.=0D +# SPDX-License-Identifier: BSD-2-Clause-Patent=0D +##=0D +=0D +=0D +[Defines]=0D + INF_VERSION =3D 0x00010017=0D + BASE_NAME =3D VariablePolicyLibRuntimeDxe=0D + FILE_GUID =3D 205F7F0E-8EAC-4914-8390-1B90DD7E2A27=0D + VERSION_STRING =3D 1.0=0D + MODULE_TYPE =3D DXE_RUNTIME_DRIVER=0D + LIBRARY_CLASS =3D VariablePolicyLib|DXE_RUNTIME_DRIVER=0D +=0D +#=0D +# The following information is for reference only and not required by the = build tools.=0D +#=0D +# VALID_ARCHITECTURES =3D ANY=0D +#=0D +=0D +=0D +[Sources]=0D + VariablePolicyLib.c=0D + VariablePolicyExtraInitRuntimeDxe.c=0D +=0D +=0D +[Packages]=0D + MdePkg/MdePkg.dec=0D + MdeModulePkg/MdeModulePkg.dec=0D +=0D +=0D +[LibraryClasses]=0D + DebugLib=0D + BaseMemoryLib=0D + MemoryAllocationLib=0D + SafeIntLib=0D + UefiBootServicesTableLib=0D + UefiRuntimeServicesTableLib=0D + PcdLib=0D +=0D +=0D +[Pcd]=0D + gEfiMdeModulePkgTokenSpaceGuid.PcdAllowVariablePolicyEnforcementDisable = ## CONSUMES=0D +=0D +=0D +[Guids]=0D + gEfiEventVirtualAddressChangeGuid=0D diff --git a/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyUnitTest/= VariablePolicyUnitTest.inf b/MdeModulePkg/Library/VariablePolicyLib/Variabl= ePolicyUnitTest/VariablePolicyUnitTest.inf new file mode 100644 index 000000000000..06489f21d604 --- /dev/null +++ b/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyUnitTest/Variabl= ePolicyUnitTest.inf @@ -0,0 +1,45 @@ +## @file VariablePolicyUnitTest.inf=0D +# UnitTest for...=0D +# Business logic for Variable Policy enforcement.=0D +#=0D +# Copyright (c) Microsoft Corporation.=0D +# SPDX-License-Identifier: BSD-2-Clause-Patent=0D +##=0D +=0D +=0D +[Defines]=0D + INF_VERSION =3D 0x00010006=0D + BASE_NAME =3D VariablePolicyUnitTest=0D + FILE_GUID =3D 1200A2E4-D756-418C-9768-528C2D181A98= =0D + MODULE_TYPE =3D HOST_APPLICATION=0D + VERSION_STRING =3D 1.0=0D +=0D +#=0D +# The following information is for reference only and not required by the = build tools.=0D +#=0D +# VALID_ARCHITECTURES =3D IA32 X64 ARM AARCH64=0D +#=0D +=0D +[Sources]=0D + VariablePolicyUnitTest.c=0D +=0D +=0D +[Packages]=0D + MdePkg/MdePkg.dec=0D + MdeModulePkg/MdeModulePkg.dec=0D + UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec=0D +=0D +=0D +[LibraryClasses]=0D + BaseLib=0D + DebugLib=0D + UnitTestLib=0D + PrintLib=0D + VariablePolicyLib=0D + BaseMemoryLib=0D + MemoryAllocationLib=0D +=0D +=0D +[BuildOptions]=0D + MSFT:NOOPT_*_*_CC_FLAGS =3D -DINTERNAL_UNIT_TEST=0D + GCC:NOOPT_*_*_CC_FLAGS =3D -DINTERNAL_UNIT_TEST=0D diff --git a/MdeModulePkg/MdeModulePkg.ci.yaml b/MdeModulePkg/MdeModulePkg.= ci.yaml index 1a7e955185d8..20d53fc5a5fa 100644 --- a/MdeModulePkg/MdeModulePkg.ci.yaml +++ b/MdeModulePkg/MdeModulePkg.ci.yaml @@ -104,7 +104,9 @@ "FVMAIN",=0D "VARCHECKPCD",=0D "Getxx",=0D - "lzturbo"=0D + "lzturbo",=0D + "musthave",=0D + "canthave"=0D ],=0D "AdditionalIncludePaths": [] # Additional paths to spell check rel= ative to package root (wildcards supported)=0D }=0D diff --git a/MdeModulePkg/MdeModulePkg.dec b/MdeModulePkg/MdeModulePkg.dec index 82aecc40d9a9..51c7057bfd1b 100644 --- a/MdeModulePkg/MdeModulePkg.dec +++ b/MdeModulePkg/MdeModulePkg.dec @@ -31,6 +31,9 @@ [LibraryClasses] ## @libraryclass Defines a set of methods to reset whole system.=0D ResetSystemLib|Include/Library/ResetSystemLib.h=0D =0D + ## @libraryclass Business logic for storing and testing variable polic= ies=0D + VariablePolicyLib|Include/Library/VariablePolicyLib.h=0D +=0D ## @libraryclass Defines a set of helper functions for resetting the s= ystem.=0D ResetUtilityLib|Include/Library/ResetUtilityLib.h=0D =0D 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 @@ #=0D # (C) Copyright 2014 Hewlett-Packard Development Company, L.P.
=0D # Copyright (c) 2007 - 2019, Intel Corporation. All rights reserved.
=0D +# Copyright (c) Microsoft Corporation.=0D #=0D # SPDX-License-Identifier: BSD-2-Clause-Patent=0D #=0D @@ -58,6 +59,7 @@ [LibraryClasses] DxeServicesLib|MdePkg/Library/DxeServicesLib/DxeServicesLib.inf=0D DxeServicesTableLib|MdePkg/Library/DxeServicesTableLib/DxeServicesTableL= ib.inf=0D UefiBootManagerLib|MdeModulePkg/Library/UefiBootManagerLib/UefiBootManag= erLib.inf=0D + VariablePolicyLib|MdeModulePkg/Library/VariablePolicyLib/VariablePolicyL= ib.inf=0D #=0D # Generic Modules=0D #=0D @@ -129,6 +131,7 @@ [LibraryClasses.common.DXE_RUNTIME_DRIVER] DebugLib|MdePkg/Library/UefiDebugLibConOut/UefiDebugLibConOut.inf=0D LockBoxLib|MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxDxeLib.inf=0D CapsuleLib|MdeModulePkg/Library/DxeCapsuleLibFmp/DxeRuntimeCapsuleLib.in= f=0D + VariablePolicyLib|MdeModulePkg/Library/VariablePolicyLib/VariablePolicyL= ibRuntimeDxe.inf=0D =0D [LibraryClasses.common.SMM_CORE]=0D HobLib|MdePkg/Library/DxeHobLib/DxeHobLib.inf=0D @@ -306,6 +309,8 @@ [Components] MdeModulePkg/Library/BootLogoLib/BootLogoLib.inf=0D MdeModulePkg/Library/TpmMeasurementLibNull/TpmMeasurementLibNull.inf=0D MdeModulePkg/Library/AuthVariableLibNull/AuthVariableLibNull.inf=0D + MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.inf=0D + MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLibRuntimeDxe.inf=0D MdeModulePkg/Library/VarCheckLib/VarCheckLib.inf=0D MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLib.inf=0D MdeModulePkg/Library/VarCheckPcdLib/VarCheckPcdLib.inf=0D 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] =0D !include UnitTestFrameworkPkg/UnitTestFrameworkPkgHost.dsc.inc=0D =0D +[LibraryClasses]=0D + SafeIntLib|MdePkg/Library/BaseSafeIntLib/BaseSafeIntLib.inf=0D +=0D [Components]=0D MdeModulePkg/Library/DxeResetSystemLib/UnitTest/MockUefiRuntimeServicesT= ableLib.inf=0D =0D #=0D # Build MdeModulePkg HOST_APPLICATION Tests=0D #=0D + MdeModulePkg/Library/VariablePolicyLib/VariablePolicyUnitTest/VariablePo= licyUnitTest.inf {=0D + =0D + VariablePolicyLib|MdeModulePkg/Library/VariablePolicyLib/VariablePol= icyLib.inf=0D +=0D + =0D + gEfiMdeModulePkgTokenSpaceGuid.PcdAllowVariablePolicyEnforcementDisa= ble|TRUE=0D + }=0D +=0D MdeModulePkg/Library/DxeResetSystemLib/UnitTest/DxeResetSystemLibUnitTes= tHost.inf {=0D =0D ResetSystemLib|MdeModulePkg/Library/DxeResetSystemLib/DxeResetSystem= Lib.inf=0D --=20 2.28.0.windows.1