From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-pg1-f177.google.com (mail-pg1-f177.google.com [209.85.215.177]) by mx.groups.io with SMTP id smtpd.web12.8023.1604904384120629979 for ; Sun, 08 Nov 2020 22:46:24 -0800 Authentication-Results: mx.groups.io; dkim=pass header.i=@corthon-com.20150623.gappssmtp.com header.s=20150623 header.b=tqCU5ysk; spf=none, err=permanent DNS error (domain: corthon.com, ip: 209.85.215.177, mailfrom: bret@corthon.com) Received: by mail-pg1-f177.google.com with SMTP id r186so6317931pgr.0 for ; Sun, 08 Nov 2020 22:46:24 -0800 (PST) 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=z+5Q4CajFRvjcieO419Vn9CSlAR/lIrx6y5YWOKvL3Q=; b=tqCU5yskWHIwDZq7iSdCVC7sSPsUCEqTcU/TLRLoGjWo2T7c4tYmVN70niCCnKcQfx yn9GyfqB3S7lSZ1UN6OKojumsrWVDRhHcwxuqzc+tr8I/En+Azvb15w8bxN6KMO+UZNy gIYPHH0YH7rY81uxYMNvHw+hVq0zwF8G0a0VCDgno/2M/gFUrGBdre2AsftturoAOUjS gGbACxlz2OalADYdY8M8+ObL1fYY25kV7Urr+bp1HpEUaQvNWXEf/ltXHxfZ7Ry+ttj8 a4V/hOchZgEn/zmVGvL5geMjCENvxvli8QocAfvXuABy/Jqq4NoGpVWAMfjDrLfrZR+C 6dTg== 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=z+5Q4CajFRvjcieO419Vn9CSlAR/lIrx6y5YWOKvL3Q=; b=M4hXw0rgMa6eeoU2XB7AS4NJljFCiA2I5XMYY5yfUMmDPiW/KZLA51WWlsUKciAd3x r3wkrHSIu/MWlb2t4EFnqA1uniQxhNRZpEyD4+2vrYSHxXQalUTxuMPmIPm3rWfwjfYv wxIbGf/x6Et6sIKiGhQRxDUYSqo35Bb5N6McaqyJwJGdRPrTC8leJEgkZdKKvYUYNHLe kufz/IT2ZDyV2t3xoDuo62JGmTDX6emNWDfyACO4XGbLzXM+TjCubcym0LRrqL079HQq TEvDtexdJGFokbaYsbifzakMmEEDrCsuCqlugH+IxM8L2pfaJSM19C+X6dyPzj29L2d4 tKXw== X-Gm-Message-State: AOAM53362chqrrddiefGG+Xs27G6KEmlATLWum2Yf1C7cSEfog3nHWjK xsNraPMBhFBudYRFMptAcv2KoEP0KWDl8JWn X-Google-Smtp-Source: ABdhPJxL6pX5mkxxzpHlmsOFj5m1RTukPON9guQRrt5L6ogkJSfLscDMQRVLBvEVaT5ziM7o8I3PEQ== X-Received: by 2002:a62:ee06:0:b029:164:20d:183b with SMTP id e6-20020a62ee060000b0290164020d183bmr12725132pfi.4.1604904382988; Sun, 08 Nov 2020 22:46:22 -0800 (PST) Return-Path: Received: from localhost.localdomain ([71.212.128.184]) by smtp.gmail.com with ESMTPSA id s145sm10215111pfs.187.2020.11.08.22.46.22 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 08 Nov 2020 22:46:22 -0800 (PST) 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 v9 02/13] MdeModulePkg: Define the VariablePolicyLib Date: Sun, 8 Nov 2020 22:45:11 -0800 Message-Id: <20201109064522.919-3-bret.barkelew@microsoft.com> X-Mailer: git-send-email 2.28.0.windows.1 In-Reply-To: <20201109064522.919-1-bret.barkelew@microsoft.com> References: <20201109064522.919-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/Include/Library/VariablePolicyLib.h = | 207 +++++ MdeModulePkg/Library/VariablePolicyLib/ReadMe.md = | 406 ++++++++++ MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.inf = | 48 ++ MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.uni = | 12 + MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLibRuntimeDxe.inf = | 51 ++ MdeModulePkg/MdeModulePkg.ci.yaml = | 4 +- MdeModulePkg/MdeModulePkg.dec = | 3 + MdeModulePkg/MdeModulePkg.dsc = | 5 + 11 files changed, 1696 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/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..c2f9850a12ca --- /dev/null +++ b/MdeModulePkg/Library/VariablePolicyLib/ReadMe.md @@ -0,0 +1,406 @@ +---=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 +There is a test that can be run as part of the Host-Based Unit Testing=0D +infrastructure provided by EDK2 PyTools (documented elsewhere). It will te= st=0D +all internal guarantees and is where you will find test cases for most of = the=0D +policy matching and security of the 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..3fe6043bf631 --- /dev/null +++ b/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.inf @@ -0,0 +1,48 @@ +## @file VariablePolicyLib.inf=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 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/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 fbbc9933f5e8..3c8bf8009c55 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 --=20 2.28.0.windows.1