From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from NAM12-BN8-obe.outbound.protection.outlook.com (NAM12-BN8-obe.outbound.protection.outlook.com [40.92.21.88]) by mx.groups.io with SMTP id smtpd.web11.3104.1590101055061938361 for ; Thu, 21 May 2020 15:44:15 -0700 Authentication-Results: mx.groups.io; dkim=fail reason="body hash did not verify" header.i=@outlook.com header.s=selector1 header.b=T/HD7mFU; spf=pass (domain: outlook.com, ip: 40.92.21.88, mailfrom: michael.kubacki@outlook.com) ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=ZXNp/ipg8SNva9Iv7esRr37l/0+MjaM7kD9klOLR2dq5M519h9p6zKmGSxeHMbIc+rFYClqvVlZxzx1taMc0GEhXzcXPtJJLsktxdfPx0SO0nhKk6ZCgy4G6KJq4O/Ex3obqXLREdUdA7IgnsmCUZY76/6BCdkFSBqfqBSLTG/dg0471tRsy48vCTD5CUQMzAAh/cr3ls3hcfo+eUya44fI+lqWuxvrwHf+pLi/Mv4hdX1ylKi/Xia0kYJgejm8AZELoSVMT5fi9HFzeQgA62BSiyHo7eUhjl+/19KBZU13gb5CiPUCBHzVjObqEH3O9HXAfqm4VhuIujsy9Zzn7VQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=Os3daG2bhB+g8UeA1YllaTUHtcCDibIx5RNiYhrSBeU=; b=PHei22KD0YL1IbpQF+vRZiD1uxkWLAeNmQUzbz00ErdryY14eF9EZRPTNCyGORdetE//o2ErGs0UzcMln6SCmlXWDd7SweRz0X3j7ZZ8oqrW7YdVt6eOZMDsbFDTTH01iByvKsuuWVbeLtBVkjD8ZXwMH4WGBnspXDF1bhVqPKoCMTEPXO68DqOUyouYzm0esyWlrnTevrGYtBRBvI2BLRRQY9psOWDzbtlmS859BXPqS5X+8UGfPNxJdF8xwes3E1J4wc85PGxqPwPNRstDbPIS0XadWnMW/lpjdWDZyWlalRet4t3fUGMEZkHK+/bCwKkL5nGPmLY5ZEMLrrVwMQ== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=outlook.com; dmarc=pass action=none header.from=outlook.com; dkim=pass header.d=outlook.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=outlook.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=Os3daG2bhB+g8UeA1YllaTUHtcCDibIx5RNiYhrSBeU=; b=T/HD7mFU+Hnc0+vzrrT/5mLM+ZEFZMnNRovlFxKL5KK6l37VctClL+tL/sSZCRaC+x+ae69/+LBubJsJ5Bcad5Mfnn1WRYErL80EUwVruh/5AHhPR0q8ir4Mo2uqf502qOuUgrZib/ap8Pwi/7H/5tqP2uHAFDxF8NRZSh4f7R4d9pv878dHMdJoGYSWsYqVOPlw/81gIF4O2n7dp/Qp9Kvfa5CIEXf7QHHmswAJgJRwPt4mohPq2f0r5aShCdXfPNYWKR2IKRir0Yi/0h1MIIAmQQmK3ABR2QJJmxWp3e9L/DbuclI4aRRFdkmau1WKLMfXsY+dblH9N3rFGeibog== Received: from MW2NAM12FT062.eop-nam12.prod.protection.outlook.com (2a01:111:e400:fc65::46) by MW2NAM12HT176.eop-nam12.prod.protection.outlook.com (2a01:111:e400:fc65::294) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3021.11; Thu, 21 May 2020 22:44:13 +0000 Received: from MWHPR07MB3440.namprd07.prod.outlook.com (2a01:111:e400:fc65::50) by MW2NAM12FT062.mail.protection.outlook.com (2a01:111:e400:fc65::370) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3021.11 via Frontend Transport; Thu, 21 May 2020 22:44:13 +0000 X-IncomingTopHeaderMarker: OriginalChecksum:9BD65F5C971124B248B8118361EE2F2A8D8226EDBBB66620A8DD6729D4AEBF00;UpperCasedChecksum:20BA830C425EF824756230ECE0F836BE5557B206966F334FF9239E0C75E6BC8B;SizeAsReceived:7842;Count:50 Received: from MWHPR07MB3440.namprd07.prod.outlook.com ([fe80::bcc9:271b:20db:52e3]) by MWHPR07MB3440.namprd07.prod.outlook.com ([fe80::bcc9:271b:20db:52e3%6]) with mapi id 15.20.3021.020; Thu, 21 May 2020 22:44:13 +0000 From: "Michael Kubacki" To: devel@edk2.groups.io CC: Jian J Wang , Hao A Wu , Liming Gao , Bret Barkelew Subject: [PATCH v3 02/14] MdeModulePkg: Define the VariablePolicyLib Date: Thu, 21 May 2020 15:43:19 -0700 Message-ID: X-Mailer: git-send-email 2.16.3.windows.1 In-Reply-To: <20200521224331.15616-1-michael.kubacki@outlook.com> References: <20200521224331.15616-1-michael.kubacki@outlook.com> X-ClientProxiedBy: MWHPR12CA0071.namprd12.prod.outlook.com (2603:10b6:300:103::33) To MWHPR07MB3440.namprd07.prod.outlook.com (2603:10b6:301:69::28) Return-Path: michael.kubacki@outlook.com X-Microsoft-Original-Message-ID: <20200521224331.15616-3-michael.kubacki@outlook.com> MIME-Version: 1.0 X-MS-Exchange-MessageSentRepresentingType: 1 Received: from localhost.localdomain (2001:4898:80e8:1:2c94:8481:fffa:8ac5) by MWHPR12CA0071.namprd12.prod.outlook.com (2603:10b6:300:103::33) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3021.23 via Frontend Transport; Thu, 21 May 2020 22:44:12 +0000 X-Mailer: git-send-email 2.16.3.windows.1 X-Microsoft-Original-Message-ID: <20200521224331.15616-3-michael.kubacki@outlook.com> X-TMN: [V+l+rOLwvVRdISI7yOY323qZqzN+UsDlHruWN71te7IefQMVnObpmztdvauv+dFj] X-MS-PublicTrafficType: Email X-IncomingHeaderCount: 50 X-EOPAttributedMessage: 0 X-MS-Office365-Filtering-Correlation-Id: 9297c0be-2408-4f06-0dc1-08d7fdd87b97 X-MS-TrafficTypeDiagnostic: MW2NAM12HT176: X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: Jiflz6XNIfD/W008jpw9XdjWRzvZ40JpHoTgIxlzlzoeZbZAq8L3QjO+iJmLlYLGISl9Pg25CVeYi2/nFvnt7UGpzrF7lnx35hC2mlKRfvd2RGOZTuDLdfBnGy4SnqPnp/BOg+QYO7yiao47hICg4zoPyvD4txAQNzTZrf2yQDQnq1KC+5eSwozj2kz7Ch7Ezd11qmZSKUItiBhNW0zT5E5fFZkdk1nJX5xWcdKcftymUc1GzN1Au1ikKxZ5WB3J X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:0;SRV:;IPV:NLI;SFV:NSPM;H:MWHPR07MB3440.namprd07.prod.outlook.com;PTR:;CAT:NONE;SFTY:;SFS:;DIR:OUT;SFP:1901; X-MS-Exchange-AntiSpam-MessageData: mtx1loXyT5H9ApnPvii09Fd+35LhQQ9Ak0HuAseHWDnqv4exk3F7Y9uFtKxvUwZGghcyns0y53rIY8vghojF7X2jM6ycp7B775vUgBirTHaFEOx2C+FDID1bM6Rs9u3Z9R2IthX8OCA6YsnvEMYTLFD5+jFoze2cbeLQF92ZrueU54sqCttUanvWH/EPeEQ8Ks6XtcnQTyt//fxc3Ta7tA== X-OriginatorOrg: outlook.com X-MS-Exchange-CrossTenant-Network-Message-Id: 9297c0be-2408-4f06-0dc1-08d7fdd87b97 X-MS-Exchange-CrossTenant-OriginalArrivalTime: 21 May 2020 22:44:13.2020 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 84df9e7f-e9f6-40af-b435-aaaaaaaaaaaa X-MS-Exchange-CrossTenant-FromEntityHeader: Internet X-MS-Exchange-CrossTenant-RMS-PersistedConsumerOrg: 00000000-0000-0000-0000-000000000000 X-MS-Exchange-Transport-CrossTenantHeadersStamped: MW2NAM12HT176 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain 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: Michael Kubacki --- MdeModulePkg/Library/VariablePolicyLib/VariablePolicyExtraInitNull.c = | 46 + MdeModulePkg/Library/VariablePolicyLib/VariablePolicyExtraInitRuntimeDxe.c= | 86 + MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.c = | 830 +++++++ MdeModulePkg/Library/VariablePolicyLib/VariablePolicyUnitTest/VariablePoli= cyUnitTest.c | 2533 ++++++++++++++++++++ MdeModulePkg/Include/Library/VariablePolicyLib.h = | 207 ++ MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.inf = | 44 + MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.uni = | 12 + MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLibRuntimeDxe.inf = | 51 + MdeModulePkg/Library/VariablePolicyLib/VariablePolicyUnitTest/VariablePoli= cyUnitTest.inf | 40 + MdeModulePkg/MdeModulePkg.dec = | 3 + MdeModulePkg/MdeModulePkg.dsc = | 5 + MdeModulePkg/Test/MdeModulePkgHostTest.dsc = | 11 + 12 files changed, 3868 insertions(+) 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 +This file contains extra init and deinit routines that don't do anything +extra. + +Copyright (c) Microsoft Corporation. +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include + + +/** + An extra init hook that enables the RuntimeDxe library instance to + register VirtualAddress change callbacks. Among other things. + + @retval EFI_SUCCESS Everything is good. Continue with init. + @retval Others Uh... don't continue. + +**/ +EFI_STATUS +VariablePolicyExtraInit ( + VOID + ) +{ + // NULL implementation. + return EFI_SUCCESS; +} + + +/** + An extra deinit hook that enables the RuntimeDxe library instance to + register VirtualAddress change callbacks. Among other things. + + @retval EFI_SUCCESS Everything is good. Continue with deinit. + @retval Others Uh... don't continue. + +**/ +EFI_STATUS +VariablePolicyExtraDeinit ( + VOID + ) +{ + // NULL implementation. + return EFI_SUCCESS; +} diff --git a/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyExtraInit= RuntimeDxe.c b/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyExtraIn= itRuntimeDxe.c new file mode 100644 index 000000000000..43418dd0409d --- /dev/null +++ b/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyExtraInitRuntime= Dxe.c @@ -0,0 +1,86 @@ +/** @file -- VariablePolicyExtraInitRuntimeDxe.c +This file contains extra init and deinit routines that register and unregi= ster +VariableAddressChange callbacks. + +Copyright (c) Microsoft Corporation. +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include + +extern EFI_GET_VARIABLE mGetVariableHelper; +extern UINT8 *mPolicyTable; +STATIC BOOLEAN mIsVirtualAddrConverted; +STATIC EFI_EVENT mVariablePolicyLibVirtualAddressChangeEvent =3D= NULL; + +/** + For the RuntimeDxe version of this lib, convert internal pointer address= es to virtual addresses. + + @param[in] Event Event whose notification function is being invoked= . + @param[in] Context The pointer to the notification function's context= , which + is implementation-dependent. +**/ +STATIC +VOID +EFIAPI +VariablePolicyLibVirtualAddressCallback ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + gRT->ConvertPointer (0, (VOID **) &mPolicyTable); + gRT->ConvertPointer (0, (VOID **) &mGetVariableHelper); + mIsVirtualAddrConverted =3D TRUE; +} + + +/** + An extra init hook that enables the RuntimeDxe library instance to + register VirtualAddress change callbacks. Among other things. + + @retval EFI_SUCCESS Everything is good. Continue with init. + @retval Others Uh... don't continue. + +**/ +EFI_STATUS +VariablePolicyExtraInit ( + VOID + ) +{ + return gBS->CreateEventEx ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + VariablePolicyLibVirtualAddressCallback, + NULL, + &gEfiEventVirtualAddressChangeGuid, + &mVariablePolicyLibVirtualAddressChangeEvent + ); +} + + +/** + An extra deinit hook that enables the RuntimeDxe library instance to + register VirtualAddress change callbacks. Among other things. + + @retval EFI_SUCCESS Everything is good. Continue with deinit. + @retval Others Uh... don't continue. + +**/ +EFI_STATUS +VariablePolicyExtraDeinit ( + VOID + ) +{ + EFI_STATUS Status; + + Status =3D EFI_SUCCESS; + if (mIsVirtualAddrConverted) { + Status =3D gBS->CloseEvent (mVariablePolicyLibVirtualAddressChangeEven= t); + } else { + Status =3D EFI_SUCCESS; + } + + return Status; +} diff --git a/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.c b/M= deModulePkg/Library/VariablePolicyLib/VariablePolicyLib.c new file mode 100644 index 000000000000..201c5e393a60 --- /dev/null +++ b/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.c @@ -0,0 +1,830 @@ +/** @file -- VariablePolicyLib.c +Business logic for Variable Policy enforcement. + +Copyright (c) Microsoft Corporation. +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include + +#include +#include +#include +#include +#include + +#include +#include + + +// IMPORTANT NOTE: This library is currently rife with multiple return sta= tements +// for error handling. A refactor should remove these at s= ome point. + +// +// This library was designed with advanced unit-test features. +// This define handles the configuration. +#ifdef INTERNAL_UNIT_TEST +#undef STATIC +#define STATIC // Nothing... +#endif + +// An abstracted GetVariable interface that enables configuration regardle= ss of the environment. +EFI_GET_VARIABLE mGetVariableHelper =3D NULL; + +// Master switch to lock this entire interface. Does not stop enforcement, +// just prevents the configuration from being changed for the rest of the = boot. +STATIC BOOLEAN mInterfaceLocked =3D FALSE; + +// Master switch to disable the entire interface for a single boot. +// This will disable all policy enforcement for the duration of the boot. +STATIC BOOLEAN mProtectionDisabled =3D FALSE; + +// Table to hold all the current policies. +UINT8 *mPolicyTable =3D NULL; +STATIC UINT32 mCurrentTableSize =3D 0; +STATIC UINT32 mCurrentTableUsage =3D 0; +STATIC UINT32 mCurrentTableCount =3D 0; + +#define POLICY_TABLE_STEP_SIZE 0x1000 + +// NOTE: DO NOT USE THESE MACROS on any structure that has not been valida= ted. +// Current table data has already been sanitized. +#define GET_NEXT_POLICY(CurPolicy) (VARIABLE_POLICY_ENTRY *)((UINT8 *) = CurPolicy + CurPolicy->Size) +#define GET_POLICY_NAME(CurPolicy) (CHAR16 *)((UINTN) CurPolicy + CurPo= licy->OffsetToName) + +#define MATCH_PRIORITY_EXACT 0 +#define MATCH_PRIORITY_MAX MATCH_PRIORITY_EXACT +#define MATCH_PRIORITY_MIN MAX_UINT8 + +// ExtraInit/ExtraDeinit functions allow RuntimeDxe to register VirtualAdd= ress callbacks. +EFI_STATUS +VariablePolicyExtraInit ( + VOID + ); + +EFI_STATUS +VariablePolicyExtraDeinit ( + VOID + ); + + +/** + This helper function determines whether the structure of an incoming pol= icy + is valid and internally consistent. + + @param[in] NewPolicy Pointer to the incoming policy structure. + + @retval TRUE + @retval FALSE Pointer is NULL, size is wrong, strings are empty, o= r + substructures overlap. + +**/ +STATIC +BOOLEAN +IsValidVariablePolicyStructure ( + IN CONST VARIABLE_POLICY_ENTRY *NewPolicy + ) +{ + EFI_STATUS Status; + UINTN EntryEnd; + CHAR16 *CheckChar; + UINTN WildcardCount; + + // Sanitize some quick values. + if (NewPolicy =3D=3D NULL || NewPolicy->Size =3D=3D 0 || + // Structure size should be at least as long as the minumum structur= e and a NULL string. + NewPolicy->Size < sizeof (VARIABLE_POLICY_ENTRY) || + // Check for the known revision. + NewPolicy->Version !=3D VARIABLE_POLICY_ENTRY_REVISION) { + return FALSE; + } + + // Calculate the theoretical end of the structure and make sure + // that the structure can fit in memory. + Status =3D SafeUintnAdd ((UINTN) NewPolicy, NewPolicy->Size, &EntryEnd); + if (EFI_ERROR (Status)) { + return FALSE; + } + + // Check for a valid Max Size. + if (NewPolicy->MaxSize =3D=3D 0) { + return FALSE; + } + + // Check for the valid list of lock policies. + if (NewPolicy->LockPolicyType !=3D VARIABLE_POLICY_TYPE_NO_LOCK && + NewPolicy->LockPolicyType !=3D VARIABLE_POLICY_TYPE_LOCK_NOW && + NewPolicy->LockPolicyType !=3D VARIABLE_POLICY_TYPE_LOCK_ON_CREATE &= & + NewPolicy->LockPolicyType !=3D VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STAT= E) { + return FALSE; + } + + // If the policy type is VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE, make su= re that the matching state variable Name + // terminates before the OffsetToName for the matching policy variable N= ame. + if (NewPolicy->LockPolicyType =3D=3D VARIABLE_POLICY_TYPE_LOCK_ON_VAR_ST= ATE) { + // Adjust CheckChar to the offset of the LockPolicy->Name. + Status =3D SafeUintnAdd ( + (UINTN) NewPolicy + sizeof (VARIABLE_POLICY_ENTRY), + sizeof (VARIABLE_LOCK_ON_VAR_STATE_POLICY), + (UINTN *) &CheckChar + ); + if (EFI_ERROR (Status) || EntryEnd <=3D (UINTN) CheckChar) { + return FALSE; + } + + while (*CheckChar !=3D CHAR_NULL) { + if (EntryEnd <=3D (UINTN) CheckChar) { + return FALSE; + } + CheckChar++; + } + + // At this point we should have either exceeded the structure or be po= inting at the last char in LockPolicy->Name. + // We should check to make sure that the policy Name comes immediately= after this character. + if ((UINTN) ++CheckChar !=3D (UINTN) NewPolicy + NewPolicy->OffsetToNa= me) { + return FALSE; + } + } else { + // If the policy type is any other value, make sure that the LockPolic= y structure has a zero length. + if (NewPolicy->OffsetToName !=3D sizeof (VARIABLE_POLICY_ENTRY)) { + return FALSE; + } + } + + // Check to make sure that the name has a terminating character + // before the end of the structure. + // We've already checked that the name is within the bounds of the struc= ture. + if (NewPolicy->Size !=3D NewPolicy->OffsetToName) { + CheckChar =3D (CHAR16 *) ((UINTN) NewPolicy + NewPolicy->OffsetToName)= ; + WildcardCount =3D 0; + while (*CheckChar !=3D CHAR_NULL) { + // Make sure there aren't excessive wildcards. + if (*CheckChar =3D=3D '#') { + WildcardCount++; + if (WildcardCount > MATCH_PRIORITY_MIN) { + return FALSE; + } + } + // Make sure you're still within the bounds of the policy structure. + if (EntryEnd <=3D (UINTN) CheckChar) { + return FALSE; + } + CheckChar++; + } + + // Finally, we should be pointed at the very last character in Name, s= o we should be right + // up against the end of the structure. + if ((UINTN) ++CheckChar !=3D EntryEnd) { + return FALSE; + } + } + + return TRUE; +} + + +/** + This helper function evaluates a policy and determines whether it matche= s the target + variable. If matched, will also return a value corresponding to the prio= rity of the match. + + The rules for "best match" are listed in the Variable Policy Spec. + Perfect name matches will return 0. + Single wildcard characters will return the number of wildcard characters= . + Full namespaces will return MAX_UINT8. + + @param[in] EvalEntry Pointer to the policy entry being evaluate= d. + @param[in] VariableName Same as EFI_SET_VARIABLE. + @param[in] VendorGuid Same as EFI_SET_VARIABLE. + @param[out] MatchPriority [Optional] On finding a match, this value = contains the priority of the match. + Lower number =3D=3D higher priority. Only = valid if a match found. + + @retval TRUE Current entry matches the target variable. + @retval FALSE Current entry does not match at all. + +**/ +STATIC +BOOLEAN +EvaluatePolicyMatch ( + IN CONST VARIABLE_POLICY_ENTRY *EvalEntry, + IN CONST CHAR16 *VariableName, + IN CONST EFI_GUID *VendorGuid, + OUT UINT8 *MatchPriority OPTIONAL + ) +{ + BOOLEAN Result; + CHAR16 *PolicyName; + UINT8 CalculatedPriority; + UINTN Index; + + Result =3D FALSE; + CalculatedPriority =3D MATCH_PRIORITY_EXACT; + + // Step 1: If the GUID doesn't match, we're done. No need to evaluate an= ything else. + if (!CompareGuid (&EvalEntry->Namespace, VendorGuid)) { + goto Exit; + } + + // If the GUID matches, check to see whether there is a Name associated + // with the policy. If not, this policy matches the entire namespace. + // Missing Name is indicated by size being equal to name. + if (EvalEntry->Size =3D=3D EvalEntry->OffsetToName) { + CalculatedPriority =3D MATCH_PRIORITY_MIN; + Result =3D TRUE; + goto Exit; + } + + // Now that we know the name exists, get it. + PolicyName =3D GET_POLICY_NAME (EvalEntry); + + // Evaluate the name against the policy name and check for a match. + // Account for any wildcards. + Index =3D 0; + Result =3D TRUE; + // Keep going until the end of both strings. + while (PolicyName[Index] !=3D CHAR_NULL || VariableName[Index] !=3D CHAR= _NULL) { + // If we don't have a match... + if (PolicyName[Index] !=3D VariableName[Index] || PolicyName[Index] = =3D=3D '#') { + // If this is a numerical wildcard, we can consider + // it a match if we alter the priority. + if (PolicyName[Index] =3D=3D L'#' && + (L'0' <=3D VariableName[Index] && VariableName[Index] <=3D L'9')= ) { + if (CalculatedPriority < MATCH_PRIORITY_MIN) { + CalculatedPriority++; + } + } else { + // Otherwise, not a match. + Result =3D FALSE; + goto Exit; + } + } + Index++; + } + +Exit: + if (Result && MatchPriority !=3D NULL) { + *MatchPriority =3D CalculatedPriority; + } + return Result; +} + + +/** + This helper function walks the current policy table and returns a pointe= r + to the best match, if any are found. Leverages EvaluatePolicyMatch() to + determine "best". + + @param[in] VariableName Same as EFI_SET_VARIABLE. + @param[in] VendorGuid Same as EFI_SET_VARIABLE. + @param[out] ReturnPriority [Optional] If pointer is provided, return= the + priority of the match. Same as EvaluatePo= licyMatch(). + Only valid if a match is returned. + + @retval VARIABLE_POLICY_ENTRY* Best match that was found. + @retval NULL No match was found. + +**/ +STATIC +VARIABLE_POLICY_ENTRY* +GetBestPolicyMatch ( + IN CONST CHAR16 *VariableName, + IN CONST EFI_GUID *VendorGuid, + OUT UINT8 *ReturnPriority OPTIONAL + ) +{ + VARIABLE_POLICY_ENTRY *BestResult; + VARIABLE_POLICY_ENTRY *CurrentEntry; + UINT8 MatchPriority; + UINT8 CurrentPriority; + UINTN Index; + + BestResult =3D NULL; + + // Walk all entries in the table, looking for matches. + CurrentEntry =3D (VARIABLE_POLICY_ENTRY *) mPolicyTable; + for (Index =3D 0; Index < mCurrentTableCount; Index++) { + // Check for a match. + if (EvaluatePolicyMatch (CurrentEntry, VariableName, VendorGuid, &Curr= entPriority)) { + // If match is better, take it. + if (BestResult =3D=3D NULL || CurrentPriority < MatchPriority) { + BestResult =3D CurrentEntry; + MatchPriority =3D CurrentPriority; + } + + // If you've hit the highest-priority match, can exit now. + if (MatchPriority =3D=3D 0) { + break; + } + } + + // If we're still in the loop, move to the next entry. + CurrentEntry =3D GET_NEXT_POLICY (CurrentEntry); + } + + // If a return priority was requested, return it. + if (ReturnPriority !=3D NULL) { + *ReturnPriority =3D MatchPriority; + } + + return BestResult; +} + + +/** + This API function validates and registers a new policy with + the policy enforcement engine. + + @param[in] NewPolicy Pointer to the incoming policy structure. + + @retval EFI_SUCCESS + @retval EFI_INVALID_PARAMETER NewPolicy is NULL or is internally i= nconsistent. + @retval EFI_ALREADY_STARTED An identical matching policy already= exists. + @retval EFI_WRITE_PROTECTED The interface has been locked until = the next reboot. + @retval EFI_UNSUPPORTED Policy enforcement has been disabled= . No reason to add more policies. + @retval EFI_ABORTED A calculation error has prevented th= is function from completing. + @retval EFI_OUT_OF_RESOURCES Cannot grow the table to hold any mo= re policies. + @retval EFI_NOT_READY Library has not yet been initialized= . + +**/ +EFI_STATUS +EFIAPI +RegisterVariablePolicy ( + IN CONST VARIABLE_POLICY_ENTRY *NewPolicy + ) +{ + EFI_STATUS Status; + VARIABLE_POLICY_ENTRY *MatchPolicy; + UINT8 MatchPriority; + UINT32 NewSize; + UINT8 *NewTable; + + if (!IsVariablePolicyLibInitialized ()) { + return EFI_NOT_READY; + } + if (mInterfaceLocked) { + return EFI_WRITE_PROTECTED; + } + + if (!IsValidVariablePolicyStructure (NewPolicy)) { + return EFI_INVALID_PARAMETER; + } + + // Check to see whether an exact matching policy already exists. + MatchPolicy =3D GetBestPolicyMatch ( + GET_POLICY_NAME (NewPolicy), + &NewPolicy->Namespace, + &MatchPriority + ); + if (MatchPolicy !=3D NULL && MatchPriority =3D=3D MATCH_PRIORITY_EXACT) = { + return EFI_ALREADY_STARTED; + } + + // If none exists, create it. + // If we need more space, allocate that now. + Status =3D SafeUint32Add (mCurrentTableUsage, NewPolicy->Size, &NewSize)= ; + if (EFI_ERROR (Status)) { + return EFI_ABORTED; + } + if (NewSize > mCurrentTableSize) { + // Use NewSize to calculate the new table size in units of POLICY_TABL= E_STEP_SIZE. + NewSize =3D ( + NewSize % POLICY_TABLE_STEP_SIZE) > 0 ? + (NewSize / POLICY_TABLE_STEP_SIZE) + 1 : + (NewSize / POLICY_TABLE_STEP_SIZE + ); + + // Calculate the new table size in absolute bytes. + Status =3D SafeUint32Mult (NewSize, POLICY_TABLE_STEP_SIZE, &NewSize); + if (EFI_ERROR (Status)) { + return EFI_ABORTED; + } + + // Reallocate and copy the table. + NewTable =3D AllocatePool (NewSize); + if (NewTable =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + CopyMem (NewTable, mPolicyTable, mCurrentTableUsage); + mCurrentTableSize =3D NewSize; + if (mPolicyTable !=3D NULL) { + FreePool (mPolicyTable); + } + mPolicyTable =3D NewTable; + } + + // Copy the policy into the table. + CopyMem (mPolicyTable + mCurrentTableUsage, NewPolicy, NewPolicy->Size); + mCurrentTableUsage +=3D NewPolicy->Size; + mCurrentTableCount +=3D 1; + + // We're done here. + + return EFI_SUCCESS; +} + + +/** + This API function checks to see whether the parameters to SetVariable wo= uld + be allowed according to the current variable policies. + + @param[in] VariableName Same as EFI_SET_VARIABLE. + @param[in] VendorGuid Same as EFI_SET_VARIABLE. + @param[in] Attributes Same as EFI_SET_VARIABLE. + @param[in] DataSize Same as EFI_SET_VARIABLE. + @param[in] Data Same as EFI_SET_VARIABLE. + + @retval EFI_SUCCESS A matching policy allows this update= . + @retval EFI_SUCCESS There are currently no policies that= restrict this update. + @retval EFI_SUCCESS The protections have been disable un= til the next reboot. + @retval EFI_WRITE_PROTECTED Variable is currently locked. + @retval EFI_INVALID_PARAMETER Attributes or size are invalid. + @retval EFI_ABORTED A lock policy exists, but an error p= revented evaluation. + @retval EFI_NOT_READY Library has not been initialized. + +**/ +EFI_STATUS +EFIAPI +ValidateSetVariable ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN UINT32 Attributes, + IN UINTN DataSize, + IN VOID *Data + ) +{ + BOOLEAN IsDel; + VARIABLE_POLICY_ENTRY *ActivePolicy; + EFI_STATUS Status; + EFI_STATUS ReturnStatus; + VARIABLE_LOCK_ON_VAR_STATE_POLICY *StateVarPolicy; + CHAR16 *StateVarName; + UINTN StateVarSize; + UINT8 StateVar; + + ReturnStatus =3D EFI_SUCCESS; + + if (!IsVariablePolicyLibInitialized ()) { + ReturnStatus =3D EFI_NOT_READY; + goto Exit; + } + + // Bail if the protections are currently disabled. + if (mProtectionDisabled) { + ReturnStatus =3D EFI_SUCCESS; + goto Exit; + } + + // Determine whether this is a delete operation. + // If so, it will affect which tests are applied. + if ((DataSize =3D=3D 0) && ((Attributes & EFI_VARIABLE_APPEND_WRITE) =3D= =3D 0)) { + IsDel =3D TRUE; + } + else { + IsDel =3D FALSE; + } + + // Find an active policy if one exists. + ActivePolicy =3D GetBestPolicyMatch (VariableName, VendorGuid, NULL); + + // If we have an active policy, check it against the incoming data. + if (ActivePolicy !=3D NULL) { + // + // Only enforce size and attribute constraints when updating data, not= deleting. + if (!IsDel) { + // Check for size constraints. + if ((ActivePolicy->MinSize > 0 && DataSize < ActivePolicy->MinSize) = || + (ActivePolicy->MaxSize > 0 && DataSize > ActivePolicy->MaxSize))= { + ReturnStatus =3D EFI_INVALID_PARAMETER; + DEBUG (( + DEBUG_VERBOSE, + "%a - Bad Size. 0x%X <> 0x%X-0x%X\n", + __FUNCTION__, + DataSize, + ActivePolicy->MinSize, + ActivePolicy->MaxSize + )); + goto Exit; + } + + // Check for attribute constraints. + if ((ActivePolicy->AttributesMustHave & Attributes) !=3D ActivePolic= y->AttributesMustHave || + (ActivePolicy->AttributesCantHave & Attributes) !=3D 0) { + ReturnStatus =3D EFI_INVALID_PARAMETER; + DEBUG (( + DEBUG_VERBOSE, + "%a - Bad Attributes. 0x%X <> 0x%X:0x%X\n", + __FUNCTION__, + Attributes, + ActivePolicy->AttributesMustHave, + ActivePolicy->AttributesCantHave + )); + goto Exit; + } + } + + // + // Lock policy check. + // + if (ActivePolicy->LockPolicyType =3D=3D VARIABLE_POLICY_TYPE_LOCK_NOW)= { + ReturnStatus =3D EFI_WRITE_PROTECTED; + goto Exit; + } else if (ActivePolicy->LockPolicyType =3D=3D VARIABLE_POLICY_TYPE_LO= CK_ON_CREATE) { + StateVarSize =3D 0; + Status =3D mGetVariableHelper ( + VariableName, + VendorGuid, + NULL, + &StateVarSize, + NULL + ); + if (Status =3D=3D EFI_BUFFER_TOO_SMALL) { + ReturnStatus =3D EFI_WRITE_PROTECTED; + goto Exit; + } + } else if (ActivePolicy->LockPolicyType =3D=3D VARIABLE_POLICY_TYPE_LO= CK_ON_VAR_STATE) { + StateVarPolicy =3D (VARIABLE_LOCK_ON_VAR_STATE_POLICY *) ((UINT8 *) = ActivePolicy + sizeof (VARIABLE_POLICY_ENTRY)); + StateVarName =3D (CHAR16 *) ((UINT8 *) StateVarPolicy + sizeof (VARI= ABLE_LOCK_ON_VAR_STATE_POLICY)); + StateVarSize =3D sizeof (StateVar); + Status =3D mGetVariableHelper ( + StateVarName, + &StateVarPolicy->Namespace, + NULL, + &StateVarSize, + &StateVar + ); + + // If the variable was found, check the state. If matched, this vari= able is locked. + if (!EFI_ERROR (Status)) { + if (StateVar =3D=3D StateVarPolicy->Value) { + ReturnStatus =3D EFI_WRITE_PROTECTED; + goto Exit; + } + } else if (Status !=3D EFI_NOT_FOUND && Status !=3D EFI_BUFFER_TOO_S= MALL) { + // EFI_NOT_FOUND and EFI_BUFFER_TOO_SMALL indicate that the state = doesn't match. + // We don't know what happened, but it isn't good. + ReturnStatus =3D EFI_ABORTED; + goto Exit; + } + } + } + +Exit: + DEBUG ((DEBUG_VERBOSE, "%a - Variable (%g:%s) returning %r.\n", __FUNCTI= ON__, VendorGuid, VariableName, ReturnStatus)); + return ReturnStatus; +} + + +/** + This API function disables the variable policy enforcement. If it's + already been called once, will return EFI_ALREADY_STARTED. + + @retval EFI_SUCCESS + @retval EFI_ALREADY_STARTED Has already been called once this boot= . + @retval EFI_WRITE_PROTECTED Interface has been locked until reboot= . + @retval EFI_WRITE_PROTECTED Interface option is disabled by platfo= rm PCD. + @retval EFI_NOT_READY Library has not yet been initialized. + +**/ +EFI_STATUS +EFIAPI +DisableVariablePolicy ( + VOID + ) +{ + if (!IsVariablePolicyLibInitialized ()) { + return EFI_NOT_READY; + } + if (mProtectionDisabled) { + return EFI_ALREADY_STARTED; + } + if (mInterfaceLocked) { + return EFI_WRITE_PROTECTED; + } + if (!PcdGetBool (PcdAllowVariablePolicyEnforcementDisable)) { + return EFI_WRITE_PROTECTED; + } + mProtectionDisabled =3D TRUE; + return EFI_SUCCESS; +} + + +/** + This API function will dump the entire contents of the variable policy t= able. + + Similar to GetVariable, the first call can be made with a 0 size and it = will return + the size of the buffer required to hold the entire table. + + @param[out] Policy Pointer to the policy buffer. Can be NULL if Siz= e is 0. + @param[in,out] Size On input, the size of the output buffer. On outp= ut, the size + of the data returned. + + @retval EFI_SUCCESS Policy data is in the output buffer = and Size has been updated. + @retval EFI_INVALID_PARAMETER Size is NULL, or Size is non-zero an= d Policy is NULL. + @retval EFI_BUFFER_TOO_SMALL Size is insufficient to hold policy.= Size updated with required size. + @retval EFI_NOT_READY Library has not yet been initialized= . + +**/ +EFI_STATUS +EFIAPI +DumpVariablePolicy ( + OUT UINT8 *Policy, + IN OUT UINT32 *Size + ) +{ + if (!IsVariablePolicyLibInitialized ()) { + return EFI_NOT_READY; + } + + // Check the parameters. + if (Size =3D=3D NULL || (*Size > 0 && Policy =3D=3D NULL)) { + return EFI_INVALID_PARAMETER; + } + + // Make sure the size is sufficient to hold the policy table. + if (*Size < mCurrentTableUsage) { + *Size =3D mCurrentTableUsage; + return EFI_BUFFER_TOO_SMALL; + } + + // If we're still here, copy the table and bounce. + CopyMem (Policy, mPolicyTable, mCurrentTableUsage); + *Size =3D mCurrentTableUsage; + + return EFI_SUCCESS; +} + + +/** + This API function returns whether or not the policy engine is + currently being enforced. + + @retval TRUE + @retval FALSE + @retval FALSE Library has not yet been initialized. + +**/ +BOOLEAN +EFIAPI +IsVariablePolicyEnabled ( + VOID + ) +{ + if (!IsVariablePolicyLibInitialized ()) { + return FALSE; + } + return !mProtectionDisabled; +} + + +/** + This API function locks the interface so that no more policy updates + can be performed or changes made to the enforcement until the next boot. + + @retval EFI_SUCCESS + @retval EFI_NOT_READY Library has not yet been initialized. + +**/ +EFI_STATUS +EFIAPI +LockVariablePolicy ( + VOID + ) +{ + if (!IsVariablePolicyLibInitialized ()) { + return EFI_NOT_READY; + } + if (mInterfaceLocked) { + return EFI_WRITE_PROTECTED; + } + mInterfaceLocked =3D TRUE; + return EFI_SUCCESS; +} + + +/** + This API function returns whether or not the policy interface is locked + for the remainder of the boot. + + @retval TRUE + @retval FALSE + @retval FALSE Library has not yet been initialized. + +**/ +BOOLEAN +EFIAPI +IsVariablePolicyInterfaceLocked ( + VOID + ) +{ + if (!IsVariablePolicyLibInitialized ()) { + return FALSE; + } + return mInterfaceLocked; +} + + +/** + This helper function initializes the library and sets + up any required internal structures or handlers. + + Also registers the internal pointer for the GetVariable helper. + + @param[in] GetVariableHelper A function pointer matching the EFI_GET_VA= RIABLE prototype that will be used to + check policy criteria that involve the existence of othe= r variables. + + @retval EFI_SUCCESS + @retval EFI_ALREADY_STARTED The initialize function has been calle= d more than once without a call to + deinitialize. + +**/ +EFI_STATUS +EFIAPI +InitVariablePolicyLib ( + IN EFI_GET_VARIABLE GetVariableHelper + ) +{ + EFI_STATUS Status; + + if (mGetVariableHelper !=3D NULL) { + Status =3D EFI_ALREADY_STARTED; + } + + if (!EFI_ERROR (Status)) { + Status =3D VariablePolicyExtraInit (); + } + + if (!EFI_ERROR (Status)) { + // Save an internal pointer to the GetVariableHelper. + mGetVariableHelper =3D GetVariableHelper; + + // Initialize the global state. + mInterfaceLocked =3D FALSE; + mProtectionDisabled =3D FALSE; + mPolicyTable =3D NULL; + mCurrentTableSize =3D 0; + mCurrentTableUsage =3D 0; + mCurrentTableCount =3D 0; + } + + return Status; +} + + +/** + This helper function returns whether or not the library is currently ini= tialized. + + @retval TRUE + @retval FALSE + +**/ +BOOLEAN +EFIAPI +IsVariablePolicyLibInitialized ( + VOID + ) +{ + return (mGetVariableHelper !=3D NULL); +} + + +/** + This helper function tears down the library. + + Should generally only be used for test harnesses. + + @retval EFI_SUCCESS + @retval EFI_NOT_READY Deinitialize was called without first call= ing initialize. + +**/ +EFI_STATUS +EFIAPI +DeinitVariablePolicyLib ( + VOID + ) +{ + EFI_STATUS Status; + + if (mGetVariableHelper =3D=3D NULL) { + Status =3D EFI_NOT_READY; + } + + if (!EFI_ERROR (Status)) { + Status =3D VariablePolicyExtraDeinit (); + } + + if (!EFI_ERROR (Status)) { + mGetVariableHelper =3D NULL; + mInterfaceLocked =3D FALSE; + mProtectionDisabled =3D FALSE; + mCurrentTableSize =3D 0; + mCurrentTableUsage =3D 0; + mCurrentTableCount =3D 0; + + if (mPolicyTable !=3D NULL) { + FreePool (mPolicyTable); + mPolicyTable =3D NULL; + } + } + + return Status; +} diff --git a/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyUnitTest/= VariablePolicyUnitTest.c b/MdeModulePkg/Library/VariablePolicyLib/VariableP= olicyUnitTest/VariablePolicyUnitTest.c new file mode 100644 index 000000000000..9f1122d94e91 --- /dev/null +++ b/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyUnitTest/Variabl= ePolicyUnitTest.c @@ -0,0 +1,2533 @@ +/** @file -- VariablePolicyUnitTest.c +UnitTest for... +Business logic for Variable Policy enforcement. + +Copyright (c) Microsoft Corporation. +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +// MU_CHANGE - Turn this off for now. Try to turn it back on with extra bu= ild options. +// #ifndef INTERNAL_UNIT_TEST +// #error Make sure to build thie with INTERNAL_UNIT_TEST enabled! Otherwi= se, some important tests may be skipped! +// #endif + + +#define UNIT_TEST_NAME "UEFI Variable Policy UnitTest" +#define UNIT_TEST_VERSION "0.5" + +///=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 + +#pragma pack(push, 1) +typedef struct _SIMPLE_VARIABLE_POLICY_ENTRY { + VARIABLE_POLICY_ENTRY Header; + CHAR16 Name[]; +} SIMPLE_VARIABLE_POLICY_ENTRY; +#define EXPANDED_VARIABLE_POLICY_ENTRY_VAR_NAME_LENGTH 1001 // 1000 ch= aracters + terminator. +#define EXPANDED_VARIABLE_POLICY_ENTRY_VAR_NAME_SIZE (EXPANDED_VARIABLE= _POLICY_ENTRY_VAR_NAME_LENGTH * sizeof (CHAR16)) +typedef struct _EXPANDED_VARIABLE_POLICY_ENTRY { + VARIABLE_POLICY_ENTRY Header; + VARIABLE_LOCK_ON_VAR_STATE_POLICY StatePolicy; + CHAR16 StateName[EXPANDED_VARIABLE_POLICY_E= NTRY_VAR_NAME_LENGTH]; + CHAR16 Name[EXPANDED_VARIABLE_POLICY_ENTRY_= VAR_NAME_LENGTH]; +} EXPANDED_VARIABLE_POLICY_ENTRY; +#pragma pack(pop) + +// {F955BA2D-4A2C-480C-BFD1-3CC522610592} +#define TEST_GUID_1 { 0xf955ba2d, 0x4a2c, 0x480c, { 0xbf, 0xd1, 0x3c, 0xc5= , 0x22, 0x61, 0x5, 0x92 } } +EFI_GUID mTestGuid1 =3D TEST_GUID_1; +// {2DEA799E-5E73-43B9-870E-C945CE82AF3A} +#define TEST_GUID_2 { 0x2dea799e, 0x5e73, 0x43b9, { 0x87, 0xe, 0xc9, 0x45,= 0xce, 0x82, 0xaf, 0x3a } } +EFI_GUID mTestGuid2 =3D TEST_GUID_2; +// {698A2BFD-A616-482D-B88C-7100BD6682A9} +#define TEST_GUID_3 { 0x698a2bfd, 0xa616, 0x482d, { 0xb8, 0x8c, 0x71, 0x0,= 0xbd, 0x66, 0x82, 0xa9 } } +EFI_GUID mTestGuid3 =3D TEST_GUID_3; + +#define TEST_VAR_1_NAME L"TestVar1" +#define TEST_VAR_2_NAME L"TestVar2" +#define TEST_VAR_3_NAME L"TestVar3" + +#define TEST_POLICY_ATTRIBUTES_NULL 0 +#define TEST_POLICY_MIN_SIZE_NULL 0 +#define TEST_POLICY_MAX_SIZE_NULL MAX_UINT32 + +#define TEST_POLICY_MIN_SIZE_10 10 +#define TEST_POLICY_MAX_SIZE_200 200 + +#define TEST_300_HASHES_STRING L"####################################= ##############"\ + "###################################= ###############"\ + "###################################= ###############"\ + "###################################= ###############"\ + "###################################= ###############"\ + "###################################= ###############" + + +///=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 + +/** + Helper function to initialize a VARIABLE_POLICY_ENTRY structure with a N= ame and StateName. + + Takes care of all the messy packing. + + @param[in,out] Entry + @param[in] Name [Optional] + @param[in] StateName [Optional] + + @retval TRUE + @retval FALSE + +**/ +STATIC +BOOLEAN +InitExpVarPolicyStrings ( + EXPANDED_VARIABLE_POLICY_ENTRY *Entry, + CHAR16 *Name, OPTIONAL + CHAR16 *StateName OPTIONAL + ) +{ + UINTN NameSize; + UINTN StateNameSize; + + NameSize =3D Name =3D=3D NULL ? 0 : StrSize (Name); + StateNameSize =3D StateName =3D=3D NULL ? 0 : StrSize (StateName); + + if (NameSize > EXPANDED_VARIABLE_POLICY_ENTRY_VAR_NAME_SIZE || NameSize = > MAX_UINT16 || + StateNameSize > EXPANDED_VARIABLE_POLICY_ENTRY_VAR_NAME_SIZE || Stat= eNameSize > MAX_UINT16) { + return FALSE; + } + + Entry->Header.OffsetToName =3D sizeof (VARIABLE_POLICY_ENTRY); + if (StateName !=3D NULL) { + Entry->Header.OffsetToName +=3D (UINT16) sizeof (VARIABLE_LOCK_ON_VAR_= STATE_POLICY) + (UINT16) StateNameSize; + } + Entry->Header.Size =3D Entry->Header.OffsetToName + (UINT16) NameSize; + + CopyMem ((UINT8 *) Entry + Entry->Header.OffsetToName, Name, NameSize); + if (StateName !=3D NULL) { + CopyMem ( + (UINT8 *) Entry + sizeof (VARIABLE_POLICY_ENTRY) + sizeof (VARIABLE_= LOCK_ON_VAR_STATE_POLICY), + StateName, + StateNameSize + ); + } + + return TRUE; +} + +/** + Mocked version of GetVariable, for testing. +**/ +EFI_STATUS +EFIAPI +StubGetVariableNull ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + OUT UINT32 *Attributes, OPTIONAL + IN OUT UINTN *DataSize, + OUT VOID *Data OPTIONAL + ) +{ + UINT32 MockedAttr; + UINTN MockedDataSize; + VOID *MockedData; + EFI_STATUS MockedReturn; + + check_expected_ptr (VariableName); + check_expected_ptr (VendorGuid); + check_expected_ptr (DataSize); + + MockedAttr =3D (UINT32) mock (); + MockedDataSize =3D (UINTN) mock (); + MockedData =3D (VOID *) (UINTN) mock (); + MockedReturn =3D (EFI_STATUS) mock (); + + if (Attributes !=3D NULL) { + *Attributes =3D MockedAttr; + } + if (Data !=3D NULL && !EFI_ERROR (MockedReturn)) { + CopyMem (Data, MockedData, MockedDataSize); + } + + *DataSize =3D MockedDataSize; + + return MockedReturn; +} + +// +// Anything you think might be helpful that isn't a test itself. +// + +/** + This is a common setup function that will ensure the library is always i= nitialized + with the stubbed GetVariable. + + Not used by all test cases, but by most. +**/ +STATIC +UNIT_TEST_STATUS +LibInitMocked ( + IN UNIT_TEST_CONTEXT Context + ) +{ + return EFI_ERROR (InitVariablePolicyLib (StubGetVariableNull)) ? UNIT_TE= ST_ERROR_PREREQUISITE_NOT_MET : UNIT_TEST_PASSED; +} + +/** + Common cleanup function to make sure that the library is always de-initi= alized prior + to the next test case. +*/ +STATIC +VOID +LibCleanup ( + IN UNIT_TEST_CONTEXT Context + ) +{ + DeinitVariablePolicyLib (); +} + + +///=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 + +///=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 + +/** + Test Case +*/ +UNIT_TEST_STATUS +EFIAPI +ShouldBeAbleToInitAndDeinitTheLibrary ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + Status =3D InitVariablePolicyLib (StubGetVariableNull); + UT_ASSERT_NOT_EFI_ERROR (Status); + + UT_ASSERT_TRUE (IsVariablePolicyLibInitialized ()); + + Status =3D DeinitVariablePolicyLib (); + UT_ASSERT_NOT_EFI_ERROR (Status); + + UT_ASSERT_FALSE (IsVariablePolicyLibInitialized ()); + + return UNIT_TEST_PASSED; +} + +/** + Test Case +*/ +UNIT_TEST_STATUS +EFIAPI +ShouldNotBeAbleToInitializeTheLibraryTwice ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + Status =3D InitVariablePolicyLib (StubGetVariableNull); + UT_ASSERT_NOT_EFI_ERROR (Status); + Status =3D InitVariablePolicyLib (StubGetVariableNull); + UT_ASSERT_TRUE (EFI_ERROR (Status)); + return UNIT_TEST_PASSED; +} + +/** + Test Case +*/ +UNIT_TEST_STATUS +EFIAPI +ShouldFailDeinitWithoutInit ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + Status =3D DeinitVariablePolicyLib (); + UT_ASSERT_TRUE (EFI_ERROR (Status)); + return UNIT_TEST_PASSED; +} + +/** + Test Case +*/ +UNIT_TEST_STATUS +EFIAPI +ApiCommandsShouldNotRespondIfLibIsUninitialized ( + IN UNIT_TEST_CONTEXT Context + ) +{ + SIMPLE_VARIABLE_POLICY_ENTRY TestPolicy =3D { + { + VARIABLE_POLICY_ENTRY_REVISION, + sizeof (VARIABLE_POLICY_ENTRY) + sizeof (TEST_VAR_1_NAME), + sizeof (VARIABLE_POLICY_ENTRY), + TEST_GUID_1, + TEST_POLICY_MIN_SIZE_NULL, + TEST_POLICY_MAX_SIZE_NULL, + TEST_POLICY_ATTRIBUTES_NULL, + TEST_POLICY_ATTRIBUTES_NULL, + VARIABLE_POLICY_TYPE_NO_LOCK + }, + TEST_VAR_1_NAME + }; + UINT8 DummyData[8]; + UINT32 DummyDataSize =3D sizeof (DummyData); + + // This test should not start with an initialized library. + + // Verify that all API commands fail. + UT_ASSERT_TRUE (EFI_ERROR (LockVariablePolicy ())); + UT_ASSERT_TRUE (EFI_ERROR (DisableVariablePolicy ())); + UT_ASSERT_TRUE (EFI_ERROR (RegisterVariablePolicy (&TestPolicy.Header)))= ; + UT_ASSERT_TRUE (EFI_ERROR (DumpVariablePolicy (DummyData, &DummyDataSize= ))); + UT_ASSERT_FALSE (IsVariablePolicyInterfaceLocked ()); + UT_ASSERT_FALSE (IsVariablePolicyEnabled ()); + UT_ASSERT_TRUE ( + EFI_ERROR (ValidateSetVariable (TEST_VAR_1_NAME, &mTestGuid1, VARIABLE= _ATTRIBUTE_NV_BS, sizeof (DummyData), DummyData)) + ); + + return UNIT_TEST_PASSED; +} + + +///=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 + +#ifdef INTERNAL_UNIT_TEST + +BOOLEAN +EvaluatePolicyMatch ( + IN CONST VARIABLE_POLICY_ENTRY *EvalEntry, + IN CONST CHAR16 *VariableName, + IN CONST EFI_GUID *VendorGuid, + OUT UINT8 *MatchPriority OPTIONAL + ); + +/** + Test Case +*/ +UNIT_TEST_STATUS +EFIAPI +PoliciesShouldMatchByNameAndGuid ( + IN UNIT_TEST_CONTEXT Context + ) +{ + SIMPLE_VARIABLE_POLICY_ENTRY MatchCheckPolicy =3D { + { + VARIABLE_POLICY_ENTRY_REVISION, + sizeof (VARIABLE_POLICY_ENTRY) + sizeof (TEST_VAR_1_NAME), + sizeof (VARIABLE_POLICY_ENTRY), + TEST_GUID_1, + TEST_POLICY_MIN_SIZE_NULL, + TEST_POLICY_MAX_SIZE_NULL, + TEST_POLICY_ATTRIBUTES_NULL, + TEST_POLICY_ATTRIBUTES_NULL, + VARIABLE_POLICY_TYPE_NO_LOCK + }, + TEST_VAR_1_NAME + }; + CHAR16 *CheckVar1Name =3D TEST_VAR_1_NAME; + CHAR16 *CheckVar2Name =3D TEST_VAR_2_NAME; + + // Make sure that a different name does not match. + UT_ASSERT_FALSE (EvaluatePolicyMatch (&MatchCheckPolicy.Header, CheckVar= 2Name, &mTestGuid1, NULL)); + + // Make sure that a different GUID does not match. + UT_ASSERT_FALSE (EvaluatePolicyMatch (&MatchCheckPolicy.Header, CheckVar= 1Name, &mTestGuid2, NULL)); + + // Make sure that the same name and GUID match. + UT_ASSERT_TRUE (EvaluatePolicyMatch (&MatchCheckPolicy.Header, CheckVar1= Name, &mTestGuid1, NULL)); + + return UNIT_TEST_PASSED; +} + +/** + Test Case +*/ +UNIT_TEST_STATUS +EFIAPI +WildcardPoliciesShouldMatchDigits ( + IN UNIT_TEST_CONTEXT Context + ) +{ + SIMPLE_VARIABLE_POLICY_ENTRY MatchCheckPolicy =3D { + { + VARIABLE_POLICY_ENTRY_REVISION, + sizeof (VARIABLE_POLICY_ENTRY) + sizeof (L"Wildcard#VarName##"), + sizeof (VARIABLE_POLICY_ENTRY), + TEST_GUID_1, + TEST_POLICY_MIN_SIZE_NULL, + TEST_POLICY_MAX_SIZE_NULL, + TEST_POLICY_ATTRIBUTES_NULL, + TEST_POLICY_ATTRIBUTES_NULL, + VARIABLE_POLICY_TYPE_NO_LOCK + }, + L"Wildcard#VarName##" + }; + CHAR16 *CheckVar1Name =3D L"Wildcard1VarName12"; + CHAR16 *CheckVar2Name =3D L"Wildcard2VarName34"; + CHAR16 *CheckVarBName =3D L"WildcardBVarName56"; + CHAR16 *CheckVarHName =3D L"Wildcard#VarName56"; + + // Make sure that two different sets of wildcard numbers match. + UT_ASSERT_TRUE (EvaluatePolicyMatch (&MatchCheckPolicy.Header, CheckVar1= Name, &mTestGuid1, NULL)); + UT_ASSERT_TRUE (EvaluatePolicyMatch (&MatchCheckPolicy.Header, CheckVar2= Name, &mTestGuid1, NULL)); + + // Make sure that the non-number charaters don't match. + UT_ASSERT_FALSE (EvaluatePolicyMatch (&MatchCheckPolicy.Header, CheckVar= BName, &mTestGuid1, NULL)); + + // Make sure that '#' signs don't match. + UT_ASSERT_FALSE (EvaluatePolicyMatch (&MatchCheckPolicy.Header, CheckVar= HName, &mTestGuid1, NULL)); + + return UNIT_TEST_PASSED; +} + +/** + Test Case +*/ +UNIT_TEST_STATUS +EFIAPI +WildcardPoliciesShouldMatchDigitsAdvanced ( + IN UNIT_TEST_CONTEXT Context + ) +{ + SIMPLE_VARIABLE_POLICY_ENTRY MatchCheckPolicy =3D { + { + VARIABLE_POLICY_ENTRY_REVISION, + sizeof (VARIABLE_POLICY_ENTRY) + sizeof (TEST_300_HASHES_STRING), + sizeof (VARIABLE_POLICY_ENTRY), + TEST_GUID_1, + TEST_POLICY_MIN_SIZE_NULL, + TEST_POLICY_MAX_SIZE_NULL, + TEST_POLICY_ATTRIBUTES_NULL, + TEST_POLICY_ATTRIBUTES_NULL, + VARIABLE_POLICY_TYPE_NO_LOCK + }, + TEST_300_HASHES_STRING + }; + CHAR16 *CheckShorterString =3D L"01234567890123456789012345678901= 234567890123456789"; + CHAR16 *CheckValidString =3D L"0123456789012345678901234567890123= 4567890123456789"\ + "01234567890123456789012345678901234= 567890123456789"\ + "01234567890123456789012345678901234= 567890123456789"\ + "01234567890123456789012345678901234= 567890123456789"\ + "01234567890123456789012345678901234= 567890123456789"\ + "01234567890123456789012345678901234= 567890123456789"; + CHAR16 *CheckLongerString =3D L"012345678901234567890123456789012= 34567890123456789"\ + "01234567890123456789012345678901234= 567890123456789"\ + "01234567890123456789012345678901234= 567890123456789"\ + "01234567890123456789012345678901234= 567890123456789"\ + "01234567890123456789012345678901234= 567890123456789"\ + "01234567890123456789012345678901234= 567890123456789"\ + "01234567890123456789012345678901234= 567890123456789"; + UINT8 MatchPriority; + + // Make sure that the shorter and the longer do not match. + UT_ASSERT_FALSE (EvaluatePolicyMatch (&MatchCheckPolicy.Header, CheckSho= rterString, &mTestGuid1, NULL)); + UT_ASSERT_FALSE (EvaluatePolicyMatch (&MatchCheckPolicy.Header, CheckLon= gerString, &mTestGuid1, NULL)); + + // Make sure that the valid one matches and has the expected priority. + UT_ASSERT_TRUE (EvaluatePolicyMatch (&MatchCheckPolicy.Header, CheckVali= dString, &mTestGuid1, &MatchPriority)); + UT_ASSERT_EQUAL (MatchPriority, MAX_UINT8); + + return UNIT_TEST_PASSED; +} + +/** + Test Case +*/ +UNIT_TEST_STATUS +EFIAPI +WildcardPoliciesShouldMatchNamespaces ( + IN UNIT_TEST_CONTEXT Context + ) +{ + VARIABLE_POLICY_ENTRY MatchCheckPolicy =3D { + VARIABLE_POLICY_ENTRY_REVISION, + sizeof (VARIABLE_POLICY_ENTRY), + sizeof (VARIABLE_POLICY_ENTRY), + TEST_GUID_1, + TEST_POLICY_MIN_SIZE_NULL, + TEST_POLICY_MAX_SIZE_NULL, + TEST_POLICY_ATTRIBUTES_NULL, + TEST_POLICY_ATTRIBUTES_NULL, + VARIABLE_POLICY_TYPE_NO_LOCK + }; + CHAR16 *CheckVar1Name =3D L"Wildcard1VarName12"; + CHAR16 *CheckVar2Name =3D L"Wildcard2VarName34"; + CHAR16 *CheckVarBName =3D L"WildcardBVarName56"; + CHAR16 *CheckVarHName =3D L"Wildcard#VarName56"; + + // Make sure that all names in the same namespace match. + UT_ASSERT_TRUE (EvaluatePolicyMatch (&MatchCheckPolicy, CheckVar1Name, &= mTestGuid1, NULL)); + UT_ASSERT_TRUE (EvaluatePolicyMatch (&MatchCheckPolicy, CheckVar2Name, &= mTestGuid1, NULL)); + UT_ASSERT_TRUE (EvaluatePolicyMatch (&MatchCheckPolicy, CheckVarBName, &= mTestGuid1, NULL)); + UT_ASSERT_TRUE (EvaluatePolicyMatch (&MatchCheckPolicy, CheckVarHName, &= mTestGuid1, NULL)); + + // Make sure that different namespace doesn't match. + UT_ASSERT_FALSE (EvaluatePolicyMatch (&MatchCheckPolicy, CheckVar1Name, = &mTestGuid2, NULL)); + + return UNIT_TEST_PASSED; +} + +/** + Test Case +*/ +UNIT_TEST_STATUS +EFIAPI +MatchPrioritiesShouldFollowRules ( + IN UNIT_TEST_CONTEXT Context + ) +{ + SIMPLE_VARIABLE_POLICY_ENTRY MatchCheckPolicy =3D { + { + VARIABLE_POLICY_ENTRY_REVISION, + sizeof (VARIABLE_POLICY_ENTRY) + sizeof (L"Wildcard1VarName12"), + sizeof (VARIABLE_POLICY_ENTRY), + TEST_GUID_1, + TEST_POLICY_MIN_SIZE_NULL, + TEST_POLICY_MAX_SIZE_NULL, + TEST_POLICY_ATTRIBUTES_NULL, + TEST_POLICY_ATTRIBUTES_NULL, + VARIABLE_POLICY_TYPE_NO_LOCK + }, + L"Wildcard1VarName12" + }; + CHAR16 CheckVar1Name[] =3D L"Wildcard1VarName12"; + CHAR16 MatchVar1Name[] =3D L"Wildcard1VarName12"; + CHAR16 MatchVar2Name[] =3D L"Wildcard#VarName12"; + CHAR16 MatchVar3Name[] =3D L"Wildcard#VarName#2"; + CHAR16 MatchVar4Name[] =3D L"Wildcard#VarName##"; + UINT8 MatchPriority; + + // Check with a perfect match. + CopyMem (&MatchCheckPolicy.Name, MatchVar1Name, sizeof (MatchVar1Name)); + UT_ASSERT_TRUE (EvaluatePolicyMatch (&MatchCheckPolicy.Header, CheckVar1= Name, &mTestGuid1, &MatchPriority)); + UT_ASSERT_EQUAL (MatchPriority, 0); + + // Check with progressively lower priority matches. + CopyMem (&MatchCheckPolicy.Name, MatchVar2Name, sizeof (MatchVar2Name)); + UT_ASSERT_TRUE (EvaluatePolicyMatch (&MatchCheckPolicy.Header, CheckVar1= Name, &mTestGuid1, &MatchPriority)); + UT_ASSERT_EQUAL (MatchPriority, 1); + CopyMem (&MatchCheckPolicy.Name, MatchVar3Name, sizeof (MatchVar3Name)); + UT_ASSERT_TRUE (EvaluatePolicyMatch (&MatchCheckPolicy.Header, CheckVar1= Name, &mTestGuid1, &MatchPriority)); + UT_ASSERT_EQUAL (MatchPriority, 2); + CopyMem (&MatchCheckPolicy.Name, MatchVar4Name, sizeof (MatchVar4Name)); + UT_ASSERT_TRUE (EvaluatePolicyMatch (&MatchCheckPolicy.Header, CheckVar1= Name, &mTestGuid1, &MatchPriority)); + UT_ASSERT_EQUAL (MatchPriority, 3); + + // Check against the entire namespace. + MatchCheckPolicy.Header.Size =3D sizeof (VARIABLE_POLICY_ENTRY); + UT_ASSERT_TRUE (EvaluatePolicyMatch(&MatchCheckPolicy.Header, CheckVar1N= ame, &mTestGuid1, &MatchPriority)); + UT_ASSERT_EQUAL (MatchPriority, MAX_UINT8); + + return UNIT_TEST_PASSED; +} + +#endif // INTERNAL_UNIT_TEST + + +///=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 + +/** + Test Case +*/ +UNIT_TEST_STATUS +EFIAPI +RegisterShouldAllowNamespaceWildcards ( + IN UNIT_TEST_CONTEXT Context + ) +{ + SIMPLE_VARIABLE_POLICY_ENTRY ValidationPolicy =3D { + { + VARIABLE_POLICY_ENTRY_REVISION, + sizeof (VARIABLE_POLICY_ENTRY), + sizeof (VARIABLE_POLICY_ENTRY), + TEST_GUID_1, + TEST_POLICY_MIN_SIZE_NULL, + TEST_POLICY_MAX_SIZE_NULL, + TEST_POLICY_ATTRIBUTES_NULL, + TEST_POLICY_ATTRIBUTES_NULL, + VARIABLE_POLICY_TYPE_NO_LOCK + }, + L"" + }; + + UT_ASSERT_NOT_EFI_ERROR (RegisterVariablePolicy (&ValidationPolicy.Heade= r)); + + return UNIT_TEST_PASSED; +} + +/** + Test Case +*/ +UNIT_TEST_STATUS +EFIAPI +RegisterShouldAllowStateVarsForNamespaces ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EXPANDED_VARIABLE_POLICY_ENTRY ValidationPolicy =3D { + { + VARIABLE_POLICY_ENTRY_REVISION, + 0, // Will be populated by init helper. + 0, // Will be populated by init helper. + TEST_GUID_1, + TEST_POLICY_MIN_SIZE_NULL, + TEST_POLICY_MAX_SIZE_NULL, + TEST_POLICY_ATTRIBUTES_NULL, + TEST_POLICY_ATTRIBUTES_NULL, + VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE + }, + { + TEST_GUID_2, + 1, // Value + 0 // Padding + }, + L"", + L"" + }; + UT_ASSERT_TRUE (InitExpVarPolicyStrings (&ValidationPolicy, NULL, TEST_V= AR_2_NAME)); + + UT_ASSERT_NOT_EFI_ERROR (RegisterVariablePolicy (&ValidationPolicy.Heade= r)); + + return UNIT_TEST_PASSED; +} + +/** + Test Case +*/ +UNIT_TEST_STATUS +EFIAPI +RegisterShouldRejectNullPointers ( + IN UNIT_TEST_CONTEXT Context + ) +{ + UT_ASSERT_EQUAL (RegisterVariablePolicy (NULL), EFI_INVALID_PARAMETER); + return UNIT_TEST_PASSED; +} + +/** + Test Case +*/ +UNIT_TEST_STATUS +EFIAPI +RegisterShouldRejectBadRevisions ( + IN UNIT_TEST_CONTEXT Context + ) +{ + SIMPLE_VARIABLE_POLICY_ENTRY ValidationPolicy =3D { + { + VARIABLE_POLICY_ENTRY_REVISION, + sizeof (VARIABLE_POLICY_ENTRY) + sizeof (TEST_VAR_1_NAME), + sizeof (VARIABLE_POLICY_ENTRY), + TEST_GUID_1, + TEST_POLICY_MIN_SIZE_NULL, + TEST_POLICY_MAX_SIZE_NULL, + TEST_POLICY_ATTRIBUTES_NULL, + TEST_POLICY_ATTRIBUTES_NULL, + VARIABLE_POLICY_TYPE_NO_LOCK + }, + TEST_VAR_1_NAME + }; + + ValidationPolicy.Header.Version =3D MAX_UINT32; + UT_ASSERT_EQUAL (RegisterVariablePolicy (&ValidationPolicy.Header), EFI_= INVALID_PARAMETER); + + return UNIT_TEST_PASSED; +} + +/** + Test Case +*/ +UNIT_TEST_STATUS +EFIAPI +RegisterShouldRejectBadSizes ( + IN UNIT_TEST_CONTEXT Context + ) +{ + SIMPLE_VARIABLE_POLICY_ENTRY ValidationPolicy =3D { + { + VARIABLE_POLICY_ENTRY_REVISION, + sizeof (VARIABLE_POLICY_ENTRY) + sizeof (TEST_VAR_1_NAME), + sizeof (VARIABLE_POLICY_ENTRY), + TEST_GUID_1, + TEST_POLICY_MIN_SIZE_NULL, + TEST_POLICY_MAX_SIZE_NULL, + TEST_POLICY_ATTRIBUTES_NULL, + TEST_POLICY_ATTRIBUTES_NULL, + VARIABLE_POLICY_TYPE_NO_LOCK + }, + TEST_VAR_1_NAME + }; + + ValidationPolicy.Header.Size =3D sizeof (VARIABLE_POLICY_ENTRY) - 2; + UT_ASSERT_EQUAL (RegisterVariablePolicy (&ValidationPolicy.Header), EFI_= INVALID_PARAMETER); + + return UNIT_TEST_PASSED; +} + +/** + Test Case +*/ +UNIT_TEST_STATUS +EFIAPI +RegisterShouldRejectBadOffsets ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EXPANDED_VARIABLE_POLICY_ENTRY ValidationPolicy =3D { + { + VARIABLE_POLICY_ENTRY_REVISION, + 0, // Will be populated by init helper. + 0, // Will be populated by init helper. + TEST_GUID_1, + TEST_POLICY_MIN_SIZE_NULL, + TEST_POLICY_MAX_SIZE_NULL, + TEST_POLICY_ATTRIBUTES_NULL, + TEST_POLICY_ATTRIBUTES_NULL, + VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE + }, + { + TEST_GUID_2, + 1, // Value + 0 // Padding + }, + L"", + L"" + }; + UT_ASSERT_TRUE (InitExpVarPolicyStrings (&ValidationPolicy, TEST_VAR_1_N= AME, TEST_VAR_2_NAME)); + + // Check for an offset outside the size bounds. + ValidationPolicy.Header.OffsetToName =3D ValidationPolicy.Header.Size + = 1; + UT_ASSERT_EQUAL (RegisterVariablePolicy (&ValidationPolicy.Header), EFI_= INVALID_PARAMETER); + + // Check for an offset inside the policy header. + ValidationPolicy.Header.OffsetToName =3D sizeof (VARIABLE_POLICY_ENTRY) = - 2; + UT_ASSERT_EQUAL (RegisterVariablePolicy (&ValidationPolicy.Header), EFI_= INVALID_PARAMETER); + + // Check for an offset inside the state policy header. + ValidationPolicy.Header.OffsetToName =3D sizeof (VARIABLE_POLICY_ENTRY) = + 2; + UT_ASSERT_EQUAL (RegisterVariablePolicy (&ValidationPolicy.Header), EFI_= INVALID_PARAMETER); + + // Check for a ridiculous offset. + ValidationPolicy.Header.OffsetToName =3D MAX_UINT16; + UT_ASSERT_EQUAL (RegisterVariablePolicy (&ValidationPolicy.Header), EFI_= INVALID_PARAMETER); + + return UNIT_TEST_PASSED; +} + +/** + Test Case +*/ +UNIT_TEST_STATUS +EFIAPI +RegisterShouldRejectMissingStateStrings ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EXPANDED_VARIABLE_POLICY_ENTRY ValidationPolicy =3D { + { + VARIABLE_POLICY_ENTRY_REVISION, + 0, // Will be populated by init helper. + 0, // Will be populated by init helper. + TEST_GUID_1, + TEST_POLICY_MIN_SIZE_NULL, + TEST_POLICY_MAX_SIZE_NULL, + TEST_POLICY_ATTRIBUTES_NULL, + TEST_POLICY_ATTRIBUTES_NULL, + VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE + }, + { + TEST_GUID_2, + 1, // Value + 0 // Padding + }, + L"", + L"" + }; + UT_ASSERT_TRUE (InitExpVarPolicyStrings (&ValidationPolicy, TEST_VAR_1_N= AME, TEST_VAR_2_NAME)); + + // Remove the state string and copy the Name into it's place. + // Also adjust the offset. + ValidationPolicy.Header.Size =3D sizeof (VARIABLE_POLICY_ENTRY)= + sizeof (VARIABLE_LOCK_ON_VAR_STATE_POLICY) + sizeof (TEST_VAR_1_NAME); + ValidationPolicy.Header.OffsetToName =3D sizeof (VARIABLE_POLICY_ENTRY)= + sizeof (VARIABLE_LOCK_ON_VAR_STATE_POLICY); + CopyMem ((UINT8 *) &ValidationPolicy + ValidationPolicy.Header.OffsetToN= ame, TEST_VAR_1_NAME, sizeof (TEST_VAR_1_NAME)); + + // Make sure that this structure fails. + UT_ASSERT_EQUAL (RegisterVariablePolicy (&ValidationPolicy.Header), EFI_= INVALID_PARAMETER); + + return UNIT_TEST_PASSED; +} + +/** + Test Case +*/ +UNIT_TEST_STATUS +EFIAPI +RegisterShouldRejectStringsMissingNull ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EXPANDED_VARIABLE_POLICY_ENTRY ValidationPolicy =3D { + { + VARIABLE_POLICY_ENTRY_REVISION, + 0, // Will be populated by init helper. + 0, // Will be populated by init helper. + TEST_GUID_1, + TEST_POLICY_MIN_SIZE_NULL, + TEST_POLICY_MAX_SIZE_NULL, + TEST_POLICY_ATTRIBUTES_NULL, + TEST_POLICY_ATTRIBUTES_NULL, + VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE + }, + { + TEST_GUID_2, + 1, // Value + 0 // Padding + }, + L"", + L"" + }; + UT_ASSERT_TRUE (InitExpVarPolicyStrings (&ValidationPolicy, TEST_VAR_1_N= AME, TEST_VAR_2_NAME)); + + // Removing the NULL from the Name should fail. + ValidationPolicy.Header.Size =3D ValidationPolicy.Header.Size - sizeof (= CHAR16); + UT_ASSERT_EQUAL (RegisterVariablePolicy (&ValidationPolicy.Header), EFI_= INVALID_PARAMETER); + + // Removing the NULL from the State Name is a little trickier. + // Copy the Name up one byte. + ValidationPolicy.Header.OffsetToName =3D ValidationPolicy.Header.OffsetT= oName - sizeof (CHAR16); + CopyMem ((UINT8 *) &ValidationPolicy + ValidationPolicy.Header.OffsetToN= ame, TEST_VAR_1_NAME, sizeof (TEST_VAR_1_NAME)); + UT_ASSERT_EQUAL (RegisterVariablePolicy (&ValidationPolicy.Header), EFI_= INVALID_PARAMETER); + + return UNIT_TEST_PASSED; +} + +/** + Test Case +*/ +UNIT_TEST_STATUS +EFIAPI +RegisterShouldRejectMalformedStrings ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EXPANDED_VARIABLE_POLICY_ENTRY ValidationPolicy =3D { + { + VARIABLE_POLICY_ENTRY_REVISION, + 0, // Will be populated by init helper. + 0, // Will be populated by init helper. + TEST_GUID_1, + TEST_POLICY_MIN_SIZE_NULL, + TEST_POLICY_MAX_SIZE_NULL, + TEST_POLICY_ATTRIBUTES_NULL, + TEST_POLICY_ATTRIBUTES_NULL, + VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE + }, + { + TEST_GUID_2, + 1, // Value + 0 // Padding + }, + L"", + L"" + }; + UT_ASSERT_TRUE (InitExpVarPolicyStrings (&ValidationPolicy, TEST_VAR_1_N= AME, TEST_VAR_2_NAME)); + + // Bisecting the NULL from the Name should fail. + ValidationPolicy.Header.Size =3D ValidationPolicy.Header.Size - 1; + UT_ASSERT_EQUAL (RegisterVariablePolicy (&ValidationPolicy.Header), EFI_= INVALID_PARAMETER); + + // Bisecting the NULL from the State Name is a little trickier. + // Copy the Name up one byte. + ValidationPolicy.Header.OffsetToName =3D ValidationPolicy.Header.OffsetT= oName - 1; + CopyMem ((UINT8 *) &ValidationPolicy + ValidationPolicy.Header.OffsetToN= ame, TEST_VAR_1_NAME, sizeof (TEST_VAR_1_NAME)); + UT_ASSERT_EQUAL (RegisterVariablePolicy (&ValidationPolicy.Header), EFI_= INVALID_PARAMETER); + + return UNIT_TEST_PASSED; +} + +/** + Test Case +*/ +UNIT_TEST_STATUS +EFIAPI +RegisterShouldRejectUnpackedPolicies ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EXPANDED_VARIABLE_POLICY_ENTRY ValidationPolicy =3D { + { + VARIABLE_POLICY_ENTRY_REVISION, + 0, // Will be populated by init helper. + 0, // Will be populated by init helper. + TEST_GUID_1, + TEST_POLICY_MIN_SIZE_NULL, + TEST_POLICY_MAX_SIZE_NULL, + TEST_POLICY_ATTRIBUTES_NULL, + TEST_POLICY_ATTRIBUTES_NULL, + VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE + }, + { + TEST_GUID_2, + 1, // Value + 0 // Padding + }, + L"", + L"" + }; + UT_ASSERT_TRUE (InitExpVarPolicyStrings (&ValidationPolicy, TEST_VAR_1_N= AME, TEST_VAR_2_NAME)); + + // Increase the size and move the Name out a bit. + ValidationPolicy.Header.Size =3D ValidationPolicy.Header.Size + sizeof (= CHAR16); + ValidationPolicy.Header.OffsetToName =3D ValidationPolicy.Header.OffsetT= oName + sizeof (CHAR16); + CopyMem ((UINT8 *) &ValidationPolicy + ValidationPolicy.Header.OffsetToN= ame, TEST_VAR_1_NAME, sizeof (TEST_VAR_1_NAME)); + UT_ASSERT_EQUAL (RegisterVariablePolicy (&ValidationPolicy.Header), EFI_= INVALID_PARAMETER); + + // Reintialize without the state policy and try the same test. + ValidationPolicy.Header.LockPolicyType =3D VARIABLE_POLICY_TYPE_NO_LOCK; + UT_ASSERT_TRUE (InitExpVarPolicyStrings (&ValidationPolicy, TEST_VAR_1_N= AME, NULL)); + ValidationPolicy.Header.Size =3D ValidationPolicy.Header.Size + sizeof (= CHAR16); + ValidationPolicy.Header.OffsetToName =3D ValidationPolicy.Header.OffsetT= oName + sizeof (CHAR16); + CopyMem ((UINT8 *) &ValidationPolicy + ValidationPolicy.Header.OffsetToN= ame, TEST_VAR_1_NAME, sizeof (TEST_VAR_1_NAME)); + UT_ASSERT_EQUAL (RegisterVariablePolicy (&ValidationPolicy.Header), EFI_= INVALID_PARAMETER); + + return UNIT_TEST_PASSED; +} + +/** + Test Case +*/ +UNIT_TEST_STATUS +EFIAPI +RegisterShouldRejectInvalidNameCharacters ( + IN UNIT_TEST_CONTEXT Context + ) +{ + // EXPANDED_VARIABLE_POLICY_ENTRY ValidationPolicy =3D { + // { + // VARIABLE_POLICY_ENTRY_REVISION, + // 0, // Will be populated by init helper. + // 0, // Will be populated by init helper. + // TEST_GUID_1, + // TEST_POLICY_MIN_SIZE_NULL, + // TEST_POLICY_MAX_SIZE_NULL, + // TEST_POLICY_ATTRIBUTES_NULL, + // TEST_POLICY_ATTRIBUTES_NULL, + // VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE + // }, + // { + // TEST_GUID_2, + // 1, // Value + // 0 // Padding + // }, + // L"", + // L"" + // }; + + // Currently, there are no known invalid characters. + // '#' in LockPolicy->Name are taken as literal. + + return UNIT_TEST_PASSED; +} + +/** + Test Case +*/ +UNIT_TEST_STATUS +EFIAPI +RegisterShouldRejectBadPolicyConstraints ( + IN UNIT_TEST_CONTEXT Context + ) +{ + SIMPLE_VARIABLE_POLICY_ENTRY ValidationPolicy =3D { + { + VARIABLE_POLICY_ENTRY_REVISION, + sizeof (VARIABLE_POLICY_ENTRY) + sizeof (TEST_VAR_1_NAME), + sizeof (VARIABLE_POLICY_ENTRY), + TEST_GUID_1, + TEST_POLICY_MIN_SIZE_NULL, + TEST_POLICY_MAX_SIZE_NULL, + TEST_POLICY_ATTRIBUTES_NULL, + TEST_POLICY_ATTRIBUTES_NULL, + VARIABLE_POLICY_TYPE_NO_LOCK + }, + TEST_VAR_1_NAME + }; + + // Make sure that invalid MAXes are rejected. + ValidationPolicy.Header.MaxSize =3D 0; + UT_ASSERT_EQUAL (RegisterVariablePolicy (&ValidationPolicy.Header), EFI_= INVALID_PARAMETER); + + return UNIT_TEST_PASSED; +} + +/** + Test Case +*/ +UNIT_TEST_STATUS +EFIAPI +RegisterShouldRejectUnknownLockPolicies ( + IN UNIT_TEST_CONTEXT Context + ) +{ + SIMPLE_VARIABLE_POLICY_ENTRY ValidationPolicy =3D { + { + VARIABLE_POLICY_ENTRY_REVISION, + sizeof (VARIABLE_POLICY_ENTRY) + sizeof (TEST_VAR_1_NAME), + sizeof (VARIABLE_POLICY_ENTRY), + TEST_GUID_1, + TEST_POLICY_MIN_SIZE_NULL, + TEST_POLICY_MAX_SIZE_NULL, + TEST_POLICY_ATTRIBUTES_NULL, + TEST_POLICY_ATTRIBUTES_NULL, + VARIABLE_POLICY_TYPE_NO_LOCK + }, + TEST_VAR_1_NAME + }; + + ValidationPolicy.Header.LockPolicyType =3D VARIABLE_POLICY_TYPE_LOCK_ON_= VAR_STATE + 1; + UT_ASSERT_EQUAL (RegisterVariablePolicy (&ValidationPolicy.Header), EFI_= INVALID_PARAMETER); + ValidationPolicy.Header.LockPolicyType =3D VARIABLE_POLICY_TYPE_LOCK_ON_= VAR_STATE + 1; + UT_ASSERT_EQUAL (RegisterVariablePolicy (&ValidationPolicy.Header), EFI_= INVALID_PARAMETER); + + return UNIT_TEST_PASSED; +} + +/** + Test Case +*/ +UNIT_TEST_STATUS +EFIAPI +RegisterShouldRejectPolicesWithTooManyWildcards ( + IN UNIT_TEST_CONTEXT Context + ) +{ + SIMPLE_VARIABLE_POLICY_ENTRY ValidationPolicy =3D { + { + VARIABLE_POLICY_ENTRY_REVISION, + sizeof (VARIABLE_POLICY_ENTRY) + sizeof (TEST_300_HASHES_STRING), + sizeof (VARIABLE_POLICY_ENTRY), + TEST_GUID_1, + TEST_POLICY_MIN_SIZE_NULL, + TEST_POLICY_MAX_SIZE_NULL, + TEST_POLICY_ATTRIBUTES_NULL, + TEST_POLICY_ATTRIBUTES_NULL, + VARIABLE_POLICY_TYPE_NO_LOCK + }, + TEST_300_HASHES_STRING + }; + + // 300 Hashes is currently larger than the possible maximum match priori= ty. + UT_ASSERT_EQUAL (RegisterVariablePolicy (&ValidationPolicy.Header), EFI_= INVALID_PARAMETER); + + return UNIT_TEST_PASSED; +} + +/** + Test Case +*/ +UNIT_TEST_STATUS +EFIAPI +RegisterShouldRejectDuplicatePolicies ( + IN UNIT_TEST_CONTEXT Context + ) +{ + SIMPLE_VARIABLE_POLICY_ENTRY ValidationPolicy =3D { + { + VARIABLE_POLICY_ENTRY_REVISION, + sizeof (VARIABLE_POLICY_ENTRY) + sizeof (TEST_VAR_1_NAME), + sizeof (VARIABLE_POLICY_ENTRY), + TEST_GUID_1, + TEST_POLICY_MIN_SIZE_NULL, + TEST_POLICY_MAX_SIZE_NULL, + TEST_POLICY_ATTRIBUTES_NULL, + TEST_POLICY_ATTRIBUTES_NULL, + VARIABLE_POLICY_TYPE_NO_LOCK + }, + TEST_VAR_1_NAME + }; + + UT_ASSERT_NOT_EFI_ERROR (RegisterVariablePolicy (&ValidationPolicy.Heade= r)); + UT_ASSERT_STATUS_EQUAL (RegisterVariablePolicy (&ValidationPolicy.Header= ), EFI_ALREADY_STARTED); + + return UNIT_TEST_PASSED; +} + +/** + Test Case +*/ +UNIT_TEST_STATUS +EFIAPI +MinAndMaxSizePoliciesShouldBeHonored ( + IN UNIT_TEST_CONTEXT Context + ) +{ + SIMPLE_VARIABLE_POLICY_ENTRY ValidationPolicy =3D { + { + VARIABLE_POLICY_ENTRY_REVISION, + sizeof (VARIABLE_POLICY_ENTRY) + sizeof (TEST_VAR_1_NAME), + sizeof (VARIABLE_POLICY_ENTRY), + TEST_GUID_1, + TEST_POLICY_MIN_SIZE_10, + TEST_POLICY_MAX_SIZE_200, + TEST_POLICY_ATTRIBUTES_NULL, + TEST_POLICY_ATTRIBUTES_NULL, + VARIABLE_POLICY_TYPE_NO_LOCK + }, + TEST_VAR_1_NAME + }; + EFI_STATUS PolicyCheck; + UINT8 DummyData[TEST_POLICY_MAX_SIZE_200 + 1]; + + + // Without a policy, there should be no constraints on variable creation= . + PolicyCheck =3D ValidateSetVariable ( + TEST_VAR_1_NAME, + &mTestGuid1, + VARIABLE_ATTRIBUTE_NV_BS, + TEST_POLICY_MAX_SIZE_200 + 1, + DummyData + ); + UT_ASSERT_NOT_EFI_ERROR (PolicyCheck); + + // Set a policy to test against. + UT_ASSERT_NOT_EFI_ERROR (RegisterVariablePolicy (&ValidationPolicy.Heade= r)); + + // With a policy, make sure that sizes outsize the target range fail. + PolicyCheck =3D ValidateSetVariable ( + TEST_VAR_1_NAME, + &mTestGuid1, + VARIABLE_ATTRIBUTE_NV_BS, + TEST_POLICY_MAX_SIZE_200 + 1, + DummyData + ); + UT_ASSERT_TRUE (EFI_ERROR (PolicyCheck)); + + // With a policy, make sure that sizes outsize the target range fail. + PolicyCheck =3D ValidateSetVariable ( + TEST_VAR_1_NAME, + &mTestGuid1, + VARIABLE_ATTRIBUTE_NV_BS, + TEST_POLICY_MIN_SIZE_10 - 1, + DummyData + ); + UT_ASSERT_TRUE (EFI_ERROR (PolicyCheck)); + + // With a policy, make sure a valid variable is still valid. + PolicyCheck =3D ValidateSetVariable ( + TEST_VAR_1_NAME, + &mTestGuid1, + VARIABLE_ATTRIBUTE_NV_BS, + TEST_POLICY_MIN_SIZE_10 + 1, + DummyData + ); + UT_ASSERT_NOT_EFI_ERROR (PolicyCheck); + + return UNIT_TEST_PASSED; +} + +/** + Test Case +*/ +UNIT_TEST_STATUS +EFIAPI +AttributeMustPoliciesShouldBeHonored ( + IN UNIT_TEST_CONTEXT Context + ) +{ + SIMPLE_VARIABLE_POLICY_ENTRY ValidationPolicy =3D { + { + VARIABLE_POLICY_ENTRY_REVISION, + sizeof (VARIABLE_POLICY_ENTRY) + sizeof (TEST_VAR_1_NAME), + sizeof (VARIABLE_POLICY_ENTRY), + TEST_GUID_1, + TEST_POLICY_MIN_SIZE_NULL, + TEST_POLICY_MAX_SIZE_NULL, + VARIABLE_ATTRIBUTE_NV_BS_RT, + TEST_POLICY_ATTRIBUTES_NULL, + VARIABLE_POLICY_TYPE_NO_LOCK + }, + TEST_VAR_1_NAME + }; + EFI_STATUS PolicyCheck; + UINT8 DummyData[12]; + + + // Without a policy, there should be no constraints on variable creation= . + PolicyCheck =3D ValidateSetVariable ( + TEST_VAR_1_NAME, + &mTestGuid1, + TEST_POLICY_ATTRIBUTES_NULL, + sizeof (DummyData), + DummyData + ); + UT_ASSERT_NOT_EFI_ERROR (PolicyCheck); + + // Set a policy to test against. + UT_ASSERT_NOT_EFI_ERROR (RegisterVariablePolicy (&ValidationPolicy.Heade= r)); + + // With a policy, make sure that no attributes fail. + PolicyCheck =3D ValidateSetVariable ( + TEST_VAR_1_NAME, + &mTestGuid1, + TEST_POLICY_ATTRIBUTES_NULL, + sizeof (DummyData), + DummyData + ); + UT_ASSERT_TRUE (EFI_ERROR (PolicyCheck)); + + // With a policy, make sure that some -- but not all -- attributes fail. + PolicyCheck =3D ValidateSetVariable ( + TEST_VAR_1_NAME, + &mTestGuid1, + VARIABLE_ATTRIBUTE_BS_RT_AT, + sizeof (DummyData), + DummyData + ); + UT_ASSERT_TRUE (EFI_ERROR (PolicyCheck)); + + // With a policy, make sure that all attributes pass. + PolicyCheck =3D ValidateSetVariable ( + TEST_VAR_1_NAME, + &mTestGuid1, + VARIABLE_ATTRIBUTE_NV_BS_RT, + sizeof (DummyData), + DummyData + ); + UT_ASSERT_NOT_EFI_ERROR (PolicyCheck); + + // With a policy, make sure that all attributes -- plus some -- pass. + PolicyCheck =3D ValidateSetVariable ( + TEST_VAR_1_NAME, + &mTestGuid1, + VARIABLE_ATTRIBUTE_NV_BS_RT_AT, + sizeof (DummyData), + DummyData + ); + UT_ASSERT_NOT_EFI_ERROR (PolicyCheck); + + return UNIT_TEST_PASSED; +} + +/** + Test Case +*/ +UNIT_TEST_STATUS +EFIAPI +AttributeCantPoliciesShouldBeHonored ( + IN UNIT_TEST_CONTEXT Context + ) +{ + SIMPLE_VARIABLE_POLICY_ENTRY ValidationPolicy =3D { + { + VARIABLE_POLICY_ENTRY_REVISION, + sizeof (VARIABLE_POLICY_ENTRY) + sizeof (TEST_VAR_1_NAME), + sizeof (VARIABLE_POLICY_ENTRY), + TEST_GUID_1, + TEST_POLICY_MIN_SIZE_NULL, + TEST_POLICY_MAX_SIZE_NULL, + TEST_POLICY_ATTRIBUTES_NULL, + EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS, + VARIABLE_POLICY_TYPE_NO_LOCK + }, + TEST_VAR_1_NAME + }; + EFI_STATUS PolicyCheck; + UINT8 DummyData[12]; + + + // Without a policy, there should be no constraints on variable creation= . + PolicyCheck =3D ValidateSetVariable ( + TEST_VAR_1_NAME, + &mTestGuid1, + VARIABLE_ATTRIBUTE_BS_RT_AT, + sizeof (DummyData), + DummyData + ); + UT_ASSERT_NOT_EFI_ERROR (PolicyCheck); + + // Set a policy to test against. + UT_ASSERT_NOT_EFI_ERROR (RegisterVariablePolicy (&ValidationPolicy.Heade= r)); + + // With a policy, make sure that forbidden attributes fail. + PolicyCheck =3D ValidateSetVariable ( + TEST_VAR_1_NAME, + &mTestGuid1, + EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS, + sizeof (DummyData), + DummyData + ); + UT_ASSERT_TRUE (EFI_ERROR (PolicyCheck)); + + // With a policy, make sure that a mixture of attributes -- including th= e forbidden -- fail. + PolicyCheck =3D ValidateSetVariable ( + TEST_VAR_1_NAME, + &mTestGuid1, + VARIABLE_ATTRIBUTE_BS_RT_AT, + sizeof (DummyData), + DummyData + ); + UT_ASSERT_TRUE (EFI_ERROR (PolicyCheck)); + + // With a policy, make sure that attributes without the forbidden pass. + PolicyCheck =3D ValidateSetVariable ( + TEST_VAR_1_NAME, + &mTestGuid1, + VARIABLE_ATTRIBUTE_NV_BS_RT, + sizeof (DummyData), + DummyData + ); + UT_ASSERT_NOT_EFI_ERROR (PolicyCheck); + + return UNIT_TEST_PASSED; +} + +/** + Test Case +*/ +UNIT_TEST_STATUS +EFIAPI +VariablesShouldBeDeletableRegardlessOfSize ( + IN UNIT_TEST_CONTEXT Context + ) +{ + SIMPLE_VARIABLE_POLICY_ENTRY ValidationPolicy =3D { + { + VARIABLE_POLICY_ENTRY_REVISION, + sizeof (VARIABLE_POLICY_ENTRY) + sizeof (TEST_VAR_1_NAME), + sizeof (VARIABLE_POLICY_ENTRY), + TEST_GUID_1, + TEST_POLICY_MIN_SIZE_10, + TEST_POLICY_MAX_SIZE_NULL, + TEST_POLICY_ATTRIBUTES_NULL, + EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS, + VARIABLE_POLICY_TYPE_NO_LOCK + }, + TEST_VAR_1_NAME + }; + EFI_STATUS PolicyCheck; + UINT8 DummyData[TEST_POLICY_MAX_SIZE_200+1]; + + // Create a policy enforcing a minimum variable size. + UT_ASSERT_NOT_EFI_ERROR (RegisterVariablePolicy (&ValidationPolicy.Heade= r)); + + // Make sure that a normal set would fail. + PolicyCheck =3D ValidateSetVariable ( + TEST_VAR_1_NAME, + &mTestGuid1, + VARIABLE_ATTRIBUTE_NV_BS, + TEST_POLICY_MIN_SIZE_10-1, + DummyData + ); + UT_ASSERT_STATUS_EQUAL (PolicyCheck, EFI_INVALID_PARAMETER); + + // Now make sure that a delete would succeed. + PolicyCheck =3D ValidateSetVariable ( + TEST_VAR_1_NAME, + &mTestGuid1, + VARIABLE_ATTRIBUTE_NV_BS, + 0, + NULL + ); + UT_ASSERT_NOT_EFI_ERROR (PolicyCheck); + + return UNIT_TEST_PASSED; +} + +/** + Test Case +*/ +UNIT_TEST_STATUS +EFIAPI +LockNowPoliciesShouldBeHonored ( + IN UNIT_TEST_CONTEXT Context + ) +{ + SIMPLE_VARIABLE_POLICY_ENTRY ValidationPolicy =3D { + { + VARIABLE_POLICY_ENTRY_REVISION, + sizeof (VARIABLE_POLICY_ENTRY) + sizeof (TEST_VAR_1_NAME), + sizeof (VARIABLE_POLICY_ENTRY), + TEST_GUID_1, + TEST_POLICY_MIN_SIZE_NULL, + TEST_POLICY_MAX_SIZE_NULL, + TEST_POLICY_ATTRIBUTES_NULL, + TEST_POLICY_ATTRIBUTES_NULL, + VARIABLE_POLICY_TYPE_LOCK_NOW + }, + TEST_VAR_1_NAME + }; + EFI_STATUS PolicyCheck; + UINT8 DummyData[12]; + + + // Without a policy, there should be no constraints on variable creation= . + PolicyCheck =3D ValidateSetVariable ( + TEST_VAR_1_NAME, + &mTestGuid1, + VARIABLE_ATTRIBUTE_BS_RT_AT, + sizeof (DummyData), + DummyData + ); + UT_ASSERT_NOT_EFI_ERROR (PolicyCheck); + + // Set a policy to test against. + UT_ASSERT_NOT_EFI_ERROR (RegisterVariablePolicy (&ValidationPolicy.Heade= r)); + + // With a policy, make sure that writes immediately fail. + PolicyCheck =3D ValidateSetVariable ( + TEST_VAR_1_NAME, + &mTestGuid1, + VARIABLE_ATTRIBUTE_BS_RT_AT, + sizeof (DummyData), + DummyData + ); + UT_ASSERT_TRUE (EFI_ERROR (PolicyCheck)); + + return UNIT_TEST_PASSED; +} + +/** + Test Case +*/ +UNIT_TEST_STATUS +EFIAPI +LockOnCreatePoliciesShouldBeHonored ( + IN UNIT_TEST_CONTEXT Context + ) +{ + SIMPLE_VARIABLE_POLICY_ENTRY ValidationPolicy =3D { + { + VARIABLE_POLICY_ENTRY_REVISION, + sizeof (VARIABLE_POLICY_ENTRY) + sizeof (TEST_VAR_1_NAME), + sizeof (VARIABLE_POLICY_ENTRY), + TEST_GUID_1, + TEST_POLICY_MIN_SIZE_NULL, + TEST_POLICY_MAX_SIZE_NULL, + TEST_POLICY_ATTRIBUTES_NULL, + TEST_POLICY_ATTRIBUTES_NULL, + VARIABLE_POLICY_TYPE_LOCK_ON_CREATE + }, + TEST_VAR_1_NAME + }; + EFI_STATUS PolicyCheck; + UINT8 DummyData[12]; + UINTN ExpectedDataSize; + + + // Without a policy, there should be no constraints on variable creation= . + PolicyCheck =3D ValidateSetVariable ( + TEST_VAR_1_NAME, + &mTestGuid1, + VARIABLE_ATTRIBUTE_BS_RT_AT, + sizeof (DummyData), + DummyData + ); + UT_ASSERT_NOT_EFI_ERROR (PolicyCheck); + + // Set a policy to test against. + UT_ASSERT_NOT_EFI_ERROR (RegisterVariablePolicy (&ValidationPolicy.Heade= r)); + + // Set consistent expectations on what the calls are looking for. + expect_memory_count (StubGetVariableNull, VariableName, TEST_VAR_1_NAME,= sizeof (TEST_VAR_1_NAME), 2); + expect_memory_count (StubGetVariableNull, VendorGuid, &mTestGuid1, sizeo= f (mTestGuid1), 2); + ExpectedDataSize =3D 0; + expect_memory_count (StubGetVariableNull, DataSize, &ExpectedDataSize, s= izeof (ExpectedDataSize), 2); + + // With a policy, make sure that writes still work, since the variable d= oesn't exist. + will_return (StubGetVariableNull, TEST_POLICY_ATTRIBUTES_NULL); // At= tributes + will_return (StubGetVariableNull, 0); // Si= ze + will_return (StubGetVariableNull, NULL); // Da= taPtr + will_return (StubGetVariableNull, EFI_NOT_FOUND); // St= atus + PolicyCheck =3D ValidateSetVariable ( + TEST_VAR_1_NAME, + &mTestGuid1, + VARIABLE_ATTRIBUTE_BS_RT_AT, + sizeof (DummyData), + DummyData + ); + UT_ASSERT_NOT_EFI_ERROR (PolicyCheck); + + // With a policy, make sure that a call with an "existing" variable fail= s. + will_return (StubGetVariableNull, TEST_POLICY_ATTRIBUTES_NULL); // At= tributes + will_return (StubGetVariableNull, 10); // Si= ze + will_return (StubGetVariableNull, NULL); // Da= taPtr + will_return (StubGetVariableNull, EFI_BUFFER_TOO_SMALL); // St= atus + PolicyCheck =3D ValidateSetVariable ( + TEST_VAR_1_NAME, + &mTestGuid1, + VARIABLE_ATTRIBUTE_BS_RT_AT, + sizeof (DummyData), + DummyData + ); + UT_ASSERT_TRUE (EFI_ERROR (PolicyCheck)); + + return UNIT_TEST_PASSED; +} + +/** + Test Case +*/ +UNIT_TEST_STATUS +EFIAPI +LockOnStatePoliciesShouldBeHonored ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EXPANDED_VARIABLE_POLICY_ENTRY ValidationPolicy =3D { + { + VARIABLE_POLICY_ENTRY_REVISION, + 0, // Will be populated by init helper. + 0, // Will be populated by init helper. + TEST_GUID_1, + TEST_POLICY_MIN_SIZE_NULL, + TEST_POLICY_MAX_SIZE_NULL, + TEST_POLICY_ATTRIBUTES_NULL, + TEST_POLICY_ATTRIBUTES_NULL, + VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE + }, + { + TEST_GUID_2, + 20, // Value + 0 // Padding + }, + L"", + L"" + }; + EFI_STATUS PolicyCheck; + UINT8 DummyData[12]; + UINT8 ValidationStateVar; + UINTN ExpectedDataSize; + UT_ASSERT_TRUE (InitExpVarPolicyStrings (&ValidationPolicy, TEST_VAR_1_N= AME, TEST_VAR_2_NAME)); + + + // Without a policy, there should be no constraints on variable creation= . + PolicyCheck =3D ValidateSetVariable ( + TEST_VAR_1_NAME, + &mTestGuid1, + VARIABLE_ATTRIBUTE_BS_RT_AT, + sizeof (DummyData), + DummyData + ); + UT_ASSERT_NOT_EFI_ERROR (PolicyCheck); + + // Set a policy to test against. + UT_ASSERT_NOT_EFI_ERROR (RegisterVariablePolicy (&ValidationPolicy.Heade= r)); + + // Set consistent expectations on what the calls are looking for. + expect_memory_count (StubGetVariableNull, VariableName, TEST_VAR_2_NAME,= sizeof (TEST_VAR_2_NAME), 5); + expect_memory_count (StubGetVariableNull, VendorGuid, &mTestGuid2, sizeo= f (mTestGuid2), 5); + ExpectedDataSize =3D 1; + expect_memory_count (StubGetVariableNull, DataSize, &ExpectedDataSize, s= izeof (ExpectedDataSize), 5); + + // With a policy, make sure that writes still work, since the variable d= oesn't exist. + will_return (StubGetVariableNull, TEST_POLICY_ATTRIBUTES_NULL); // At= tributes + will_return (StubGetVariableNull, 0); // Si= ze + will_return (StubGetVariableNull, NULL); // Da= taPtr + will_return (StubGetVariableNull, EFI_NOT_FOUND); // St= atus + PolicyCheck =3D ValidateSetVariable ( + TEST_VAR_1_NAME, + &mTestGuid1, + VARIABLE_ATTRIBUTE_BS_RT_AT, + sizeof (DummyData), + DummyData + ); + UT_ASSERT_NOT_EFI_ERROR (PolicyCheck); + + // With a policy, make sure that a state variable that's too large doesn= 't lock the variable. + will_return (StubGetVariableNull, TEST_POLICY_ATTRIBUTES_NULL); // At= tributes + will_return (StubGetVariableNull, 10); // Si= ze + will_return (StubGetVariableNull, NULL); // Da= taPtr + will_return (StubGetVariableNull, EFI_BUFFER_TOO_SMALL); // St= atus + PolicyCheck =3D ValidateSetVariable ( + TEST_VAR_1_NAME, + &mTestGuid1, + VARIABLE_ATTRIBUTE_BS_RT_AT, + sizeof (DummyData), + DummyData + ); + UT_ASSERT_NOT_EFI_ERROR (PolicyCheck); + + // With a policy, check a state variable with the wrong value. + ValidationStateVar =3D 0; + will_return (StubGetVariableNull, TEST_POLICY_ATTRIBUTES_NULL); // At= tributes + will_return (StubGetVariableNull, sizeof (ValidationStateVar)); // S= ize + will_return (StubGetVariableNull, &ValidationStateVar); // Da= taPtr + will_return (StubGetVariableNull, EFI_SUCCESS); // St= atus + PolicyCheck =3D ValidateSetVariable ( + TEST_VAR_1_NAME, + &mTestGuid1, + VARIABLE_ATTRIBUTE_BS_RT_AT, + sizeof (DummyData), + DummyData + ); + UT_ASSERT_NOT_EFI_ERROR (PolicyCheck); + + // With a policy, check a state variable with another wrong value. + ValidationStateVar =3D 10; + will_return (StubGetVariableNull, TEST_POLICY_ATTRIBUTES_NULL); // At= tributes + will_return (StubGetVariableNull, sizeof (ValidationStateVar)); // S= ize + will_return (StubGetVariableNull, &ValidationStateVar); // Da= taPtr + will_return (StubGetVariableNull, EFI_SUCCESS); // St= atus + PolicyCheck =3D ValidateSetVariable ( + TEST_VAR_1_NAME, + &mTestGuid1, + VARIABLE_ATTRIBUTE_BS_RT_AT, + sizeof (DummyData), + DummyData + ); + UT_ASSERT_NOT_EFI_ERROR (PolicyCheck); + + // With a policy, make sure that a call with a correct state variable fa= ils. + ValidationStateVar =3D 20; + will_return (StubGetVariableNull, TEST_POLICY_ATTRIBUTES_NULL); // At= tributes + will_return (StubGetVariableNull, sizeof (ValidationStateVar)); // S= ize + will_return (StubGetVariableNull, &ValidationStateVar); // Da= taPtr + will_return (StubGetVariableNull, EFI_SUCCESS); // St= atus + PolicyCheck =3D ValidateSetVariable ( + TEST_VAR_1_NAME, + &mTestGuid1, + VARIABLE_ATTRIBUTE_BS_RT_AT, + sizeof (DummyData), + DummyData + ); + UT_ASSERT_TRUE (EFI_ERROR (PolicyCheck)); + + return UNIT_TEST_PASSED; +} + +/** + Test Case +*/ +UNIT_TEST_STATUS +EFIAPI +LockOnStatePoliciesShouldApplyToNamespaces ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EXPANDED_VARIABLE_POLICY_ENTRY ValidationPolicy =3D { + { + VARIABLE_POLICY_ENTRY_REVISION, + 0, // Will be populated by init helper. + 0, // Will be populated by init helper. + TEST_GUID_1, + TEST_POLICY_MIN_SIZE_NULL, + TEST_POLICY_MAX_SIZE_NULL, + TEST_POLICY_ATTRIBUTES_NULL, + TEST_POLICY_ATTRIBUTES_NULL, + VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE + }, + { + TEST_GUID_2, + 20, // Value + 0 // Padding + }, + L"", + L"" + }; + EFI_STATUS PolicyCheck; + UINT8 DummyData[12]; + UINT8 ValidationStateVar; + UINTN ExpectedDataSize; + UT_ASSERT_TRUE (InitExpVarPolicyStrings (&ValidationPolicy, NULL, TEST_V= AR_2_NAME)); + + + // Without a policy, there should be no constraints on variable creation= . + PolicyCheck =3D ValidateSetVariable ( + TEST_VAR_1_NAME, + &mTestGuid1, + VARIABLE_ATTRIBUTE_BS_RT_AT, + sizeof (DummyData), + DummyData + ); + UT_ASSERT_NOT_EFI_ERROR (PolicyCheck); + PolicyCheck =3D ValidateSetVariable ( + TEST_VAR_3_NAME, + &mTestGuid1, + VARIABLE_ATTRIBUTE_BS_RT_AT, + sizeof (DummyData), + DummyData + ); + UT_ASSERT_NOT_EFI_ERROR (PolicyCheck); + + // Set a policy to test against. + UT_ASSERT_NOT_EFI_ERROR (RegisterVariablePolicy (&ValidationPolicy.Heade= r)); + + // Set consistent expectations on what the calls are looking for. + expect_memory_count (StubGetVariableNull, VariableName, TEST_VAR_2_NAME,= sizeof (TEST_VAR_2_NAME), 4); + expect_memory_count (StubGetVariableNull, VendorGuid, &mTestGuid2, sizeo= f (mTestGuid2), 4); + ExpectedDataSize =3D 1; + expect_memory_count (StubGetVariableNull, DataSize, &ExpectedDataSize, s= izeof (ExpectedDataSize), 4); + + // With a policy, make sure that writes still work, since the variable d= oesn't exist. + will_return (StubGetVariableNull, TEST_POLICY_ATTRIBUTES_NULL); // At= tributes + will_return (StubGetVariableNull, 0); // Si= ze + will_return (StubGetVariableNull, NULL); // Da= taPtr + will_return (StubGetVariableNull, EFI_NOT_FOUND); // St= atus + PolicyCheck =3D ValidateSetVariable ( + TEST_VAR_1_NAME, + &mTestGuid1, + VARIABLE_ATTRIBUTE_BS_RT_AT, + sizeof (DummyData), + DummyData + ); + UT_ASSERT_NOT_EFI_ERROR (PolicyCheck); + will_return (StubGetVariableNull, TEST_POLICY_ATTRIBUTES_NULL); // At= tributes + will_return (StubGetVariableNull, 0); // Si= ze + will_return (StubGetVariableNull, NULL); // Da= taPtr + will_return (StubGetVariableNull, EFI_NOT_FOUND); // St= atus + PolicyCheck =3D ValidateSetVariable ( + TEST_VAR_3_NAME, + &mTestGuid1, + VARIABLE_ATTRIBUTE_BS_RT_AT, + sizeof (DummyData), + DummyData + ); + UT_ASSERT_NOT_EFI_ERROR (PolicyCheck); + + // With a policy, make sure that a call with a correct state variable fa= ils. + ValidationStateVar =3D 20; + will_return (StubGetVariableNull, TEST_POLICY_ATTRIBUTES_NULL); // At= tributes + will_return (StubGetVariableNull, sizeof (ValidationStateVar)); // S= ize + will_return (StubGetVariableNull, &ValidationStateVar); // Da= taPtr + will_return (StubGetVariableNull, EFI_SUCCESS); // St= atus + PolicyCheck =3D ValidateSetVariable ( + TEST_VAR_1_NAME, + &mTestGuid1, + VARIABLE_ATTRIBUTE_BS_RT_AT, + sizeof (DummyData), + DummyData + ); + UT_ASSERT_TRUE (EFI_ERROR (PolicyCheck)); + will_return (StubGetVariableNull, TEST_POLICY_ATTRIBUTES_NULL); // At= tributes + will_return (StubGetVariableNull, sizeof (ValidationStateVar)); // S= ize + will_return (StubGetVariableNull, &ValidationStateVar); // Da= taPtr + will_return (StubGetVariableNull, EFI_SUCCESS); // St= atus + PolicyCheck =3D ValidateSetVariable ( + TEST_VAR_3_NAME, + &mTestGuid1, + VARIABLE_ATTRIBUTE_BS_RT_AT, + sizeof (DummyData), + DummyData + ); + UT_ASSERT_TRUE (EFI_ERROR (PolicyCheck)); + + return UNIT_TEST_PASSED; +} + +/** + Test Case +*/ +UNIT_TEST_STATUS +EFIAPI +LockOnStateShouldHandleErrorsGracefully ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EXPANDED_VARIABLE_POLICY_ENTRY ValidationPolicy =3D { + { + VARIABLE_POLICY_ENTRY_REVISION, + 0, // Will be populated by init helper. + 0, // Will be populated by init helper. + TEST_GUID_1, + TEST_POLICY_MIN_SIZE_NULL, + TEST_POLICY_MAX_SIZE_NULL, + TEST_POLICY_ATTRIBUTES_NULL, + TEST_POLICY_ATTRIBUTES_NULL, + VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE + }, + { + TEST_GUID_2, + 20, // Value + 0 // Padding + }, + L"", + L"" + }; + EFI_STATUS PolicyCheck; + UINT8 DummyData[12]; + UT_ASSERT_TRUE (InitExpVarPolicyStrings (&ValidationPolicy, TEST_VAR_1_N= AME, TEST_VAR_2_NAME)); + + + // Without a policy, there should be no constraints on variable creation= . + PolicyCheck =3D ValidateSetVariable ( + TEST_VAR_1_NAME, + &mTestGuid1, + VARIABLE_ATTRIBUTE_BS_RT_AT, + sizeof (DummyData), + DummyData + ); + UT_ASSERT_NOT_EFI_ERROR (PolicyCheck); + + // Set a policy to test against. + UT_ASSERT_NOT_EFI_ERROR (RegisterVariablePolicy (&ValidationPolicy.Heade= r)); + + // Configure the stub to not care about parameters. We're testing errors= . + expect_any_always (StubGetVariableNull, VariableName); + expect_any_always (StubGetVariableNull, VendorGuid); + expect_any_always (StubGetVariableNull, DataSize); + + // With a policy, make sure that writes still work, since the variable d= oesn't exist. + will_return (StubGetVariableNull, TEST_POLICY_ATTRIBUTES_NULL); // At= tributes + will_return (StubGetVariableNull, 0); // Si= ze + will_return (StubGetVariableNull, NULL); // Da= taPtr + will_return (StubGetVariableNull, EFI_NOT_FOUND); // St= atus + PolicyCheck =3D ValidateSetVariable ( + TEST_VAR_1_NAME, + &mTestGuid1, + VARIABLE_ATTRIBUTE_BS_RT_AT, + sizeof (DummyData), + DummyData + ); + UT_ASSERT_NOT_EFI_ERROR (PolicyCheck); + + // Verify that state variables that are the wrong size won't lock the va= riable. + will_return (StubGetVariableNull, TEST_POLICY_ATTRIBUTES_NULL); // At= tributes + will_return (StubGetVariableNull, 0); // Si= ze + will_return (StubGetVariableNull, NULL); // Da= taPtr + will_return (StubGetVariableNull, EFI_BUFFER_TOO_SMALL); // St= atus + PolicyCheck =3D ValidateSetVariable ( + TEST_VAR_1_NAME, + &mTestGuid1, + VARIABLE_ATTRIBUTE_BS_RT_AT, + sizeof (DummyData), + DummyData + ); + UT_ASSERT_NOT_EFI_ERROR (PolicyCheck); + + // Verify that unexpected errors default to locked. + will_return (StubGetVariableNull, TEST_POLICY_ATTRIBUTES_NULL); // At= tributes + will_return (StubGetVariableNull, 0); // Si= ze + will_return (StubGetVariableNull, NULL); // Da= taPtr + will_return (StubGetVariableNull, EFI_UNSUPPORTED); // St= atus + PolicyCheck =3D ValidateSetVariable ( + TEST_VAR_1_NAME, + &mTestGuid1, + VARIABLE_ATTRIBUTE_BS_RT_AT, + sizeof (DummyData), + DummyData + ); + UT_ASSERT_TRUE (EFI_ERROR (PolicyCheck)); + + will_return (StubGetVariableNull, TEST_POLICY_ATTRIBUTES_NULL); // At= tributes + will_return (StubGetVariableNull, 0); // Si= ze + will_return (StubGetVariableNull, NULL); // Da= taPtr + will_return (StubGetVariableNull, EFI_NOT_READY); // St= atus + PolicyCheck =3D ValidateSetVariable ( + TEST_VAR_1_NAME, + &mTestGuid1, + VARIABLE_ATTRIBUTE_BS_RT_AT, + sizeof (DummyData), + DummyData + ); + UT_ASSERT_TRUE (EFI_ERROR (PolicyCheck)); + + return UNIT_TEST_PASSED; +} + +/** + Test Case +*/ +UNIT_TEST_STATUS +EFIAPI +BestMatchPriorityShouldBeObeyed ( + IN UNIT_TEST_CONTEXT Context + ) +{ + SIMPLE_VARIABLE_POLICY_ENTRY ValidationPolicy =3D { + { + VARIABLE_POLICY_ENTRY_REVISION, + sizeof (VARIABLE_POLICY_ENTRY) + sizeof (L"Wild12Card34Placeholder")= , + sizeof (VARIABLE_POLICY_ENTRY), + TEST_GUID_1, + TEST_POLICY_MIN_SIZE_NULL, + TEST_POLICY_MAX_SIZE_NULL, + TEST_POLICY_ATTRIBUTES_NULL, + TEST_POLICY_ATTRIBUTES_NULL, + VARIABLE_POLICY_TYPE_NO_LOCK + }, + L"Wild12Card34Placeholder" + }; + EFI_STATUS PolicyCheck; + UINT8 DummyData[70]; + CHAR16 *PolicyName =3D (CHAR16 *) ((UINT8 *) &ValidationPolicy + si= zeof (VARIABLE_POLICY_ENTRY)); + UINTN PolicyNameSize =3D sizeof (L"Wild12Card34Placeholder"); + CHAR16 *FourWildcards =3D L"Wild##Card##Placeholder"; + CHAR16 *ThreeWildcards =3D L"Wild##Card#4Placeholder"; + CHAR16 *TwoWildcards =3D L"Wild##Card34Placeholder"; + CHAR16 *OneWildcard =3D L"Wild#2Card34Placeholder"; + CHAR16 *NoWildcards =3D L"Wild12Card34Placeholder"; + + // Create all of the policies from least restrictive to most restrictive= . + // NoWildcards should be the most restrictive. + ValidationPolicy.Header.MaxSize =3D 60; + ValidationPolicy.Header.Size =3D ValidationPolicy.Header.OffsetToName; + UT_ASSERT_NOT_EFI_ERROR (RegisterVariablePolicy (&ValidationPolicy.Heade= r)); + ValidationPolicy.Header.Size +=3D (UINT16) PolicyNameSize; + ValidationPolicy.Header.MaxSize =3D 50; + CopyMem (PolicyName, FourWildcards, PolicyNameSize); + UT_ASSERT_NOT_EFI_ERROR (RegisterVariablePolicy (&ValidationPolicy.Heade= r)); + ValidationPolicy.Header.MaxSize =3D 40; + CopyMem (PolicyName, ThreeWildcards, PolicyNameSize); + UT_ASSERT_NOT_EFI_ERROR (RegisterVariablePolicy (&ValidationPolicy.Heade= r)); + ValidationPolicy.Header.MaxSize =3D 30; + CopyMem (PolicyName, TwoWildcards, PolicyNameSize); + UT_ASSERT_NOT_EFI_ERROR (RegisterVariablePolicy (&ValidationPolicy.Heade= r)); + ValidationPolicy.Header.MaxSize =3D 20; + CopyMem (PolicyName, OneWildcard, PolicyNameSize); + UT_ASSERT_NOT_EFI_ERROR (RegisterVariablePolicy (&ValidationPolicy.Heade= r)); + ValidationPolicy.Header.MaxSize =3D 10; + CopyMem (PolicyName, NoWildcards, PolicyNameSize); + UT_ASSERT_NOT_EFI_ERROR (RegisterVariablePolicy (&ValidationPolicy.Heade= r)); + + // Verify that variables only matching the namespace have the most flexi= ble policy. + PolicyCheck =3D ValidateSetVariable ( + L"ArbitraryName", + &mTestGuid1, + VARIABLE_ATTRIBUTE_BS_RT_AT, + 65, + DummyData + ); + UT_ASSERT_TRUE (EFI_ERROR (PolicyCheck)); + PolicyCheck =3D ValidateSetVariable ( + L"ArbitraryName", + &mTestGuid1, + VARIABLE_ATTRIBUTE_BS_RT_AT, + 55, + DummyData + ); + UT_ASSERT_NOT_EFI_ERROR (PolicyCheck); + + // Verify that variables matching increasing characters get increasing p= olicy restrictions. + PolicyCheck =3D ValidateSetVariable ( + L"Wild77Card77Placeholder", + &mTestGuid1, + VARIABLE_ATTRIBUTE_BS_RT_AT, + 55, + DummyData + ); + UT_ASSERT_TRUE (EFI_ERROR (PolicyCheck)); + PolicyCheck =3D ValidateSetVariable ( + L"Wild77Card77Placeholder", + &mTestGuid1, + VARIABLE_ATTRIBUTE_BS_RT_AT, + 45, + DummyData + ); + UT_ASSERT_NOT_EFI_ERROR (PolicyCheck); + + PolicyCheck =3D ValidateSetVariable ( + L"Wild77Card74Placeholder", + &mTestGuid1, + VARIABLE_ATTRIBUTE_BS_RT_AT, + 45, + DummyData + ); + UT_ASSERT_TRUE (EFI_ERROR (PolicyCheck)); + PolicyCheck =3D ValidateSetVariable ( + L"Wild77Card74Placeholder", + &mTestGuid1, + VARIABLE_ATTRIBUTE_BS_RT_AT, + 35, + DummyData + ); + UT_ASSERT_NOT_EFI_ERROR (PolicyCheck); + + PolicyCheck =3D ValidateSetVariable ( + L"Wild77Card34Placeholder", + &mTestGuid1, + VARIABLE_ATTRIBUTE_BS_RT_AT, + 35, + DummyData + ); + UT_ASSERT_TRUE (EFI_ERROR (PolicyCheck)); + PolicyCheck =3D ValidateSetVariable ( + L"Wild77Card34Placeholder", + &mTestGuid1, + VARIABLE_ATTRIBUTE_BS_RT_AT, + 25, + DummyData + ); + UT_ASSERT_NOT_EFI_ERROR (PolicyCheck); + + PolicyCheck =3D ValidateSetVariable ( + L"Wild72Card34Placeholder", + &mTestGuid1, + VARIABLE_ATTRIBUTE_BS_RT_AT, + 25, + DummyData + ); + UT_ASSERT_TRUE (EFI_ERROR (PolicyCheck)); + PolicyCheck =3D ValidateSetVariable ( + L"Wild72Card34Placeholder", + &mTestGuid1, + VARIABLE_ATTRIBUTE_BS_RT_AT, + 15, + DummyData + ); + UT_ASSERT_NOT_EFI_ERROR (PolicyCheck); + + PolicyCheck =3D ValidateSetVariable ( + L"Wild12Card34Placeholder", + &mTestGuid1, + VARIABLE_ATTRIBUTE_BS_RT_AT, + 15, + DummyData + ); + UT_ASSERT_TRUE (EFI_ERROR (PolicyCheck)); + PolicyCheck =3D ValidateSetVariable ( + L"Wild12Card34Placeholder", + &mTestGuid1, + VARIABLE_ATTRIBUTE_BS_RT_AT, + 5, + DummyData + ); + UT_ASSERT_NOT_EFI_ERROR (PolicyCheck); + + return UNIT_TEST_PASSED; +} + + +///=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 + +/** + Test Case +*/ +UNIT_TEST_STATUS +EFIAPI +ShouldBeAbleToLockInterface ( + IN UNIT_TEST_CONTEXT Context + ) +{ + SIMPLE_VARIABLE_POLICY_ENTRY TestPolicy =3D { + { + VARIABLE_POLICY_ENTRY_REVISION, + sizeof (VARIABLE_POLICY_ENTRY) + sizeof (TEST_VAR_1_NAME), + sizeof (VARIABLE_POLICY_ENTRY), + TEST_GUID_1, + TEST_POLICY_MIN_SIZE_NULL, + TEST_POLICY_MAX_SIZE_NULL, + TEST_POLICY_ATTRIBUTES_NULL, + TEST_POLICY_ATTRIBUTES_NULL, + VARIABLE_POLICY_TYPE_NO_LOCK + }, + TEST_VAR_1_NAME + }; + + // Make sure it's not already locked. + UT_ASSERT_FALSE (IsVariablePolicyInterfaceLocked ()); + // Lock it. + UT_ASSERT_NOT_EFI_ERROR (LockVariablePolicy ()); + // Verify that it's locked. + UT_ASSERT_TRUE (IsVariablePolicyInterfaceLocked ()); + + // Verify that all state-changing commands fail. + UT_ASSERT_TRUE (EFI_ERROR (LockVariablePolicy ())); + UT_ASSERT_TRUE (EFI_ERROR (DisableVariablePolicy ())); + UT_ASSERT_TRUE (EFI_ERROR (RegisterVariablePolicy (&TestPolicy.Header)))= ; + + return UNIT_TEST_PASSED; +} + +/** + Test Case +*/ +UNIT_TEST_STATUS +EFIAPI +ShouldBeAbleToDisablePolicyEnforcement ( + IN UNIT_TEST_CONTEXT Context + ) +{ + SIMPLE_VARIABLE_POLICY_ENTRY TestPolicy =3D { + { + VARIABLE_POLICY_ENTRY_REVISION, + sizeof (VARIABLE_POLICY_ENTRY) + sizeof (TEST_VAR_1_NAME), + sizeof (VARIABLE_POLICY_ENTRY), + TEST_GUID_1, + TEST_POLICY_MIN_SIZE_10, + TEST_POLICY_MAX_SIZE_200, + TEST_POLICY_ATTRIBUTES_NULL, + TEST_POLICY_ATTRIBUTES_NULL, + VARIABLE_POLICY_TYPE_NO_LOCK + }, + TEST_VAR_1_NAME + }; + EFI_STATUS PolicyCheck; + UINT8 DummyData[TEST_POLICY_MIN_SIZE_10-1]; + + // Make sure that the policy enforcement is currently enabled. + UT_ASSERT_TRUE (IsVariablePolicyEnabled ()); + // Add a policy before it's disabled. + UT_ASSERT_NOT_EFI_ERROR (RegisterVariablePolicy (&TestPolicy.Header)); + // Disable the policy enforcement. + UT_ASSERT_NOT_EFI_ERROR (DisableVariablePolicy ()); + // Make sure that the policy enforcement is currently disabled. + UT_ASSERT_FALSE (IsVariablePolicyEnabled ()); + + // Check to make sure that a policy violation still passes. + PolicyCheck =3D ValidateSetVariable ( + TEST_VAR_1_NAME, + &mTestGuid1, + VARIABLE_ATTRIBUTE_NV_BS, + sizeof (DummyData), + DummyData + ); + UT_ASSERT_NOT_EFI_ERROR (PolicyCheck); + + return UNIT_TEST_PASSED; +} + +/** + Test Case +*/ +UNIT_TEST_STATUS +EFIAPI +ShouldNotBeAbleToDisablePoliciesTwice ( + IN UNIT_TEST_CONTEXT Context + ) +{ + // Make sure that the policy enforcement is currently enabled. + UT_ASSERT_TRUE (IsVariablePolicyEnabled ()); + // Disable the policy enforcement. + UT_ASSERT_NOT_EFI_ERROR (DisableVariablePolicy ()); + // Make sure that the policy enforcement is currently disabled. + UT_ASSERT_FALSE (IsVariablePolicyEnabled ()); + // Try to disable again and verify failure. + UT_ASSERT_TRUE (EFI_ERROR (DisableVariablePolicy ())); + + return UNIT_TEST_PASSED; +} + +/** + Test Case +*/ +UNIT_TEST_STATUS +EFIAPI +ShouldBeAbleToAddNewPoliciesAfterDisabled ( + IN UNIT_TEST_CONTEXT Context + ) +{ + SIMPLE_VARIABLE_POLICY_ENTRY TestPolicy =3D { + { + VARIABLE_POLICY_ENTRY_REVISION, + sizeof (VARIABLE_POLICY_ENTRY) + sizeof (TEST_VAR_1_NAME), + sizeof (VARIABLE_POLICY_ENTRY), + TEST_GUID_1, + TEST_POLICY_MIN_SIZE_10, + TEST_POLICY_MAX_SIZE_200, + TEST_POLICY_ATTRIBUTES_NULL, + TEST_POLICY_ATTRIBUTES_NULL, + VARIABLE_POLICY_TYPE_NO_LOCK + }, + TEST_VAR_1_NAME + }; + EFI_STATUS PolicyCheck; + + // Make sure that the policy enforcement is currently enabled. + UT_ASSERT_TRUE (IsVariablePolicyEnabled ()); + // Disable the policy enforcement. + UT_ASSERT_NOT_EFI_ERROR (DisableVariablePolicy ()); + + // Make sure that new policy creation still works, it just won't be enfo= rced. + PolicyCheck =3D RegisterVariablePolicy (&TestPolicy.Header); + UT_ASSERT_NOT_EFI_ERROR (PolicyCheck); + + return UNIT_TEST_PASSED; +} + +/** + Test Case +*/ +UNIT_TEST_STATUS +EFIAPI +ShouldBeAbleToLockAfterDisabled ( + IN UNIT_TEST_CONTEXT Context + ) +{ + // Make sure that the policy enforcement is currently enabled. + UT_ASSERT_TRUE (IsVariablePolicyEnabled ()); + // Disable the policy enforcement. + UT_ASSERT_NOT_EFI_ERROR (DisableVariablePolicy ()); + + // Make sure that we can lock in this state. + UT_ASSERT_FALSE (IsVariablePolicyInterfaceLocked ()); + UT_ASSERT_NOT_EFI_ERROR (LockVariablePolicy ()); + UT_ASSERT_TRUE (IsVariablePolicyInterfaceLocked ()); + + return UNIT_TEST_PASSED; +} + +/** + Test Case +*/ +UNIT_TEST_STATUS +EFIAPI +ShouldBeAbleToDumpThePolicyTable ( + IN UNIT_TEST_CONTEXT Context + ) +{ + SIMPLE_VARIABLE_POLICY_ENTRY TestPolicy =3D { + { + VARIABLE_POLICY_ENTRY_REVISION, + sizeof (VARIABLE_POLICY_ENTRY) + sizeof (TEST_VAR_1_NAME), + sizeof (VARIABLE_POLICY_ENTRY), + TEST_GUID_1, + TEST_POLICY_MIN_SIZE_10, + TEST_POLICY_MAX_SIZE_200, + TEST_POLICY_ATTRIBUTES_NULL, + TEST_POLICY_ATTRIBUTES_NULL, + VARIABLE_POLICY_TYPE_NO_LOCK + }, + TEST_VAR_1_NAME + }; + EFI_STATUS PolicyCheck; + UINT32 DumpSize; + UINT32 BufferSize; + VOID *DumpBuffer; + + // For good measure, test some parameter validation. + UT_ASSERT_STATUS_EQUAL (DumpVariablePolicy (NULL, NULL), EFI_INVALID_PAR= AMETER); + DumpSize =3D 10; + UT_ASSERT_STATUS_EQUAL (DumpVariablePolicy (NULL, &DumpSize), EFI_INVALI= D_PARAMETER); + + // Now for the actual test case. + + // Allocate a buffer to hold the output. + BufferSize =3D sizeof (VARIABLE_POLICY_ENTRY) + sizeof (TEST_VAR_1_NAME)= ; + DumpBuffer =3D AllocatePool (BufferSize); + UT_ASSERT_NOT_EQUAL (DumpBuffer, NULL); + + // Verify that the current table size is 0. + DumpSize =3D BufferSize; + UT_ASSERT_NOT_EFI_ERROR (DumpVariablePolicy (DumpBuffer, &DumpSize)); + UT_ASSERT_EQUAL (DumpSize, 0); + + // Now, set a new policy. + UT_ASSERT_NOT_EFI_ERROR (RegisterVariablePolicy (&TestPolicy.Header)); + + // Make sure that the new return is non-zero and fails as expected. + DumpSize =3D 0; + PolicyCheck =3D DumpVariablePolicy (NULL, &DumpSize); + UT_ASSERT_STATUS_EQUAL (PolicyCheck, EFI_BUFFER_TOO_SMALL); + UT_ASSERT_EQUAL (DumpSize, BufferSize); + + // Now verify that we can fetch the dump. + DumpSize =3D BufferSize; + UT_ASSERT_NOT_EFI_ERROR (DumpVariablePolicy (DumpBuffer, &DumpSize)); + UT_ASSERT_EQUAL (DumpSize, BufferSize); + UT_ASSERT_MEM_EQUAL (&TestPolicy, DumpBuffer, BufferSize); + + // Always put away your toys. + FreePool (DumpBuffer); + + return UNIT_TEST_PASSED; +} + +/** + Test Case +*/ +UNIT_TEST_STATUS +EFIAPI +ShouldBeAbleToDumpThePolicyTableAfterDisabled ( + IN UNIT_TEST_CONTEXT Context + ) +{ + SIMPLE_VARIABLE_POLICY_ENTRY TestPolicy =3D { + { + VARIABLE_POLICY_ENTRY_REVISION, + sizeof (VARIABLE_POLICY_ENTRY) + sizeof (TEST_VAR_1_NAME), + sizeof (VARIABLE_POLICY_ENTRY), + TEST_GUID_1, + TEST_POLICY_MIN_SIZE_10, + TEST_POLICY_MAX_SIZE_200, + TEST_POLICY_ATTRIBUTES_NULL, + TEST_POLICY_ATTRIBUTES_NULL, + VARIABLE_POLICY_TYPE_NO_LOCK + }, + TEST_VAR_1_NAME + }; + SIMPLE_VARIABLE_POLICY_ENTRY TestPolicy2 =3D { + { + VARIABLE_POLICY_ENTRY_REVISION, + sizeof (VARIABLE_POLICY_ENTRY) + sizeof (TEST_VAR_2_NAME), + sizeof (VARIABLE_POLICY_ENTRY), + TEST_GUID_2, + TEST_POLICY_MIN_SIZE_10, + TEST_POLICY_MAX_SIZE_200, + TEST_POLICY_ATTRIBUTES_NULL, + TEST_POLICY_ATTRIBUTES_NULL, + VARIABLE_POLICY_TYPE_NO_LOCK + }, + TEST_VAR_2_NAME + }; + EFI_STATUS PolicyCheck; + UINT32 DumpSize; + VOID *DumpBuffer; + + DumpBuffer =3D NULL; + DumpSize =3D 0; + + // Register a new policy. + UT_ASSERT_NOT_EFI_ERROR (RegisterVariablePolicy (&TestPolicy.Header)); + // Make sure that we can dump the policy. + PolicyCheck =3D DumpVariablePolicy (DumpBuffer, &DumpSize); + UT_ASSERT_STATUS_EQUAL (PolicyCheck, EFI_BUFFER_TOO_SMALL); + DumpBuffer =3D AllocatePool (DumpSize); + UT_ASSERT_NOT_EFI_ERROR (DumpVariablePolicy (DumpBuffer, &DumpSize)); + UT_ASSERT_MEM_EQUAL (DumpBuffer, &TestPolicy, DumpSize); + + // Clean up from this step. + FreePool (DumpBuffer); + DumpBuffer =3D NULL; + DumpSize =3D 0; + + // Now disable the engine. + DisableVariablePolicy (); + + // Now register a new policy and make sure that both can be dumped. + UT_ASSERT_NOT_EFI_ERROR (RegisterVariablePolicy (&TestPolicy2.Header)); + // Make sure that we can dump the policy. + PolicyCheck =3D DumpVariablePolicy (DumpBuffer, &DumpSize); + UT_ASSERT_STATUS_EQUAL (PolicyCheck, EFI_BUFFER_TOO_SMALL); + DumpBuffer =3D AllocatePool (DumpSize); + UT_ASSERT_NOT_EFI_ERROR (DumpVariablePolicy (DumpBuffer, &DumpSize)); + + // Finally, make sure that both policies are in the dump. + UT_ASSERT_MEM_EQUAL (DumpBuffer, &TestPolicy, TestPolicy.Header.Size); + UT_ASSERT_MEM_EQUAL ( + (UINT8 *) DumpBuffer + TestPolicy.Header.Size, + &TestPolicy2, + TestPolicy2.Header.Size + ); + + // Always put away your toys. + FreePool (DumpBuffer); + + return UNIT_TEST_PASSED; +} + + +///=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 + +/** + SampleUnitTestApp + + @param[in] ImageHandle The firmware allocated handle for the EFI image. + @param[in] SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The entry point executed successfully. + @retval other Some error occurred when executing this entry po= int. + +**/ +int +main ( + ) +{ + EFI_STATUS Status; + UNIT_TEST_FRAMEWORK_HANDLE Framework =3D NULL; + UNIT_TEST_SUITE_HANDLE ArchTests; + UNIT_TEST_SUITE_HANDLE PolicyTests; + UNIT_TEST_SUITE_HANDLE UtilityTests; +#ifdef INTERNAL_UNIT_TEST + UNIT_TEST_SUITE_HANDLE InternalTests; +#endif // INTERNAL_UNIT_TEST + + DEBUG ((DEBUG_INFO, "%a v%a\n", UNIT_TEST_NAME, UNIT_TEST_VERSION)); + + // + // Start setting up the test framework for running the tests. + // + Status =3D InitUnitTestFramework (&Framework, UNIT_TEST_NAME, gEfiCaller= BaseName, UNIT_TEST_VERSION); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Failed in InitUnitTestFramework. Status =3D %r\n= ", Status)); + goto EXIT; + } + + + // + // Add all test suites and tests. + // + Status =3D CreateUnitTestSuite (&ArchTests, Framework, "Variable Policy = Architectural Tests", "VarPolicy.Arch", NULL, NULL); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Failed in CreateUnitTestSuite for ArchTests\n"))= ; + Status =3D EFI_OUT_OF_RESOURCES; + goto EXIT; + } + AddTestCase (ArchTests, + "Deinitialization should fail if not previously initialize= d", "VarPolicy.Arch.OnlyDeinit", + ShouldFailDeinitWithoutInit, NULL, NULL, NULL); + AddTestCase (ArchTests, + "Initialization followed by deinitialization should succee= d", "VarPolicy.Arch.InitDeinit", + ShouldBeAbleToInitAndDeinitTheLibrary, NULL, NULL, NULL); + AddTestCase (ArchTests, + "The initialization function fail if called twice without = a deinit", "VarPolicy.Arch.InitTwice", + ShouldNotBeAbleToInitializeTheLibraryTwice, NULL, LibClean= up, NULL); + AddTestCase (ArchTests, + "API functions should be unavailable until library is init= ialized", "VarPolicy.Arch.UninitApiOff", + ApiCommandsShouldNotRespondIfLibIsUninitialized, NULL, Lib= Cleanup, NULL); + +#ifdef INTERNAL_UNIT_TEST + Status =3D CreateUnitTestSuite (&InternalTests, Framework, "Variable Pol= icy Internal Tests", "VarPolicy.Internal", NULL, NULL); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Failed in CreateUnitTestSuite for InternalTests\= n")); + Status =3D EFI_OUT_OF_RESOURCES; + goto EXIT; + } + AddTestCase (InternalTests, + "Policy matching should use name and GUID", "VarPolicy.Int= ernal.NameGuid", + PoliciesShouldMatchByNameAndGuid, LibInitMocked, LibCleanu= p, NULL); + AddTestCase (InternalTests, + "# sign wildcards should match digits", "VarPolicy.Interna= l.WildDigits", + WildcardPoliciesShouldMatchDigits, LibInitMocked, LibClean= up, NULL); + AddTestCase (InternalTests, + "Digit wildcards should check edge cases", "VarPolicy.Inte= rnal.WildDigitsAdvanced", + WildcardPoliciesShouldMatchDigitsAdvanced, LibInitMocked, = LibCleanup, NULL); + AddTestCase (InternalTests, + "Empty names should match an entire namespace", "VarPolicy= .Internal.WildNamespace", + WildcardPoliciesShouldMatchNamespaces, LibInitMocked, LibC= leanup, NULL); + AddTestCase (InternalTests, + "Match priority should weight correctly based on wildcards= ", "VarPolicy.Internal.Priorities", + MatchPrioritiesShouldFollowRules, LibInitMocked, LibCleanu= p, NULL); +#endif // INTERNAL_UNIT_TEST + + Status =3D CreateUnitTestSuite (&PolicyTests, Framework, "Variable Polic= y Manipulation Tests", "VarPolicy.Policy", NULL, NULL); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Failed in CreateUnitTestSuite for PolicyTests\n"= )); + Status =3D EFI_OUT_OF_RESOURCES; + goto EXIT; + } + AddTestCase (PolicyTests, + "RegisterShouldAllowNamespaceWildcards", "VarPolicy.Policy= .AllowNamespace", + RegisterShouldAllowNamespaceWildcards, LibInitMocked, LibC= leanup, NULL); + AddTestCase (PolicyTests, + "RegisterShouldAllowStateVarsForNamespaces", "VarPolicy.Po= licy.AllowStateNamespace", + RegisterShouldAllowStateVarsForNamespaces, LibInitMocked, = LibCleanup, NULL); + AddTestCase (PolicyTests, + "RegisterShouldRejectNullPointers", "VarPolicy.Policy.Null= Pointers", + RegisterShouldRejectNullPointers, LibInitMocked, LibCleanu= p, NULL); + AddTestCase (PolicyTests, + "RegisterShouldRejectBadRevisions", "VarPolicy.Policy.BadR= evisions", + RegisterShouldRejectBadRevisions, LibInitMocked, LibCleanu= p, NULL); + AddTestCase (PolicyTests, + "RegisterShouldRejectBadSizes", "VarPolicy.Policy.BadSizes= ", + RegisterShouldRejectBadSizes, LibInitMocked, LibCleanup, N= ULL); + AddTestCase (PolicyTests, + "RegisterShouldRejectBadOffsets", "VarPolicy.Policy.BadOff= sets", + RegisterShouldRejectBadOffsets, LibInitMocked, LibCleanup,= NULL); + AddTestCase (PolicyTests, + "RegisterShouldRejectMissingStateStrings", "VarPolicy.Poli= cy.MissingStateString", + RegisterShouldRejectMissingStateStrings, LibInitMocked, Li= bCleanup, NULL); + AddTestCase (PolicyTests, + "RegisterShouldRejectStringsMissingNull", "VarPolicy.Polic= y.MissingNull", + RegisterShouldRejectStringsMissingNull, LibInitMocked, Lib= Cleanup, NULL); + AddTestCase (PolicyTests, + "RegisterShouldRejectMalformedStrings", "VarPolicy.Policy.= MalformedStrings", + RegisterShouldRejectMalformedStrings, LibInitMocked, LibCl= eanup, NULL); + AddTestCase (PolicyTests, + "RegisterShouldRejectUnpackedPolicies", "VarPolicy.Policy.= PolicyPacking", + RegisterShouldRejectUnpackedPolicies, LibInitMocked, LibCl= eanup, NULL); + AddTestCase (PolicyTests, + "RegisterShouldRejectInvalidNameCharacters", "VarPolicy.Po= licy.InvalidCharacters", + RegisterShouldRejectInvalidNameCharacters, LibInitMocked, = LibCleanup, NULL); + AddTestCase (PolicyTests, + "RegisterShouldRejectBadPolicyConstraints", "VarPolicy.Pol= icy.BadConstraints", + RegisterShouldRejectBadPolicyConstraints, LibInitMocked, L= ibCleanup, NULL); + AddTestCase (PolicyTests, + "RegisterShouldRejectUnknownLockPolicies", "VarPolicy.Poli= cy.BadLocks", + RegisterShouldRejectUnknownLockPolicies, LibInitMocked, Li= bCleanup, NULL); + AddTestCase (PolicyTests, + "RegisterShouldRejectPolicesWithTooManyWildcards", "VarPol= icy.Policy.TooManyWildcards", + RegisterShouldRejectPolicesWithTooManyWildcards, LibInitMo= cked, LibCleanup, NULL); + AddTestCase (PolicyTests, + "RegisterShouldRejectDuplicatePolicies", "VarPolicy.Policy= .DuplicatePolicies", + RegisterShouldRejectDuplicatePolicies, LibInitMocked, LibC= leanup, NULL); + AddTestCase (PolicyTests, + "Variables that exceed min or max sizes should be rejected= ", "VarPolicy.Policy.MinMax", + MinAndMaxSizePoliciesShouldBeHonored, LibInitMocked, LibCl= eanup, NULL); + AddTestCase (PolicyTests, + "AttributeMustPoliciesShouldBeHonored", "VarPolicy.Policy.= AttrMust", + AttributeMustPoliciesShouldBeHonored, LibInitMocked, LibCl= eanup, NULL); + AddTestCase (PolicyTests, + "AttributeCantPoliciesShouldBeHonored", "VarPolicy.Policy.= AttrCant", + AttributeCantPoliciesShouldBeHonored, LibInitMocked, LibCl= eanup, NULL); + AddTestCase (PolicyTests, + "VariablesShouldBeDeletableRegardlessOfSize", "VarPolicy.P= olicy.DeleteIgnoreSize", + VariablesShouldBeDeletableRegardlessOfSize, LibInitMocked,= LibCleanup, NULL); + AddTestCase (PolicyTests, + "LockNowPoliciesShouldBeHonored", "VarPolicy.Policy.VARIAB= LE_POLICY_TYPE_LOCK_NOW", + LockNowPoliciesShouldBeHonored, LibInitMocked, LibCleanup,= NULL); + AddTestCase (PolicyTests, + "LockOnCreatePoliciesShouldBeHonored", "VarPolicy.Policy.V= ARIABLE_POLICY_TYPE_LOCK_ON_CREATE", + LockOnCreatePoliciesShouldBeHonored, LibInitMocked, LibCle= anup, NULL); + AddTestCase (PolicyTests, + "LockOnStatePoliciesShouldBeHonored", "VarPolicy.Policy.Lo= ckState", + LockOnStatePoliciesShouldBeHonored, LibInitMocked, LibClea= nup, NULL); + AddTestCase (PolicyTests, + "LockOnStatePoliciesShouldApplyToNamespaces", "VarPolicy.P= olicy.NamespaceLockState", + LockOnStatePoliciesShouldApplyToNamespaces, LibInitMocked,= LibCleanup, NULL); + AddTestCase (PolicyTests, + "LockOnStateShouldHandleErrorsGracefully", "VarPolicy.Poli= cy.LockStateErrors", + LockOnStateShouldHandleErrorsGracefully, LibInitMocked, Li= bCleanup, NULL); + AddTestCase (PolicyTests, + "BestMatchPriorityShouldBeObeyed", "VarPolicy.Policy.BestM= atch", + BestMatchPriorityShouldBeObeyed, LibInitMocked, LibCleanup= , NULL); + + Status =3D CreateUnitTestSuite (&UtilityTests, Framework, "Variable Poli= cy Utility Tests", "VarPolicy.Utility", NULL, NULL); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Failed in CreateUnitTestSuite for UtilityTests\n= ")); + Status =3D EFI_OUT_OF_RESOURCES; + goto EXIT; + } + AddTestCase (UtilityTests, + "API commands that change state should not respond after i= nterface is locked", "VarPolicy.Utility.InterfaceLock", + ShouldBeAbleToLockInterface, LibInitMocked, LibCleanup, NU= LL); + AddTestCase (UtilityTests, + "All policies should pass once enforcement is disabled", "= VarPolicy.Utility.DisableEnforcement", + ShouldBeAbleToDisablePolicyEnforcement, LibInitMocked, Lib= Cleanup, NULL); + AddTestCase (UtilityTests, + "Disabling enforcement twice should produce an error", "Va= rPolicy.Utility.DisableEnforcementTwice", + ShouldNotBeAbleToDisablePoliciesTwice, LibInitMocked, LibC= leanup, NULL); + AddTestCase (UtilityTests, + "ShouldBeAbleToAddNewPoliciesAfterDisabled", "VarPolicy.Ut= ility.AddAfterDisable", + ShouldBeAbleToAddNewPoliciesAfterDisabled, LibInitMocked, = LibCleanup, NULL); + AddTestCase (UtilityTests, + "ShouldBeAbleToLockAfterDisabled", "VarPolicy.Utility.Lock= AfterDisable", + ShouldBeAbleToLockAfterDisabled, LibInitMocked, LibCleanup= , NULL); + AddTestCase (UtilityTests, + "Should be able to dump the policy table", "VarPolicy.Util= ity.DumpTable", + ShouldBeAbleToDumpThePolicyTable, LibInitMocked, LibCleanu= p, NULL); + AddTestCase (UtilityTests, + "ShouldBeAbleToDumpThePolicyTableAfterDisabled", "VarPolic= y.Utility.DumpTableAfterDisable", + ShouldBeAbleToDumpThePolicyTableAfterDisabled, LibInitMock= ed, LibCleanup, NULL); + + + // + // Execute the tests. + // + Status =3D RunAllTestSuites (Framework); + +EXIT: + if (Framework !=3D NULL) { + FreeUnitTestFramework (Framework); + } + + return Status; +} 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 +Business logic for Variable Policy enforcement. + +Copyright (c) Microsoft Corporation. +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _VARIABLE_POLICY_LIB_H_ +#define _VARIABLE_POLICY_LIB_H_ + +#include + +/** + This API function validates and registers a new policy with + the policy enforcement engine. + + @param[in] NewPolicy Pointer to the incoming policy structure. + + @retval EFI_SUCCESS + @retval EFI_INVALID_PARAMETER NewPolicy is NULL or is internally i= nconsistent. + @retval EFI_ALREADY_STARTED An identical matching policy already= exists. + @retval EFI_WRITE_PROTECTED The interface has been locked until = the next reboot. + @retval EFI_UNSUPPORTED Policy enforcement has been disabled= . No reason to add more policies. + @retval EFI_ABORTED A calculation error has prevented th= is function from completing. + @retval EFI_OUT_OF_RESOURCES Cannot grow the table to hold any mo= re policies. + @retval EFI_NOT_READY Library has not yet been initialized= . + +**/ +EFI_STATUS +EFIAPI +RegisterVariablePolicy ( + IN CONST VARIABLE_POLICY_ENTRY *NewPolicy + ); + + +/** + This API function checks to see whether the parameters to SetVariable wo= uld + be allowed according to the current variable policies. + + @param[in] VariableName Same as EFI_SET_VARIABLE. + @param[in] VendorGuid Same as EFI_SET_VARIABLE. + @param[in] Attributes Same as EFI_SET_VARIABLE. + @param[in] DataSize Same as EFI_SET_VARIABLE. + @param[in] Data Same as EFI_SET_VARIABLE. + + @retval EFI_SUCCESS A matching policy allows this update= . + @retval EFI_SUCCESS There are currently no policies that= restrict this update. + @retval EFI_SUCCESS The protections have been disable un= til the next reboot. + @retval EFI_WRITE_PROTECTED Variable is currently locked. + @retval EFI_INVALID_PARAMETER Attributes or size are invalid. + @retval EFI_ABORTED A lock policy exists, but an error p= revented evaluation. + @retval EFI_NOT_READY Library has not been initialized. + +**/ +EFI_STATUS +EFIAPI +ValidateSetVariable ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN UINT32 Attributes, + IN UINTN DataSize, + IN VOID *Data + ); + + +/** + This API function disables the variable policy enforcement. If it's + already been called once, will return EFI_ALREADY_STARTED. + + @retval EFI_SUCCESS + @retval EFI_ALREADY_STARTED Has already been called once this boot= . + @retval EFI_WRITE_PROTECTED Interface has been locked until reboot= . + @retval EFI_WRITE_PROTECTED Interface option is disabled by platfo= rm PCD. + @retval EFI_NOT_READY Library has not yet been initialized. + +**/ +EFI_STATUS +EFIAPI +DisableVariablePolicy ( + VOID + ); + + +/** + This API function will dump the entire contents of the variable policy t= able. + + Similar to GetVariable, the first call can be made with a 0 size and it = will return + the size of the buffer required to hold the entire table. + + @param[out] Policy Pointer to the policy buffer. Can be NULL if Siz= e is 0. + @param[in,out] Size On input, the size of the output buffer. On outp= ut, the size + of the data returned. + + @retval EFI_SUCCESS Policy data is in the output buffer = and Size has been updated. + @retval EFI_INVALID_PARAMETER Size is NULL, or Size is non-zero an= d Policy is NULL. + @retval EFI_BUFFER_TOO_SMALL Size is insufficient to hold policy.= Size updated with required size. + @retval EFI_NOT_READY Library has not yet been initialized= . + +**/ +EFI_STATUS +EFIAPI +DumpVariablePolicy ( + OUT UINT8 *Policy, + IN OUT UINT32 *Size + ); + + +/** + This API function returns whether or not the policy engine is + currently being enforced. + + @retval TRUE + @retval FALSE + @retval FALSE Library has not yet been initialized. + +**/ +BOOLEAN +EFIAPI +IsVariablePolicyEnabled ( + VOID + ); + + +/** + This API function locks the interface so that no more policy updates + can be performed or changes made to the enforcement until the next boot. + + @retval EFI_SUCCESS + @retval EFI_NOT_READY Library has not yet been initialized. + +**/ +EFI_STATUS +EFIAPI +LockVariablePolicy ( + VOID + ); + + +/** + This API function returns whether or not the policy interface is locked + for the remainder of the boot. + + @retval TRUE + @retval FALSE + @retval FALSE Library has not yet been initialized. + +**/ +BOOLEAN +EFIAPI +IsVariablePolicyInterfaceLocked ( + VOID + ); + + +/** + This helper function initializes the library and sets + up any required internal structures or handlers. + + Also registers the internal pointer for the GetVariable helper. + + @param[in] GetVariableHelper A function pointer matching the EFI_GET_VA= RIABLE prototype that will be used to + check policy criteria that involve the existence of othe= r variables. + + @retval EFI_SUCCESS + @retval EFI_ALREADY_STARTED The initialize function has been calle= d more than once without a call to + deinitialize. + +**/ +EFI_STATUS +EFIAPI +InitVariablePolicyLib ( + IN EFI_GET_VARIABLE GetVariableHelper + ); + + +/** + This helper function returns whether or not the library is currently ini= tialized. + + @retval TRUE + @retval FALSE + +**/ +BOOLEAN +EFIAPI +IsVariablePolicyLibInitialized ( + VOID + ); + + +/** + This helper function tears down the library. + + Should generally only be used for test harnesses. + + @retval EFI_SUCCESS + @retval EFI_NOT_READY Deinitialize was called without first call= ing initialize. + +**/ +EFI_STATUS +EFIAPI +DeinitVariablePolicyLib ( + VOID + ); + + +#endif // _VARIABLE_POLICY_LIB_H_ diff --git a/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.inf b= /MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.inf new file mode 100644 index 000000000000..f4a879d5382f --- /dev/null +++ b/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.inf @@ -0,0 +1,44 @@ +## @file VariablePolicyLib.inf +# Business logic for Variable Policy enforcement. +# +## +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: BSD-2-Clause-Patent +## + + +[Defines] + INF_VERSION =3D 0x00010017 + BASE_NAME =3D VariablePolicyLib + FILE_GUID =3D E9ECD342-159A-4F24-9FDF-65724027C594 + VERSION_STRING =3D 1.0 + MODULE_TYPE =3D DXE_DRIVER + LIBRARY_CLASS =3D VariablePolicyLib|DXE_DRIVER DXE_SMM_DRIVER MM_S= TANDALONE + +# +# The following information is for reference only and not required by the = build tools. +# +# VALID_ARCHITECTURES =3D ANY +# + + +[Sources] + VariablePolicyLib.c + VariablePolicyExtraInitNull.c + + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + + +[LibraryClasses] + DebugLib + BaseMemoryLib + MemoryAllocationLib + SafeIntLib + PcdLib + + +[Pcd] + gEfiMdeModulePkgTokenSpaceGuid.PcdAllowVariablePolicyEnforcementDisable = ## CONSUMES diff --git a/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.uni b= /MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.uni new file mode 100644 index 000000000000..2227ec427828 --- /dev/null +++ b/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.uni @@ -0,0 +1,12 @@ +// /** @file +// VariablePolicyLib.uni +// +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + + +#string STR_MODULE_ABSTRACT #language en-US "Library containin= g the business logic for the VariablePolicy engine" + +#string STR_MODULE_DESCRIPTION #language en-US "Library containin= g the business logic for the VariablePolicy engine" 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.in= f @@ -0,0 +1,51 @@ +## @file VariablePolicyLibRuntimeDxe.inf +# Business logic for Variable Policy enforcement. +# This instance is specifically for RuntimeDxe and contains +# extra routines to register for VirtualAddressChangeEvents. +# +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: BSD-2-Clause-Patent +## + + +[Defines] + INF_VERSION =3D 0x00010017 + BASE_NAME =3D VariablePolicyLibRuntimeDxe + FILE_GUID =3D 205F7F0E-8EAC-4914-8390-1B90DD7E2A27 + VERSION_STRING =3D 1.0 + MODULE_TYPE =3D DXE_RUNTIME_DRIVER + LIBRARY_CLASS =3D VariablePolicyLib|DXE_RUNTIME_DRIVER + +# +# The following information is for reference only and not required by the = build tools. +# +# VALID_ARCHITECTURES =3D ANY +# + + +[Sources] + VariablePolicyLib.c + VariablePolicyExtraInitRuntimeDxe.c + + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + + +[LibraryClasses] + DebugLib + BaseMemoryLib + MemoryAllocationLib + SafeIntLib + UefiBootServicesTableLib + UefiRuntimeServicesTableLib + PcdLib + + +[Pcd] + gEfiMdeModulePkgTokenSpaceGuid.PcdAllowVariablePolicyEnforcementDisable = ## CONSUMES + + +[Guids] + gEfiEventVirtualAddressChangeGuid diff --git a/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyUnitTest/= VariablePolicyUnitTest.inf b/MdeModulePkg/Library/VariablePolicyLib/Variabl= ePolicyUnitTest/VariablePolicyUnitTest.inf new file mode 100644 index 000000000000..ccc04bb600d6 --- /dev/null +++ b/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyUnitTest/Variabl= ePolicyUnitTest.inf @@ -0,0 +1,40 @@ +## @file VariablePolicyUnitTest.inf +# UnitTest for... +# Business logic for Variable Policy enforcement. +# +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: BSD-2-Clause-Patent +## + + +[Defines] + INF_VERSION =3D 0x00010006 + BASE_NAME =3D VariablePolicyUnitTest + FILE_GUID =3D 1200A2E4-D756-418C-9768-528C2D181A98 + MODULE_TYPE =3D HOST_APPLICATION + VERSION_STRING =3D 1.0 + +# +# The following information is for reference only and not required by the = build tools. +# +# VALID_ARCHITECTURES =3D IA32 X64 ARM AARCH64 +# + +[Sources] + VariablePolicyUnitTest.c + + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec + + +[LibraryClasses] + BaseLib + DebugLib + UnitTestLib + PrintLib + VariablePolicyLib + BaseMemoryLib + MemoryAllocationLib diff --git a/MdeModulePkg/MdeModulePkg.dec b/MdeModulePkg/MdeModulePkg.dec index 2e0461b87c32..31339741b840 100644 --- a/MdeModulePkg/MdeModulePkg.dec +++ b/MdeModulePkg/MdeModulePkg.dec @@ -31,6 +31,9 @@ [LibraryClasses] ## @libraryclass Defines a set of methods to reset whole system. ResetSystemLib|Include/Library/ResetSystemLib.h =20 + ## @libraryclass Business logic for storing and testing variable polic= ies + VariablePolicyLib|Include/Library/VariablePolicyLib.h + ## @libraryclass Defines a set of helper functions for resetting the s= ystem. ResetUtilityLib|Include/Library/ResetUtilityLib.h =20 diff --git a/MdeModulePkg/MdeModulePkg.dsc b/MdeModulePkg/MdeModulePkg.dsc index 25aea3e2a481..14b6ed536962 100644 --- a/MdeModulePkg/MdeModulePkg.dsc +++ b/MdeModulePkg/MdeModulePkg.dsc @@ -3,6 +3,7 @@ # # (C) Copyright 2014 Hewlett-Packard Development Company, L.P.
# Copyright (c) 2007 - 2019, Intel Corporation. All rights reserved.
+# Copyright (c) Microsoft Corporation. # # SPDX-License-Identifier: BSD-2-Clause-Patent # @@ -58,6 +59,7 @@ [LibraryClasses] DxeServicesLib|MdePkg/Library/DxeServicesLib/DxeServicesLib.inf DxeServicesTableLib|MdePkg/Library/DxeServicesTableLib/DxeServicesTableL= ib.inf UefiBootManagerLib|MdeModulePkg/Library/UefiBootManagerLib/UefiBootManag= erLib.inf + VariablePolicyLib|MdeModulePkg/Library/VariablePolicyLib/VariablePolicyL= ib.inf # # Generic Modules # @@ -129,6 +131,7 @@ [LibraryClasses.common.DXE_RUNTIME_DRIVER] DebugLib|MdePkg/Library/UefiDebugLibConOut/UefiDebugLibConOut.inf LockBoxLib|MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxDxeLib.inf CapsuleLib|MdeModulePkg/Library/DxeCapsuleLibFmp/DxeRuntimeCapsuleLib.in= f + VariablePolicyLib|MdeModulePkg/Library/VariablePolicyLib/VariablePolicyL= ibRuntimeDxe.inf =20 [LibraryClasses.common.SMM_CORE] HobLib|MdePkg/Library/DxeHobLib/DxeHobLib.inf @@ -306,6 +309,8 @@ [Components] MdeModulePkg/Library/BootLogoLib/BootLogoLib.inf MdeModulePkg/Library/TpmMeasurementLibNull/TpmMeasurementLibNull.inf MdeModulePkg/Library/AuthVariableLibNull/AuthVariableLibNull.inf + MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.inf + MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLibRuntimeDxe.inf MdeModulePkg/Library/VarCheckLib/VarCheckLib.inf MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLib.inf MdeModulePkg/Library/VarCheckPcdLib/VarCheckPcdLib.inf diff --git a/MdeModulePkg/Test/MdeModulePkgHostTest.dsc b/MdeModulePkg/Test= /MdeModulePkgHostTest.dsc index 72a119db4568..095e613f1be1 100644 --- a/MdeModulePkg/Test/MdeModulePkgHostTest.dsc +++ b/MdeModulePkg/Test/MdeModulePkgHostTest.dsc @@ -19,12 +19,23 @@ [Defines] =20 !include UnitTestFrameworkPkg/UnitTestFrameworkPkgHost.dsc.inc =20 +[LibraryClasses] + SafeIntLib|MdePkg/Library/BaseSafeIntLib/BaseSafeIntLib.inf + [Components] MdeModulePkg/Library/DxeResetSystemLib/UnitTest/MockUefiRuntimeServicesT= ableLib.inf =20 # # Build MdeModulePkg HOST_APPLICATION Tests # + MdeModulePkg/Library/VariablePolicyLib/VariablePolicyUnitTest/VariablePo= licyUnitTest.inf { + + VariablePolicyLib|MdeModulePkg/Library/VariablePolicyLib/VariablePol= icyLib.inf + + + gEfiMdeModulePkgTokenSpaceGuid.PcdAllowVariablePolicyEnforcementDisa= ble|TRUE + } + MdeModulePkg/Library/DxeResetSystemLib/UnitTest/DxeResetSystemLibUnitTes= tHost.inf { ResetSystemLib|MdeModulePkg/Library/DxeResetSystemLib/DxeResetSystem= Lib.inf --=20 2.16.3.windows.1