From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from NAM10-BN7-obe.outbound.protection.outlook.com (NAM10-BN7-obe.outbound.protection.outlook.com [40.107.92.101]) by mx.groups.io with SMTP id smtpd.web10.2467.1592378963470503123 for ; Wed, 17 Jun 2020 00:29:24 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=@microsoft.com header.s=selector2 header.b=FlO1fH0U; spf=pass (domain: microsoft.com, ip: 40.107.92.101, mailfrom: bret.barkelew@microsoft.com) ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=oL9U1fTIqwZz/5DWyPNL4VUqFFabLNk4JI7Cyd3e7tJIIUZDklPNhUJZnw3SFV9fRA4iVClRiX5Pff2LzV+7ZZHOi4F6y3BgsHr+DTTnP1Sf303v6GmCZr7RBzmQiCDJRqUeK6NP7bv75hlZN6V/DogYaXg4MvprBGfJn4l+Y2XZ1t5HsfVjcSiB6cJcQCQz1Oifgg8v5unl/seyt9qgVuFtYVT7JB82uuXw0ZvrKIkps3NDdmBzH/LIJPqsmnI4BTGGeNReqD6w2b8oboMjtzu08y6FknjOZCYQihBSZj+ozABcynT5YwaouoXfeFguB589SEKvmoSTGjgcWR1KcQ== 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=2hpIF5XkgVORScacnxKatNRlZ6ajbPKDE2qyySKp4i4=; b=ecusvMMHDEHBOrWKv69WuiKBbp2Mde12dcVg575zmJVzGo24qqXfaYLvte/RAIOP7QIEi1ezePXqRu1SF2kyJE58uN5Ah5gi5kLlRWnO6fpqw2lf6IaKZ0Y2twykIamftBVdFZSWxC78eSz3Q+Cao9y2QiDPWBltCCoiD12kfnsaNnQBzuUcJ9OtrtnEm/qKlhhPpKLmkOlAsK8aErTzZ2Oc2dnGt+VWJIQA+JyDW+HuJAsLq0rAPdzHCivcVPwLaK/67mD0kDEPIB1d6nYRNh/X2LSuCDTLMK58o0IR3hK/urH4iigKvhqFIdi/P1MK67HkZIgQkM/gFx1jVr5Y7A== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=microsoft.com; dmarc=pass action=none header.from=microsoft.com; dkim=pass header.d=microsoft.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=selector2; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=2hpIF5XkgVORScacnxKatNRlZ6ajbPKDE2qyySKp4i4=; b=FlO1fH0UfJLv4BbaxxJqZZkOYd2QC8Ca8OXYQzhkVWM1jDZArQuzy2ddKqcVGhjAWaGKhkzuquCAb+REQ05CqfElGY/pe5iM65yw9iitF147HfJCrPF3FgBzWCoLrUVsu401wj41RxeajpGhiaP9tHrEKirj2BLY/wua4S9um0w= Received: from CY4PR21MB0743.namprd21.prod.outlook.com (2603:10b6:903:b2::9) by CY4PR2101MB0865.namprd21.prod.outlook.com (2603:10b6:910:8a::18) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3131.9; Wed, 17 Jun 2020 07:29:19 +0000 Received: from CY4PR21MB0743.namprd21.prod.outlook.com ([fe80::4ef:d9e:62c:f319]) by CY4PR21MB0743.namprd21.prod.outlook.com ([fe80::f112:82fb:d4fd:f7dd%10]) with mapi id 15.20.3131.009; Wed, 17 Jun 2020 07:29:19 +0000 From: "Bret Barkelew" To: "devel@edk2.groups.io" , "bret@corthon.com" CC: Jian J Wang , Hao A Wu , liming.gao Subject: Re: [EXTERNAL] [edk2-devel] [PATCH v5 02/14] MdeModulePkg: Define the VariablePolicyLib Thread-Topic: [EXTERNAL] [edk2-devel] [PATCH v5 02/14] MdeModulePkg: Define the VariablePolicyLib Thread-Index: AQHWOYy5VVw+kPHwt0C6/4Vk8iR/gKjcfuiz Date: Wed, 17 Jun 2020 07:29:19 +0000 Message-ID: References: <20200603065810.806-1-brbarkel@microsoft.com>,<20200603065810.806-3-brbarkel@microsoft.com> In-Reply-To: <20200603065810.806-3-brbarkel@microsoft.com> Accept-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: msip_labels: MSIP_Label_f42aa342-8706-4288-bd11-ebb85995028c_Enabled=True;MSIP_Label_f42aa342-8706-4288-bd11-ebb85995028c_SiteId=72f988bf-86f1-41af-91ab-2d7cd011db47;MSIP_Label_f42aa342-8706-4288-bd11-ebb85995028c_SetDate=2020-06-17T07:29:17.056Z;MSIP_Label_f42aa342-8706-4288-bd11-ebb85995028c_Name=General;MSIP_Label_f42aa342-8706-4288-bd11-ebb85995028c_ContentBits=0;MSIP_Label_f42aa342-8706-4288-bd11-ebb85995028c_Method=Standard; authentication-results: edk2.groups.io; dkim=none (message not signed) header.d=none;edk2.groups.io; dmarc=none action=none header.from=microsoft.com; x-originating-ip: [71.212.143.8] x-ms-publictraffictype: Email x-ms-office365-filtering-ht: Tenant x-ms-office365-filtering-correlation-id: 51023c5e-34de-4543-bfbc-08d812902619 x-ms-traffictypediagnostic: CY4PR2101MB0865: x-ld-processed: 72f988bf-86f1-41af-91ab-2d7cd011db47,ExtAddr x-microsoft-antispam-prvs: x-ms-oob-tlc-oobclassifiers: OLM:10000; x-forefront-prvs: 04371797A5 x-ms-exchange-senderadcheck: 1 x-microsoft-antispam: BCL:0; x-microsoft-antispam-message-info: IQCWcF0WMjvrK/1Ookl6qq9yqek5sySB+kqlS3vo1g/SYei38NAm5IcrgDwtmccmPYEvM4hSYxIJJQu35ePdJgLYlPgjzxYI/gL/HQ4HWPvLmYZSL8mwKXTVH9uCIwK3TKN5h/PY6XMAAKQBkzpCJ+P8yyK4uFc+X2KfcVKgij+cXplTQN2QiR2e7gYYo6Yqs6GtxrrJ8fzj3KN0FcwDxqxQoEm13KPXS7w1kVm7NCkvl5DWspwve0AqDyA1EbecC8AMDVR5JaYc3UiI5/nc2YPfA10PHcf59/62VpZ84AJ30Bb7TwhcQuCn7HUR7/lvkF75IKoNoCVCs9oYgyRtmt5BQFHdR+1fO/GExyv2I2dfovZcGcKCReS9uqSrOr8GzVd6XNioL3uxRKTjXY/Ptcl1vGUqDJ6edYWOULg+D//vkyrKmGLdw93MQk6jVSvE x-forefront-antispam-report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:CY4PR21MB0743.namprd21.prod.outlook.com;PTR:;CAT:NONE;SFTY:;SFS:(4636009)(136003)(346002)(39860400002)(396003)(376002)(366004)(53546011)(8676002)(8990500004)(26005)(10290500003)(8936002)(9686003)(186003)(4326008)(6506007)(966005)(478600001)(2906002)(55016002)(19627405001)(86362001)(316002)(5660300002)(166002)(82960400001)(30864003)(66446008)(66946007)(64756008)(66476007)(66556008)(91956017)(76116006)(82950400001)(19627235002)(71200400001)(33656002)(83380400001)(7696005)(52536014)(110136005)(54906003)(559001)(569008);DIR:OUT;SFP:1102; x-ms-exchange-antispam-messagedata: lYx1pkKWi9zlQEdM+uFbKsw5c86S/uvRRSzx2N/NErJElLE2ao6xKDCXpivtV7YApQPuwYBuPbgmpIHEPZUkoVxuX4JIilUT0d2mCtfO7bpe+eJIp8Yh2/zjdQCnXYw87tSVEMZtUvTvy0Oz91KMQ7qn9ng2uaHQO5bel69YoYRh9OQqiV620Lp0yr1+BdAcvVDPSvCpOYlh2QruG12z+vYzC2e20P8dcK0T5a8cPsrNSSmcKl84D7EXdD3ySJH9cBhhAo8Uqr6ej6ePL86C5Qx4/RmoZ5uYEheX3phX+70ZmOL5q1/dwOkoNxju0W6ttigWz7ozvbP2clEqxrJYQW5ybJVnvy/xDmHOBF9eYZT2ZYGci5e+nuUIs1KFz+1ambt2GTltyybvUkajjih2t+mdHBVOQIF4cUycbvHtGzmyZdo7UlJ6B+hvDm0tkK9iX6KOPnvgKvITXgfrRNPpWh7j0ulFdv/jRmMCSlugREE= x-ms-exchange-transport-forked: True MIME-Version: 1.0 X-OriginatorOrg: microsoft.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-AuthSource: CY4PR21MB0743.namprd21.prod.outlook.com X-MS-Exchange-CrossTenant-Network-Message-Id: 51023c5e-34de-4543-bfbc-08d812902619 X-MS-Exchange-CrossTenant-originalarrivaltime: 17 Jun 2020 07:29:19.5218 (UTC) X-MS-Exchange-CrossTenant-fromentityheader: Hosted X-MS-Exchange-CrossTenant-id: 72f988bf-86f1-41af-91ab-2d7cd011db47 X-MS-Exchange-CrossTenant-mailboxtype: HOSTED X-MS-Exchange-CrossTenant-userprincipalname: KjW1JIYNl2FXucH4Z1yLhCJ5EWIPRn7CPvH2zykfpt7Nnn8ezFv3uNCPsA0I0P1TNDGiVr06W2wAhFZUxGwmQA== X-MS-Exchange-Transport-CrossTenantHeadersStamped: CY4PR2101MB0865 Content-Language: en-US Content-Type: multipart/alternative; boundary="_000_CY4PR21MB074358CF8FE24CBA96894524EF9A0CY4PR21MB0743namp_" --_000_CY4PR21MB074358CF8FE24CBA96894524EF9A0CY4PR21MB0743namp_ Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: quoted-printable Bump. This specific patch needs Reviews. - Bret ________________________________ From: devel@edk2.groups.io on behalf of Bret Barkele= w via groups.io Sent: Tuesday, June 2, 2020 11:57 PM To: devel@edk2.groups.io Cc: Jian J Wang ; Hao A Wu ; lim= ing.gao Subject: [EXTERNAL] [edk2-devel] [PATCH v5 02/14] MdeModulePkg: Define the = VariablePolicyLib https://nam06.safelinks.protection.outlook.com/?url=3Dhttps%3A%2F%2Fbugzill= a.tianocore.org%2Fshow_bug.cgi%3Fid%3D2522&data=3D02%7C01%7Cbret.barkel= ew%40microsoft.com%7C5f525d9b2e954b4b474d08d807a3da45%7C72f988bf86f141af91a= b2d7cd011db47%7C1%7C0%7C637267747622305708&sdata=3DV3OQlMW5ifVdpn5BJiGA= mc8HsjXplYCm%2FdANjL9xbdI%3D&reserved=3D0 VariablePolicy is an updated interface to replace VarLock and VarCheckProtocol. Add the VariablePolicyLib library that implements the portable business logic for the VariablePolicy engine. Also add host-based CI test cases for the lib. Cc: Jian J Wang Cc: Hao A Wu Cc: Liming Gao Cc: Bret Barkelew Signed-off-by: Bret Barkelew --- MdeModulePkg/Library/VariablePolicyLib/VariablePolicyExtraInitNull.c = | 46 + MdeModulePkg/Library/VariablePolicyLib/VariablePolicyExtraInitRuntimeDxe.c= | 85 + MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.c = | 813 +++++++ MdeModulePkg/Library/VariablePolicyLib/VariablePolicyUnitTest/VariablePoli= cyUnitTest.c | 2436 ++++++++++++++++++++ MdeModulePkg/Include/Library/VariablePolicyLib.h = | 207 ++ MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.inf = | 44 + MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.uni = | 12 + MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLibRuntimeDxe.inf = | 51 + MdeModulePkg/Library/VariablePolicyLib/VariablePolicyUnitTest/VariablePoli= cyUnitTest.inf | 40 + MdeModulePkg/MdeModulePkg.dec = | 3 + MdeModulePkg/MdeModulePkg.dsc = | 5 + MdeModulePkg/Test/MdeModulePkgHostTest.dsc = | 11 + 12 files changed, 3753 insertions(+) diff --git a/MdeModulePkg/Library/VariablePolicyLib/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..3ca87048b14b --- /dev/null +++ b/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyExtraInitRuntime= Dxe.c @@ -0,0 +1,85 @@ +/** @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..c63807ef8531 --- /dev/null +++ b/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.c @@ -0,0 +1,813 @@ +/** @file -- VariablePolicyLib.c +Business logic for Variable Policy enforcement. + +Copyright (c) Microsoft Corporation. +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include + +#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*)Cur= Policy + CurPolicy->Size) +#define GET_POLICY_NAME(CurPolicy) (CHAR16*)((UINTN)CurPolicy + CurPoli= cy->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_ENT= RY), + 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 exeeded the structure or be poi= nting at the last char in LockPolicy->Name. + // We should check to make sure that the policy Name comes immediately= after this charcter. + if ((UINTN)++CheckChar !=3D (UINTN)NewPolicy + NewPolicy->OffsetToName= ) { + return FALSE; + } + } + // If the policy type is any other value, make sure that the LockPolicy = structure has a zero length. + else { + if (NewPolicy->OffsetToName !=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++; + } + } + // Otherwise, not a match. + else { + 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", __FUN= CTION__, + 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. + // + // Check for immediate lock. + if (ActivePolicy->LockPolicyType =3D=3D VARIABLE_POLICY_TYPE_LOCK_NOW)= { + ReturnStatus =3D EFI_WRITE_PROTECTED; + goto Exit; + } + // Check for lock on create. + else if (ActivePolicy->LockPolicyType =3D=3D VARIABLE_POLICY_TYPE_LOCK= _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; + } + } + // Check for lock on state variable. + else if (ActivePolicy->LockPolicyType =3D=3D VARIABLE_POLICY_TYPE_LOCK= _ON_VAR_STATE) { + StateVarPolicy =3D (VARIABLE_LOCK_ON_VAR_STATE_POLICY*)((UINT8*)Acti= vePolicy + sizeof(VARIABLE_POLICY_ENTRY)); + StateVarName =3D (CHAR16*)((UINT8*)StateVarPolicy + sizeof(VARIABLE_= 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; + } + } + // EFI_NOT_FOUND and EFI_BUFFER_TOO_SMALL indicate that the state do= esn't match. + else if (Status !=3D EFI_NOT_FOUND && Status !=3D EFI_BUFFER_TOO_SMA= LL) { + // 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..f133f2f30e36 --- /dev/null +++ b/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyUnitTest/Variabl= ePolicyUnitTest.c @@ -0,0 +1,2436 @@ +/** @file -- VariablePolicyUnitTest.c +UnitTest for... +Business logic for Variable Policy enforcement. + +Copyright (c) Microsoft Corporation. +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#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_ST= ATE_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(VARIAB= LE_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*)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, CheckVar1= Name, &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.OffsetToNam= e, 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(C= HAR16); + 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.OffsetToNam= e, 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.OffsetToNam= e, 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(C= HAR16); + ValidationPolicy.Header.OffsetToName =3D ValidationPolicy.Header.OffsetT= oName + sizeof(CHAR16); + CopyMem( (UINT8*)&ValidationPolicy + ValidationPolicy.Header.OffsetToNam= e, 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(C= HAR16); + ValidationPolicy.Header.OffsetToName =3D ValidationPolicy.Header.OffsetT= oName + sizeof(CHAR16); + CopyMem( (UINT8*)&ValidationPolicy + ValidationPolicy.Header.OffsetToNam= e, 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 ); // A= ttributes + will_return( StubGetVariableNull, 0 ); // S= ize + will_return( StubGetVariableNull, NULL ); // D= ataPtr + will_return( StubGetVariableNull, EFI_NOT_FOUND ); // S= tatus + 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 ); // A= ttributes + will_return( StubGetVariableNull, 10 ); // S= ize + will_return( StubGetVariableNull, NULL ); // D= ataPtr + will_return( StubGetVariableNull, EFI_BUFFER_TOO_SMALL ); // S= tatus + 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 ); // A= ttributes + will_return( StubGetVariableNull, 0 ); // S= ize + will_return( StubGetVariableNull, NULL ); // D= ataPtr + will_return( StubGetVariableNull, EFI_NOT_FOUND ); // S= tatus + 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 ); // A= ttributes + will_return( StubGetVariableNull, 10 ); // S= ize + will_return( StubGetVariableNull, NULL ); // D= ataPtr + will_return( StubGetVariableNull, EFI_BUFFER_TOO_SMALL ); // S= tatus + 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 ); // A= ttributes + will_return( StubGetVariableNull, sizeof(ValidationStateVar) ); // S= ize + will_return( StubGetVariableNull, &ValidationStateVar ); // D= ataPtr + will_return( StubGetVariableNull, EFI_SUCCESS ); // S= tatus + 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 ); // A= ttributes + will_return( StubGetVariableNull, sizeof(ValidationStateVar) ); // S= ize + will_return( StubGetVariableNull, &ValidationStateVar ); // D= ataPtr + will_return( StubGetVariableNull, EFI_SUCCESS ); // S= tatus + 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 ); // A= ttributes + will_return( StubGetVariableNull, sizeof(ValidationStateVar) ); // S= ize + will_return( StubGetVariableNull, &ValidationStateVar ); // D= ataPtr + will_return( StubGetVariableNull, EFI_SUCCESS ); // S= tatus + 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 ); // A= ttributes + will_return( StubGetVariableNull, 0 ); // S= ize + will_return( StubGetVariableNull, NULL ); // D= ataPtr + will_return( StubGetVariableNull, EFI_NOT_FOUND ); // S= tatus + 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 ); // A= ttributes + will_return( StubGetVariableNull, 0 ); // S= ize + will_return( StubGetVariableNull, NULL ); // D= ataPtr + will_return( StubGetVariableNull, EFI_NOT_FOUND ); // S= tatus + 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 ); // A= ttributes + will_return( StubGetVariableNull, sizeof(ValidationStateVar) ); // S= ize + will_return( StubGetVariableNull, &ValidationStateVar ); // D= ataPtr + will_return( StubGetVariableNull, EFI_SUCCESS ); // S= tatus + 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 ); // A= ttributes + will_return( StubGetVariableNull, sizeof(ValidationStateVar) ); // S= ize + will_return( StubGetVariableNull, &ValidationStateVar ); // D= ataPtr + will_return( StubGetVariableNull, EFI_SUCCESS ); // S= tatus + 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 ); // A= ttributes + will_return( StubGetVariableNull, 0 ); // S= ize + will_return( StubGetVariableNull, NULL ); // D= ataPtr + will_return( StubGetVariableNull, EFI_NOT_FOUND ); // S= tatus + 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 ); // A= ttributes + will_return( StubGetVariableNull, 0 ); // S= ize + will_return( StubGetVariableNull, NULL ); // D= ataPtr + will_return( StubGetVariableNull, EFI_BUFFER_TOO_SMALL ); // S= tatus + 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 ); // A= ttributes + will_return( StubGetVariableNull, 0 ); // S= ize + will_return( StubGetVariableNull, NULL ); // D= ataPtr + will_return( StubGetVariableNull, EFI_UNSUPPORTED ); // S= tatus + 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 ); // A= ttributes + will_return( StubGetVariableNull, 0 ); // S= ize + will_return( StubGetVariableNull, NULL ); // D= ataPtr + will_return( StubGetVariableNull, EFI_NOT_READY ); // S= tatus + 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 + sizeof= (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_PA= RAMETER ); + DumpSize =3D 10; + UT_ASSERT_STATUS_EQUAL( DumpVariablePolicy( NULL, &DumpSize ), EFI_INVAL= ID_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 occured when executing this entry poi= nt. + +**/ +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 + ## @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 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 [LibraryClasses.common.SMM_CORE] HobLib|MdePkg/Library/DxeHobLib/DxeHobLib.inf @@ -306,6 +309,8 @@ [Components] MdeModulePkg/Library/BootLogoLib/BootLogoLib.inf MdeModulePkg/Library/TpmMeasurementLibNull/TpmMeasurementLibNull.inf MdeModulePkg/Library/AuthVariableLibNull/AuthVariableLibNull.inf + MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.inf + MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLibRuntimeDxe.inf MdeModulePkg/Library/VarCheckLib/VarCheckLib.inf MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLib.inf MdeModulePkg/Library/VarCheckPcdLib/VarCheckPcdLib.inf diff --git a/MdeModulePkg/Test/MdeModulePkgHostTest.dsc b/MdeModulePkg/Test= /MdeModulePkgHostTest.dsc index 72a119db4568..095e613f1be1 100644 --- a/MdeModulePkg/Test/MdeModulePkgHostTest.dsc +++ b/MdeModulePkg/Test/MdeModulePkgHostTest.dsc @@ -19,12 +19,23 @@ [Defines] !include UnitTestFrameworkPkg/UnitTestFrameworkPkgHost.dsc.inc +[LibraryClasses] + SafeIntLib|MdePkg/Library/BaseSafeIntLib/BaseSafeIntLib.inf + [Components] MdeModulePkg/Library/DxeResetSystemLib/UnitTest/MockUefiRuntimeServicesT= ableLib.inf # # 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 -- 2.26.2.windows.1.8.g01c50adf56.20200515075929 -=3D-=3D-=3D-=3D-=3D-=3D Groups.io Links: You receive all messages sent to this group. View/Reply Online (#60643): https://nam06.safelinks.protection.outlook.com/= ?url=3Dhttps%3A%2F%2Fedk2.groups.io%2Fg%2Fdevel%2Fmessage%2F60643&data= =3D02%7C01%7Cbret.barkelew%40microsoft.com%7C5f525d9b2e954b4b474d08d807a3da= 45%7C72f988bf86f141af91ab2d7cd011db47%7C1%7C0%7C637267747622315664&sdat= a=3DNShPJaGWqn%2F4krAZWL9B1QUdajPc1uWC3%2BZPd3wcz4E%3D&reserved=3D0 Mute This Topic: https://nam06.safelinks.protection.outlook.com/?url=3Dhttp= s%3A%2F%2Fgroups.io%2Fmt%2F74646432%2F1852292&data=3D02%7C01%7Cbret.bar= kelew%40microsoft.com%7C5f525d9b2e954b4b474d08d807a3da45%7C72f988bf86f141af= 91ab2d7cd011db47%7C1%7C0%7C637267747622315664&sdata=3Daq1LOygDYZbMpRGii= bZCOCfMPffZtEFQLR8K4LKmUYk%3D&reserved=3D0 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://nam06.safelinks.protection.outlook.com/?url=3Dhttps%3A= %2F%2Fedk2.groups.io%2Fg%2Fdevel%2Funsub&data=3D02%7C01%7Cbret.barkelew= %40microsoft.com%7C5f525d9b2e954b4b474d08d807a3da45%7C72f988bf86f141af91ab2= d7cd011db47%7C1%7C0%7C637267747622315664&sdata=3DCGyCvVr0DX3Z%2F%2BKh43= OWSObWZZG58YFT6f94FhOY1LA%3D&reserved=3D0 [bret.barkelew@microsoft.com= ] -=3D-=3D-=3D-=3D-=3D-=3D --_000_CY4PR21MB074358CF8FE24CBA96894524EF9A0CY4PR21MB0743namp_ Content-Type: text/html; charset="us-ascii" Content-Transfer-Encoding: quoted-printable
Bump. This specif= ic patch needs Reviews.

- Bret


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

VariablePolicy is an updated interface to
replace VarLock and VarCheckProtocol.

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

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

Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Hao A Wu <hao.a.wu@intel.com>
Cc: Liming Gao <liming.gao@intel.com>
Cc: Bret Barkelew <brbarkel@microsoft.com>
Signed-off-by: Bret Barkelew <brbarkel@microsoft.com>
---
 MdeModulePkg/Library/VariablePolicyLib/VariablePolicyExtraInitNull.c&= nbsp;           &nbs= p;        |   46 +
 MdeModulePkg/Library/VariablePolicyLib/VariablePolicyExtraInitRuntime= Dxe.c           &nbs= p;   |   85 +
 MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.c  = ;            &n= bsp;            = ;    |  813 +++++++
 MdeModulePkg/Library/VariablePolicyLib/VariablePolicyUnitTest/Variabl= ePolicyUnitTest.c   | 2436 +++++++= 3;++++++++++++
 MdeModulePkg/Include/Library/VariablePolicyLib.h   &nb= sp;            =             &nb= sp;            |&nbs= p; 207 ++
 MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.inf &nb= sp;            =             &nb= sp;  |   44 +
 MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.uni &nb= sp;            =             &nb= sp;  |   12 +
 MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLibRuntimeDxe.in= f            &n= bsp;      |   51 +
 MdeModulePkg/Library/VariablePolicyLib/VariablePolicyUnitTest/Variabl= ePolicyUnitTest.inf |   40 +
 MdeModulePkg/MdeModulePkg.dec      &nbs= p;            &= nbsp;           &nbs= p;            &= nbsp;           &nbs= p;   |    3 +
 MdeModulePkg/MdeModulePkg.dsc      &nbs= p;            &= nbsp;           &nbs= p;            &= nbsp;           &nbs= p;   |    5 +
 MdeModulePkg/Test/MdeModulePkgHostTest.dsc    &nb= sp;            =             &nb= sp;            =      |   11 +
 12 files changed, 3753 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/VariablePolicyExtr= aInitNull.c
@@ -0,0 +1,46 @@
+/** @file -- VariablePolicyExtraInitNull.c

+This file contains extra init and deinit routines that don't do anythi= ng

+extra.

+

+Copyright (c) Microsoft Corporation.

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

+

+**/

+

+#include <Library/UefiRuntimeServicesTableLib.h>

+

+

+/**

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

+  register VirtualAddress change callbacks. Among other things.
+

+  @retval     EFI_SUCCESS   Everyth= ing is good. Continue with init.

+  @retval     Others    &= nbsp;   Uh... don't continue.

+

+**/

+EFI_STATUS

+VariablePolicyExtraInit (

+  VOID

+  )

+{

+  // NULL implementation.

+  return EFI_SUCCESS;

+}

+

+

+/**

+  An extra deinit hook that enables the RuntimeDxe library instan= ce to

+  register VirtualAddress change callbacks. Among other things.
+

+  @retval     EFI_SUCCESS   Everyth= ing is good. Continue with deinit.

+  @retval     Others    &= nbsp;   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..3ca87048b14b
--- /dev/null
+++ b/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyExtr= aInitRuntimeDxe.c
@@ -0,0 +1,85 @@
+/** @file -- VariablePolicyExtraInitRuntimeDxe.c

+This file contains extra init and deinit routines that register and un= register

+VariableAddressChange callbacks.

+

+Copyright (c) Microsoft Corporation.

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

+

+**/

+

+#include <Library/UefiBootServicesTableLib.h>

+#include <Library/UefiRuntimeServicesTableLib.h>

+

+extern EFI_GET_VARIABLE   mGetVariableHelper;

+extern UINT8         &nbs= p;    *mPolicyTable;

+STATIC BOOLEAN         &n= bsp;  mIsVirtualAddrConverted;

+STATIC EFI_EVENT         = mVariablePolicyLibVirtualAddressChangeEvent  =3D NULL;

+

+/**

+  For the RuntimeDxe version of this lib, convert internal pointe= r addresses to virtual addresses.

+

+  @param[in] Event      Event whose noti= fication function is being invoked.

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

+           &nbs= p;            is imp= lementation-dependent.

+**/

+STATIC

+VOID

+EFIAPI

+VariablePolicyLibVirtualAddressCallback (

+  IN  EFI_EVENT   Event,

+  IN  VOID        *Contex= t

+  )

+{

+  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   Everyth= ing is good. Continue with init.

+  @retval     Others    &= nbsp;   Uh... don't continue.

+

+**/

+EFI_STATUS

+VariablePolicyExtraInit (

+  VOID

+  )

+{

+  return gBS->CreateEventEx (EVT_NOTIFY_SIGNAL,

+           &nbs= p;            &= nbsp;     TPL_NOTIFY,

+           &nbs= p;            &= nbsp;     VariablePolicyLibVirtualAddressCallback,

+           &nbs= p;            &= nbsp;     NULL,

+           &nbs= p;            &= nbsp;     &gEfiEventVirtualAddressChangeGuid,

+           &nbs= p;            &= nbsp;     &mVariablePolicyLibVirtualAddressChangeEv= ent);

+}

+

+

+/**

+  An extra deinit hook that enables the RuntimeDxe library instan= ce to

+  register VirtualAddress change callbacks. Among other things.
+

+  @retval     EFI_SUCCESS   Everyth= ing is good. Continue with deinit.

+  @retval     Others    &= nbsp;   Uh... don't continue.

+

+**/

+EFI_STATUS

+VariablePolicyExtraDeinit (

+  VOID

+  )

+{

+  EFI_STATUS  Status;

+

+  Status =3D EFI_SUCCESS;

+  if (mIsVirtualAddrConverted) {

+    Status =3D gBS->CloseEvent (mVariablePolicyLibVi= rtualAddressChangeEvent);

+  }

+  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..c63807ef8531
--- /dev/null
+++ b/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.= c
@@ -0,0 +1,813 @@
+/** @file -- VariablePolicyLib.c

+Business logic for Variable Policy enforcement.

+

+Copyright (c) Microsoft Corporation.

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

+

+**/

+

+#include <Uefi.h>

+

+#include <Library/SafeIntLib.h>

+#include <Library/MemoryAllocationLib.h>

+#include <Library/BaseMemoryLib.h>

+#include <Library/DebugLib.h>

+#include <Library/PcdLib.h>

+

+#include <Protocol/VariablePolicy.h>

+#include <Library/VariablePolicyLib.h>

+

+

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

+//           &n= bsp;     for error handling. A refactor should remove t= hese at some point.

+

+//

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

+// This define handles the configuration.

+#ifdef INTERNAL_UNIT_TEST

+#undef STATIC

+#define STATIC    // Nothing...

+#endif

+

+// An abstracted GetVariable interface that enables configuration rega= rdless of the environment.

+EFI_GET_VARIABLE         =    mGetVariableHelper =3D NULL;

+

+// Master switch to lock this entire interface. Does not stop enforcem= ent,

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

+STATIC  BOOLEAN        &n= bsp;    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 bo= ot.

+STATIC  BOOLEAN        &n= bsp;    mProtectionDisabled =3D FALSE;

+

+// Table to hold all the current policies.

+UINT8           = ;            *mPolic= yTable =3D NULL;

+STATIC  UINT32        &nb= sp;     mCurrentTableSize =3D 0;

+STATIC  UINT32        &nb= sp;     mCurrentTableUsage =3D 0;

+STATIC  UINT32        &nb= sp;     mCurrentTableCount =3D 0;

+

+#define POLICY_TABLE_STEP_SIZE      &nbs= p; 0x1000

+

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

+//       Current table data has already = been sanitized.

+#define GET_NEXT_POLICY(CurPolicy)    (VARIABLE_POLICY_= ENTRY*)((UINT8*)CurPolicy + CurPolicy->Size)

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

+

+#define MATCH_PRIORITY_EXACT    0

+#define MATCH_PRIORITY_MAX      MATCH_PRIORIT= Y_EXACT

+#define MATCH_PRIORITY_MIN      MAX_UINT8

+

+// ExtraInit/ExtraDeinit functions allow RuntimeDxe to register Virtua= lAddress callbacks.

+EFI_STATUS

+VariablePolicyExtraInit (

+  VOID

+  );

+

+EFI_STATUS

+VariablePolicyExtraDeinit (

+  VOID

+  );

+

+

+/**

+  This helper function determines whether the structure of an inc= oming policy

+  is valid and internally consistent.

+

+  @param[in]  NewPolicy     Pointer to t= he incoming policy structure.

+

+  @retval     TRUE

+  @retval     FALSE   Pointer is NU= LL, size is wrong, strings are empty, or

+           &nbs= p;          substructures over= lap.

+

+**/

+STATIC

+BOOLEAN

+IsValidVariablePolicyStructure (

+  IN CONST VARIABLE_POLICY_ENTRY    *NewPolicy

+  )

+{

+  EFI_STATUS    Status;

+  UINTN         EntryEnd;=

+  CHAR16        *CheckChar;
+  UINTN         WildcardC= ount;

+

+  // 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 structure and a NULL string.

+      NewPolicy->Size < sizeof(VARIABLE= _POLICY_ENTRY) ||

+      // Check for the known revision.

+      NewPolicy->Version !=3D VARIABLE_POL= ICY_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_L= OCK &&

+      NewPolicy->LockPolicyType !=3D VARIA= BLE_POLICY_TYPE_LOCK_NOW &&

+      NewPolicy->LockPolicyType !=3D VARIA= BLE_POLICY_TYPE_LOCK_ON_CREATE &&

+      NewPolicy->LockPolicyType !=3D VARIA= BLE_POLICY_TYPE_LOCK_ON_VAR_STATE)

+  {

+    return FALSE;

+  }

+

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

+  // terminates before the OffsetToName for the matching policy v= ariable Name.

+  if (NewPolicy->LockPolicyType =3D=3D VARIABLE_POLICY_TYPE_LO= CK_ON_VAR_STATE) {

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

+    Status =3D SafeUintnAdd( (UINTN)NewPolicy + siz= eof(VARIABLE_POLICY_ENTRY),

+           &nbs= p;            &= nbsp;   sizeof(VARIABLE_LOCK_ON_VAR_STATE_POLICY),

+           &nbs= p;            &= nbsp;   (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 exeeded the = structure or be pointing at the last char in LockPolicy->Name.

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

+    if ((UINTN)++CheckChar !=3D (UINTN)NewPolic= y + NewPolicy->OffsetToName) {

+      return FALSE;

+    }

+  }

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

+  else {

+    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 structure.

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

+    CheckChar =3D (CHAR16*)((UINTN)NewPolicy + NewP= olicy->OffsetToName);

+    WildcardCount =3D 0;

+    while (*CheckChar !=3D CHAR_NULL) {

+      // Make sure there aren't excessive wil= dcards.

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

+        WildcardCount++;
+        if (WildcardCount > MATC= H_PRIORITY_MIN) {

+          return FALSE;
+        }

+      }

+      // Make sure you're still within the bo= unds of the policy structure.

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

+        return FALSE;

+      }

+      CheckChar++;

+    }

+

+    // Finally, we should be pointed at the very last c= haracter in Name, so 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 matches the target

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

+

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

+  Perfect name matches will return 0.

+  Single wildcard characters will return the number of wildcard c= haracters.

+  Full namespaces will return MAX_UINT8.

+

+  @param[in]  EvalEntry      &= nbsp;  Pointer to the policy entry being evaluated.

+  @param[in]  VariableName      Sam= e 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.

+           &nbs= p;            &= nbsp;       Lower number =3D=3D higher priori= ty. Only valid if a match found.

+

+  @retval     TRUE    &nb= sp;     Current entry matches the target variable.

+  @retval     FALSE    &n= bsp;    Current entry does not match at all.

+

+**/

+STATIC

+BOOLEAN

+EvaluatePolicyMatch (

+  IN CONST  VARIABLE_POLICY_ENTRY   *EvalEntry,
+  IN CONST  CHAR16       =            *VariableName,=

+  IN CONST  EFI_GUID      &nbs= p;         *VendorGuid,

+  OUT       UINT8   =             &nb= sp;   *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 ev= aluate anything else.

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

+    goto Exit;

+  }

+

+  // If the GUID matches, check to see whether there is a Name as= sociated

+  // with the policy. If not, this policy matches the entire name= space.

+  // 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 ma= tch.

+  // 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] || P= olicyName[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 V= ariableName[Index] && VariableName[Index] <=3D L'9')) {

+        if (CalculatedPriority <= MATCH_PRIORITY_MIN) {

+          CalculatedPrior= ity++;

+        }

+      }

+      // Otherwise, not a match.

+      else {

+        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 pointer

+  to the best match, if any are found. Leverages EvaluatePolicyMa= tch() to

+  determine "best".

+

+  @param[in]  VariableName     &nbs= p; Same as EFI_SET_VARIABLE.

+  @param[in]  VendorGuid      =    Same as EFI_SET_VARIABLE.

+  @param[out] ReturnPriority     [Optional] I= f pointer is provided, return the

+           &nbs= p;            &= nbsp;        priority of the match. Same= as EvaluatePolicyMatch().

+           &nbs= p;            &= nbsp;        Only valid if a match is re= turned.

+

+  @retval     VARIABLE_POLICY_ENTRY* &nb= sp;  Best match that was found.

+  @retval     NULL    &nb= sp;            =      No match was found.

+

+**/

+STATIC

+VARIABLE_POLICY_ENTRY*

+GetBestPolicyMatch (

+  IN CONST  CHAR16       =      *VariableName,

+  IN CONST  EFI_GUID      &nbs= p;   *VendorGuid,

+  OUT       UINT8   =           *ReturnPriority = ; OPTIONAL

+  )

+{

+  VARIABLE_POLICY_ENTRY   *BestResult;

+  VARIABLE_POLICY_ENTRY   *CurrentEntry;

+  UINT8         &nbs= p;         MatchPriority;

+  UINT8         &nbs= p;         CurrentPriority;

+  UINTN         &nbs= p;         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, &CurrentPriority )) {

+      // If match is better, take it.

+      if (BestResult =3D=3D NULL || CurrentPr= iority < MatchPriority) {

+        BestResult =3D CurrentEntry= ;

+        MatchPriority =3D CurrentPr= iority;

+      }

+

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

+      if (MatchPriority =3D=3D 0) {

+        break;

+      }

+    }

+

+    // If we're still in the loop, move to the next ent= ry.

+    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 t= he incoming policy structure.

+

+  @retval     EFI_SUCCESS

+  @retval     EFI_INVALID_PARAMETER &nbs= p; NewPolicy is NULL or is internally inconsistent.

+  @retval     EFI_ALREADY_STARTED  =    An identical matching policy already exists.

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

+  @retval     EFI_UNSUPPORTED  &nbs= p;      Policy enforcement has been disabled. No r= eason to add more policies.

+  @retval     EFI_ABORTED   &n= bsp;         A calculation error ha= s prevented this function from completing.

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

+  @retval     EFI_NOT_READY   =         Library has not yet been initial= ized.

+

+**/

+EFI_STATUS

+EFIAPI

+RegisterVariablePolicy (

+  IN CONST VARIABLE_POLICY_ENTRY    *NewPolicy

+  )

+{

+  EFI_STATUS         = ;       Status;

+  VARIABLE_POLICY_ENTRY     *MatchPolicy;

+  UINT8         &nbs= p;           MatchPriorit= y;

+  UINT32         &nb= sp;          NewSize;

+  UINT8         &nbs= p;           *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 = ),

+           &nbs= p;            &= nbsp;           &NewP= olicy->Namespace,

+           &nbs= p;            &= nbsp;           &Matc= hPriority );

+  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->Siz= e, &NewSize );

+  if (EFI_ERROR( Status )) {

+    return EFI_ABORTED;

+  }

+  if (NewSize > mCurrentTableSize) {

+    // Use NewSize to calculate the new table size in u= nits of POLICY_TABLE_STEP_SIZE.

+    NewSize =3D (NewSize % POLICY_TABLE_STEP_SIZE) >= 0 ?

+           &nbs= p;    (NewSize / POLICY_TABLE_STEP_SIZE) + 1 :

+           &nbs= p;    (NewSize / POLICY_TABLE_STEP_SIZE);

+    // Calculate the new table size in absolute bytes.<= br>
+    Status =3D SafeUint32Mult( NewSize, POLICY_TABLE_ST= EP_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, NewP= olicy->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 SetVa= riable would

+  be allowed according to the current variable policies.

+

+  @param[in]  VariableName     &nbs= p; Same as EFI_SET_VARIABLE.

+  @param[in]  VendorGuid      =    Same as EFI_SET_VARIABLE.

+  @param[in]  Attributes      =    Same as EFI_SET_VARIABLE.

+  @param[in]  DataSize      &n= bsp;    Same as EFI_SET_VARIABLE.

+  @param[in]  Data       =         Same as EFI_SET_VARIABLE.

+

+  @retval     EFI_SUCCESS   &n= bsp;         A matching policy allo= ws this update.

+  @retval     EFI_SUCCESS   &n= bsp;         There are currently no= policies that restrict this update.

+  @retval     EFI_SUCCESS   &n= bsp;         The protections have b= een disable until the next reboot.

+  @retval     EFI_WRITE_PROTECTED  =    Variable is currently locked.

+  @retval     EFI_INVALID_PARAMETER &nbs= p; Attributes or size are invalid.

+  @retval     EFI_ABORTED   &n= bsp;         A lock policy exists, = but an error prevented evaluation.

+  @retval     EFI_NOT_READY   =         Library has not been initialized= .

+

+**/

+EFI_STATUS

+EFIAPI

+ValidateSetVariable (

+  IN  CHAR16        =             &nb= sp;  *VariableName,

+  IN  EFI_GUID       &nbs= p;             = *VendorGuid,

+  IN  UINT32        =             &nb= sp;  Attributes,

+  IN  UINTN        &= nbsp;           &nbs= p;   DataSize,

+  IN  VOID        &n= bsp;            = ;    *Data

+  )

+{

+  BOOLEAN         &n= bsp;            = ;       IsDel;

+  VARIABLE_POLICY_ENTRY       =         *ActivePolicy;

+  EFI_STATUS         = ;            &n= bsp;    Status;

+  EFI_STATUS         = ;            &n= bsp;    ReturnStatus;

+  VARIABLE_LOCK_ON_VAR_STATE_POLICY   *StateVarPolicy;<= br>
+  CHAR16         &nb= sp;            =         *StateVarName;

+  UINTN         &nbs= p;            &= nbsp;        StateVarSize;

+  UINT8         &nbs= p;            &= nbsp;        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_VARIA= BLE_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 d= ata.

+  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 &a= mp;& DataSize < ActivePolicy->MinSize) ||

+          (ActivePolicy-&= gt;MaxSize > 0 && DataSize > ActivePolicy->MaxSize)) {

+        ReturnStatus =3D EFI_INVALI= D_PARAMETER;

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

+           &nbs= p;    DataSize, ActivePolicy->MinSize, ActivePolicy->M= axSize ));

+        goto Exit;

+      }

+

+      // Check for attribute constraints.

+      if ((ActivePolicy->AttributesMustHav= e & Attributes) !=3D ActivePolicy->AttributesMustHave ||

+          (ActivePolicy-&= gt;AttributesCantHave & Attributes) !=3D 0) {

+        ReturnStatus =3D EFI_INVALI= D_PARAMETER;

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

+           &nbs= p;    Attributes, ActivePolicy->AttributesMustHave, Activ= ePolicy->AttributesCantHave ));

+        goto Exit;

+      }

+    }

+

+    //

+    // Lock policy check.

+    //

+    // Check for immediate lock.

+    if (ActivePolicy->LockPolicyType =3D=3D VARIABLE= _POLICY_TYPE_LOCK_NOW) {

+      ReturnStatus =3D EFI_WRITE_PROTECTED;
+      goto Exit;

+    }

+    // Check for lock on create.

+    else if (ActivePolicy->LockPolicyType =3D=3D VAR= IABLE_POLICY_TYPE_LOCK_ON_CREATE) {

+      StateVarSize =3D 0;

+      Status =3D mGetVariableHelper( Variable= Name,

+           &nbs= p;            &= nbsp;          VendorGuid,

+           &nbs= p;            &= nbsp;          NULL,

+           &nbs= p;            &= nbsp;          &StateVarSi= ze,

+           &nbs= p;            &= nbsp;          NULL );

+      if (Status =3D=3D EFI_BUFFER_TOO_SMALL)= {

+        ReturnStatus =3D EFI_WRITE_= PROTECTED;

+        goto Exit;

+      }

+    }

+    // Check for lock on state variable.

+    else if (ActivePolicy->LockPolicyType =3D=3D VAR= IABLE_POLICY_TYPE_LOCK_ON_VAR_STATE) {

+      StateVarPolicy =3D (VARIABLE_LOCK_ON_VA= R_STATE_POLICY*)((UINT8*)ActivePolicy + sizeof(VARIABLE_POLICY_ENTRY));=

+      StateVarName =3D (CHAR16*)((UINT8*)Stat= eVarPolicy + sizeof(VARIABLE_LOCK_ON_VAR_STATE_POLICY));

+      StateVarSize =3D sizeof(StateVar);

+      Status =3D mGetVariableHelper( StateVar= Name,

+           &nbs= p;            &= nbsp;          &StateVarPo= licy->Namespace,

+           &nbs= p;            &= nbsp;          NULL,

+           &nbs= p;            &= nbsp;          &StateVarSi= ze,

+           &nbs= p;            &= nbsp;          &StateVar )= ;

+

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

+      if (!EFI_ERROR( Status )) {

+        if (StateVar =3D=3D StateVa= rPolicy->Value) {

+          ReturnStatus = =3D EFI_WRITE_PROTECTED;

+          goto Exit;

+        }

+      }

+      // EFI_NOT_FOUND and EFI_BUFFER_TOO_SMA= LL indicate that the state doesn't match.

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

+        // We don't know what happe= ned, but it isn't good.

+        ReturnStatus =3D EFI_ABORTE= D;

+        goto Exit;

+      }

+    }

+  }

+

+Exit:

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

+  return ReturnStatus;

+}

+

+

+/**

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

+  already been called once, will return EFI_ALREADY_STARTED.

+

+  @retval     EFI_SUCCESS

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

+  @retval     EFI_WRITE_PROTECTED  = Interface has been locked until reboot.

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

+  @retval     EFI_NOT_READY   =       Library has not yet been initialized.

+

+**/

+EFI_STATUS

+EFIAPI

+DisableVariablePolicy (

+  VOID

+  )

+{

+  if (!IsVariablePolicyLibInitialized()) {

+    return EFI_NOT_READY;

+  }

+  if (mProtectionDisabled) {

+    return EFI_ALREADY_STARTED;

+  }

+  if (mInterfaceLocked) {

+    return EFI_WRITE_PROTECTED;

+  }

+  if (!PcdGetBool (PcdAllowVariablePolicyEnforcementDisable)) {
+    return EFI_WRITE_PROTECTED;

+  }

+  mProtectionDisabled =3D TRUE;

+  return EFI_SUCCESS;

+}

+

+

+/**

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

+

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

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

+

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

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

+           &nbs= p;            &= nbsp; of the data returned.

+

+  @retval     EFI_SUCCESS   &n= bsp;         Policy data is in the = output buffer and Size has been updated.

+  @retval     EFI_INVALID_PARAMETER &nbs= p; Size is NULL, or Size is non-zero and Policy is NULL.

+  @retval     EFI_BUFFER_TOO_SMALL  = ;  Size is insufficient to hold policy. Size updated with required siz= e.

+  @retval     EFI_NOT_READY   =         Library has not yet been initial= ized.

+

+**/

+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    &n= bsp;    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 up= dates

+  can be performed or changes made to the enforcement until the n= ext boot.

+

+  @retval     EFI_SUCCESS

+  @retval     EFI_NOT_READY   Libra= ry 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 i= s locked

+  for the remainder of the boot.

+

+  @retval     TRUE

+  @retval     FALSE

+  @retval     FALSE    &n= bsp;    Library has not yet been initialized.

+

+**/

+BOOLEAN

+EFIAPI

+IsVariablePolicyInterfaceLocked (

+  VOID

+  )

+{

+  if (!IsVariablePolicyLibInitialized()) {

+    return FALSE;

+  }

+  return mInterfaceLocked;

+}

+

+

+/**

+  This helper function initializes the library and sets

+  up any required internal structures or handlers.

+

+  Also registers the internal pointer for the GetVariable helper.=

+

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

+           &nbs= p;      check policy criteria that involve the exi= stence of other variables.

+

+  @retval     EFI_SUCCESS

+  @retval     EFI_ALREADY_STARTED  = The initialize function has been called more than once without a call to
+           &nbs= p;            &= nbsp;           deinitial= ize.

+

+**/

+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 GetVariableHelpe= r.

+    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 curr= ently initialized.

+

+  @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 calling 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..f133f2f30e36
--- /dev/null
+++ b/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyUnit= Test/VariablePolicyUnitTest.c
@@ -0,0 +1,2436 @@
+/** @file -- VariablePolicyUnitTest.c

+UnitTest for...

+Business logic for Variable Policy enforcement.

+

+Copyright (c) Microsoft Corporation.

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

+

+**/

+

+#include <stdio.h>

+#include <string.h>

+#include <stdarg.h>

+#include <stddef.h>

+#include <setjmp.h>

+#include <cmocka.h>

+

+#include <Uefi.h>

+#include <Library/PrintLib.h>

+#include <Library/DebugLib.h>

+#include <Library/UnitTestLib.h>

+#include <Library/BaseMemoryLib.h>

+#include <Library/MemoryAllocationLib.h>

+#include <Library/BaseLib.h>

+

+#include <Guid/VariableFormat.h>

+

+#include <Protocol/VariablePolicy.h>

+#include <Library/VariablePolicyLib.h>

+

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

+// #ifndef INTERNAL_UNIT_TEST

+// #error Make sure to build thie with INTERNAL_UNIT_TEST enabled! Oth= erwise, 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         &nb= sp;          Name[];

+} SIMPLE_VARIABLE_POLICY_ENTRY;

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

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

+typedef struct _EXPANDED_VARIABLE_POLICY_ENTRY {

+  VARIABLE_POLICY_ENTRY       =         Header;

+  VARIABLE_LOCK_ON_VAR_STATE_POLICY   StatePolicy;

+  CHAR16         &nb= sp;            =         StateName[EXPANDED_VARIABLE_POLI= CY_ENTRY_VAR_NAME_LENGTH];

+  CHAR16         &nb= sp;            =         Name[EXPANDED_VARIABLE_POLICY_EN= TRY_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, 0= x45, 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"TestVa= r1"

+#define   TEST_VAR_2_NAME      = ;           L"TestVa= r2"

+#define   TEST_VAR_3_NAME      = ;           L"TestVa= r3"

+

+#define   TEST_POLICY_ATTRIBUTES_NULL    = ; 0

+#define   TEST_POLICY_MIN_SIZE_NULL    &= nbsp;  0

+#define   TEST_POLICY_MAX_SIZE_NULL    &= nbsp;  MAX_UINT32

+

+#define   TEST_POLICY_MIN_SIZE_10    &nb= sp;    10

+#define   TEST_POLICY_MAX_SIZE_200    &n= bsp;   200

+

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

+           &nbs= p;            &= nbsp;           &nbs= p; "##################################################"\

+           &nbs= p;            &= nbsp;           &nbs= p; "##################################################"\

+           &nbs= p;            &= nbsp;           &nbs= p; "##################################################"\

+           &nbs= p;            &= nbsp;           &nbs= p; "##################################################"\

+           &nbs= p;            &= nbsp;           &nbs= p; "##################################################"

+

+

+///=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 Name and StateName.

+

+  Takes care of all the messy packing.

+

+  @param[in,out]  Entry

+  @param[in]      Name   =      [Optional]

+  @param[in]      StateName   = [Optional]

+

+  @retval     TRUE

+  @retval     FALSE

+

+**/

+STATIC

+BOOLEAN

+InitExpVarPolicyStrings (

+  EXPANDED_VARIABLE_POLICY_ENTRY      *E= ntry,

+  CHAR16         &nb= sp;            =         *Name,    &n= bsp; OPTIONAL

+  CHAR16         &nb= sp;            =         *StateName  OPTIONAL

+  )

+{

+  UINTN     NameSize;

+  UINTN     StateNameSize;

+

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

+  StateNameSize =3D StateName =3D=3D NULL ? 0 : StrSize( StateNam= e );

+

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

+      StateNameSize > EXPANDED_VARIABLE_PO= LICY_ENTRY_VAR_NAME_SIZE || StateNameSize > MAX_UINT16) {

+    return FALSE;

+  }

+

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

+  if (StateName !=3D NULL) {

+    Entry->Header.OffsetToName +=3D (UINT16)size= of(VARIABLE_LOCK_ON_VAR_STATE_POLICY) + (UINT16)StateNameSize;

+  }

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

+

+  CopyMem( (UINT8*)Entry + Entry->Header.OffsetToName, Nam= e, NameSize );

+  if (StateName !=3D NULL) {

+    CopyMem( (UINT8*)Entry + sizeof(VARIABLE_POLICY= _ENTRY) + sizeof(VARIABLE_LOCK_ON_VAR_STATE_POLICY), StateName, StateNa= meSize );

+  }

+

+  return TRUE;

+}

+

+/**

+  Mocked version of GetVariable, for testing.

+**/

+EFI_STATUS

+EFIAPI

+StubGetVariableNull (

+  IN     CHAR16     =             &nb= sp;    *VariableName,

+  IN     EFI_GUID    &nbs= p;            &= nbsp;  *VendorGuid,

+  OUT    UINT32      = ;            &n= bsp;   *Attributes,    OPTIONAL

+  IN OUT UINTN        &nb= sp;            =   *DataSize,

+  OUT    VOID      &= nbsp;           &nbs= p;     *Data       &= nbsp;   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*)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 initialized

+  with the stubbed GetVariable.

+

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

+**/

+STATIC

+UNIT_TEST_STATUS

+LibInitMocked (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

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

+}

+

+/**

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

+  to the next test case.

+*/

+STATIC

+VOID

+LibCleanup (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  DeinitVariablePolicyLib();

+}

+

+

+///=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) + siz= eof(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( &TestPol= icy.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= ,

+           &nbs= p;            &= nbsp;           &nbs= p;            &m= TestGuid1,

+           &nbs= p;            &= nbsp;           &nbs= p;            VARIAB= LE_ATTRIBUTE_NV_BS,

+           &nbs= p;            &= nbsp;           &nbs= p;            sizeof= (DummyData),

+           &nbs= p;            &= nbsp;           &nbs= p;            DummyD= ata ) ) );

+

+  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      &nbs= p;         *VendorGuid,

+  OUT       UINT8   =             &nb= sp;   *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) + siz= eof(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.Hea= der, CheckVar2Name, &mTestGuid1, NULL ) );

+

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

+  UT_ASSERT_FALSE( EvaluatePolicyMatch( &MatchCheckPolicy.Hea= der, CheckVar1Name, &mTestGuid2, NULL ) );

+

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

+  UT_ASSERT_TRUE( EvaluatePolicyMatch( &MatchCheckPolicy.Head= er, CheckVar1Name, &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) + siz= eof(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.Head= er, CheckVar1Name, &mTestGuid1, NULL ) );

+  UT_ASSERT_TRUE( EvaluatePolicyMatch( &MatchCheckPolicy.Head= er, CheckVar2Name, &mTestGuid1, NULL ) );

+

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

+  UT_ASSERT_FALSE( EvaluatePolicyMatch( &MatchCheckPolicy.Hea= der, CheckVarBName, &mTestGuid1, NULL ) );

+

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

+  UT_ASSERT_FALSE( EvaluatePolicyMatch( &MatchCheckPolicy.Hea= der, CheckVarHName, &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) + siz= eof(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        *CheckShorterS= tring =3D L"01234567890123456789012345678901234567890123456789";<= br>
+  CHAR16        *CheckValidStr= ing =3D L"01234567890123456789012345678901234567890123456789"\
+           &nbs= p;            &= nbsp;           &nbs= p; "01234567890123456789012345678901234567890123456789"\

+           &nbs= p;            &= nbsp;           &nbs= p; "01234567890123456789012345678901234567890123456789"\

+           &nbs= p;            &= nbsp;           &nbs= p; "01234567890123456789012345678901234567890123456789"\

+           &nbs= p;            &= nbsp;           &nbs= p; "01234567890123456789012345678901234567890123456789"\

+           &nbs= p;            &= nbsp;           &nbs= p; "01234567890123456789012345678901234567890123456789";

+  CHAR16        *CheckLongerSt= ring =3D L"01234567890123456789012345678901234567890123456789"\
+           &nbs= p;            &= nbsp;           &nbs= p; "01234567890123456789012345678901234567890123456789"\

+           &nbs= p;            &= nbsp;           &nbs= p; "01234567890123456789012345678901234567890123456789"\

+           &nbs= p;            &= nbsp;           &nbs= p; "01234567890123456789012345678901234567890123456789"\

+           &nbs= p;            &= nbsp;           &nbs= p; "01234567890123456789012345678901234567890123456789"\

+           &nbs= p;            &= nbsp;           &nbs= p; "01234567890123456789012345678901234567890123456789"\

+           &nbs= p;            &= nbsp;           &nbs= p; "01234567890123456789012345678901234567890123456789";

+  UINT8         MatchPrio= rity;

+

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

+  UT_ASSERT_FALSE( EvaluatePolicyMatch( &MatchCheckPolicy.Hea= der, CheckShorterString, &mTestGuid1, NULL ) );

+  UT_ASSERT_FALSE( EvaluatePolicyMatch( &MatchCheckPolicy.Hea= der, CheckLongerString, &mTestGuid1, NULL ) );

+

+  // Make sure that the valid one matches and has the expected pr= iority.

+  UT_ASSERT_TRUE( EvaluatePolicyMatch( &MatchCheckPolicy.Head= er, CheckValidString, &mTestGuid1, &MatchPriority ) );

+  UT_ASSERT_EQUAL( MatchPriority, MAX_UINT8 );

+

+  return UNIT_TEST_PASSED;

+}

+

+/**

+  Test Case

+*/

+UNIT_TEST_STATUS

+EFIAPI

+WildcardPoliciesShouldMatchNamespaces (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  VARIABLE_POLICY_ENTRY   MatchCheckPolicy =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, Che= ckVar1Name, &mTestGuid1, NULL ) );

+  UT_ASSERT_TRUE( EvaluatePolicyMatch( &MatchCheckPolicy, Che= ckVar2Name, &mTestGuid1, NULL ) );

+  UT_ASSERT_TRUE( EvaluatePolicyMatch( &MatchCheckPolicy, Che= ckVarBName, &mTestGuid1, NULL ) );

+  UT_ASSERT_TRUE( EvaluatePolicyMatch( &MatchCheckPolicy, Che= ckVarHName, &mTestGuid1, NULL ) );

+

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

+  UT_ASSERT_FALSE( EvaluatePolicyMatch( &MatchCheckPolicy, Ch= eckVar1Name, &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) + siz= eof(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         MatchPrio= rity;

+

+  // Check with a perfect match.

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

+  UT_ASSERT_TRUE( EvaluatePolicyMatch( &MatchCheckPolicy.Head= er, CheckVar1Name, &mTestGuid1, &MatchPriority ) );

+  UT_ASSERT_EQUAL( MatchPriority, 0 );

+

+  // Check with progressively lower priority matches.

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

+  UT_ASSERT_TRUE( EvaluatePolicyMatch( &MatchCheckPolicy.Head= er, CheckVar1Name, &mTestGuid1, &MatchPriority ) );

+  UT_ASSERT_EQUAL( MatchPriority, 1 );

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

+  UT_ASSERT_TRUE( EvaluatePolicyMatch( &MatchCheckPolicy.Head= er, CheckVar1Name, &mTestGuid1, &MatchPriority ) );

+  UT_ASSERT_EQUAL( MatchPriority, 2 );

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

+  UT_ASSERT_TRUE( EvaluatePolicyMatch( &MatchCheckPolicy.Head= er, CheckVar1Name, &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.Head= er, CheckVar1Name, &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( &Validatio= nPolicy.Header ) );

+

+  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 populat= ed by init helper.

+      0,    // Will be populat= ed 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<= br>
+    },

+    {

+      TEST_GUID_2,

+      1,      &= nbsp;     // Value

+      0      &n= bsp;      // Padding

+    },

+    L"",

+    L""

+  };

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

+

+  UT_ASSERT_NOT_EFI_ERROR( RegisterVariablePolicy( &Validatio= nPolicy.Header ) );

+

+  return UNIT_TEST_PASSED;

+}

+

+/**

+  Test Case

+*/

+UNIT_TEST_STATUS

+EFIAPI

+RegisterShouldRejectNullPointers (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  UT_ASSERT_EQUAL( RegisterVariablePolicy( NULL ), EFI_INVALID_PA= RAMETER );

+  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) + siz= eof(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) + siz= eof(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 populat= ed by init helper.

+      0,    // Will be populat= ed 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<= br>
+    },

+    {

+      TEST_GUID_2,

+      1,      &= nbsp;     // Value

+      0      &n= bsp;      // Padding

+    },

+    L"",

+    L""

+  };

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

+

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

+  ValidationPolicy.Header.OffsetToName =3D ValidationPolicy.Heade= r.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 populat= ed by init helper.

+      0,    // Will be populat= ed 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<= br>
+    },

+    {

+      TEST_GUID_2,

+      1,      &= nbsp;     // Value

+      0      &n= bsp;      // Padding

+    },

+    L"",

+    L""

+  };

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

+

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

+  ValidationPolicy.Header.Size      = ;    =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.H= eader.OffsetToName, TEST_VAR_1_NAME, sizeof(TEST_VAR_1_NAME) );

+

+  // Make sure that this structure fails.

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

+

+  return UNIT_TEST_PASSED;

+}

+

+/**

+  Test Case

+*/

+UNIT_TEST_STATUS

+EFIAPI

+RegisterShouldRejectStringsMissingNull (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  EXPANDED_VARIABLE_POLICY_ENTRY   ValidationPolicy =3D= {

+    {

+      VARIABLE_POLICY_ENTRY_REVISION,

+      0,    // Will be populat= ed by init helper.

+      0,    // Will be populat= ed 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<= br>
+    },

+    {

+      TEST_GUID_2,

+      1,      &= nbsp;     // Value

+      0      &n= bsp;      // Padding

+    },

+    L"",

+    L""

+  };

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

+

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

+  ValidationPolicy.Header.Size =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.<= br>
+  // Copy the Name up one byte.

+  ValidationPolicy.Header.OffsetToName =3D ValidationPolicy.Heade= r.OffsetToName - sizeof(CHAR16);

+  CopyMem( (UINT8*)&ValidationPolicy + ValidationPolicy.H= eader.OffsetToName, TEST_VAR_1_NAME, sizeof(TEST_VAR_1_NAME) );

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

+

+  return UNIT_TEST_PASSED;

+}

+

+/**

+  Test Case

+*/

+UNIT_TEST_STATUS

+EFIAPI

+RegisterShouldRejectMalformedStrings (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  EXPANDED_VARIABLE_POLICY_ENTRY   ValidationPolicy =3D= {

+    {

+      VARIABLE_POLICY_ENTRY_REVISION,

+      0,    // Will be populat= ed by init helper.

+      0,    // Will be populat= ed 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<= br>
+    },

+    {

+      TEST_GUID_2,

+      1,      &= nbsp;     // Value

+      0      &n= bsp;      // Padding

+    },

+    L"",

+    L""

+  };

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

+

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

+  ValidationPolicy.Header.Size =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.Heade= r.OffsetToName - 1;

+  CopyMem( (UINT8*)&ValidationPolicy + ValidationPolicy.H= eader.OffsetToName, TEST_VAR_1_NAME, sizeof(TEST_VAR_1_NAME) );

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

+

+  return UNIT_TEST_PASSED;

+}

+

+/**

+  Test Case

+*/

+UNIT_TEST_STATUS

+EFIAPI

+RegisterShouldRejectUnpackedPolicies (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  EXPANDED_VARIABLE_POLICY_ENTRY   ValidationPolicy =3D= {

+    {

+      VARIABLE_POLICY_ENTRY_REVISION,

+      0,    // Will be populat= ed by init helper.

+      0,    // Will be populat= ed 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<= br>
+    },

+    {

+      TEST_GUID_2,

+      1,      &= nbsp;     // Value

+      0      &n= bsp;      // Padding

+    },

+    L"",

+    L""

+  };

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

+

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

+  ValidationPolicy.Header.Size =3D ValidationPolicy.Header.Size &= #43; sizeof(CHAR16);

+  ValidationPolicy.Header.OffsetToName =3D ValidationPolicy.Heade= r.OffsetToName + sizeof(CHAR16);

+  CopyMem( (UINT8*)&ValidationPolicy + ValidationPolicy.H= eader.OffsetToName, TEST_VAR_1_NAME, sizeof(TEST_VAR_1_NAME) );

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

+

+  // Reintialize without the state policy and try the same test.<= br>
+  ValidationPolicy.Header.LockPolicyType =3D VARIABLE_POLICY_TYPE= _NO_LOCK;

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

+  ValidationPolicy.Header.Size =3D ValidationPolicy.Header.Size &= #43; sizeof(CHAR16);

+  ValidationPolicy.Header.OffsetToName =3D ValidationPolicy.Heade= r.OffsetToName + sizeof(CHAR16);

+  CopyMem( (UINT8*)&ValidationPolicy + ValidationPolicy.H= eader.OffsetToName, TEST_VAR_1_NAME, sizeof(TEST_VAR_1_NAME) );

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

+

+  return UNIT_TEST_PASSED;

+}

+

+/**

+  Test Case

+*/

+UNIT_TEST_STATUS

+EFIAPI

+RegisterShouldRejectInvalidNameCharacters (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  // EXPANDED_VARIABLE_POLICY_ENTRY   ValidationPolicy = =3D {

+  //   {

+  //     VARIABLE_POLICY_ENTRY_REVISION,

+  //     0,    // Will be popu= lated by init helper.

+  //     0,    // Will be popu= lated 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_STA= TE

+  //   },

+  //   {

+  //     TEST_GUID_2,

+  //     1,     &nbs= p;      // 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) + siz= eof(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) + siz= eof(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) + siz= eof(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 mat= ch priority.

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

+

+  return UNIT_TEST_PASSED;

+}

+

+/**

+  Test Case

+*/

+UNIT_TEST_STATUS

+EFIAPI

+RegisterShouldRejectDuplicatePolicies (

+  IN UNIT_TEST_CONTEXT      Context

+  )

+{

+  SIMPLE_VARIABLE_POLICY_ENTRY   ValidationPolicy =3D {=

+    {

+      VARIABLE_POLICY_ENTRY_REVISION,

+      sizeof(VARIABLE_POLICY_ENTRY) + siz= eof(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( &Validatio= nPolicy.Header ) );

+  UT_ASSERT_STATUS_EQUAL( RegisterVariablePolicy( &Validation= Policy.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) + siz= eof(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,

+           &nbs= p;            &= nbsp;           &mTes= tGuid1,

+           &nbs= p;            &= nbsp;           VARIABLE_= ATTRIBUTE_NV_BS,

+           &nbs= p;            &= nbsp;           TEST_POLI= CY_MAX_SIZE_200+1,

+           &nbs= p;            &= nbsp;           DummyData= );

+  UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );

+

+  // Set a policy to test against.

+  UT_ASSERT_NOT_EFI_ERROR( RegisterVariablePolicy( &Validatio= nPolicy.Header ) );

+

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

+  PolicyCheck =3D ValidateSetVariable( TEST_VAR_1_NAME,

+           &nbs= p;            &= nbsp;           &mTes= tGuid1,

+           &nbs= p;            &= nbsp;           VARIABLE_= ATTRIBUTE_NV_BS,

+           &nbs= p;            &= nbsp;           TEST_POLI= CY_MAX_SIZE_200+1,

+           &nbs= p;            &= nbsp;           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,

+           &nbs= p;            &= nbsp;           &mTes= tGuid1,

+           &nbs= p;            &= nbsp;           VARIABLE_= ATTRIBUTE_NV_BS,

+           &nbs= p;            &= nbsp;           TEST_POLI= CY_MIN_SIZE_10-1,

+           &nbs= p;            &= nbsp;           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,

+           &nbs= p;            &= nbsp;           &mTes= tGuid1,

+           &nbs= p;            &= nbsp;           VARIABLE_= ATTRIBUTE_NV_BS,

+           &nbs= p;            &= nbsp;           TEST_POLI= CY_MIN_SIZE_10+1,

+           &nbs= p;            &= nbsp;           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) + siz= eof(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,

+           &nbs= p;            &= nbsp;           &mTes= tGuid1,

+           &nbs= p;            &= nbsp;           TEST_POLI= CY_ATTRIBUTES_NULL,

+           &nbs= p;            &= nbsp;           sizeof(Du= mmyData),

+           &nbs= p;            &= nbsp;           DummyData= );

+  UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );

+

+  // Set a policy to test against.

+  UT_ASSERT_NOT_EFI_ERROR( RegisterVariablePolicy( &Validatio= nPolicy.Header ) );

+

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

+  PolicyCheck =3D ValidateSetVariable( TEST_VAR_1_NAME,

+           &nbs= p;            &= nbsp;           &mTes= tGuid1,

+           &nbs= p;            &= nbsp;           TEST_POLI= CY_ATTRIBUTES_NULL,

+           &nbs= p;            &= nbsp;           sizeof(Du= mmyData),

+           &nbs= p;            &= nbsp;           DummyData= );

+  UT_ASSERT_TRUE( EFI_ERROR( PolicyCheck ) );

+

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

+  PolicyCheck =3D ValidateSetVariable( TEST_VAR_1_NAME,

+           &nbs= p;            &= nbsp;           &mTes= tGuid1,

+           &nbs= p;            &= nbsp;           VARIABLE_= ATTRIBUTE_BS_RT_AT,

+           &nbs= p;            &= nbsp;           sizeof(Du= mmyData),

+           &nbs= p;            &= nbsp;           DummyData= );

+  UT_ASSERT_TRUE( EFI_ERROR( PolicyCheck ) );

+

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

+  PolicyCheck =3D ValidateSetVariable( TEST_VAR_1_NAME,

+           &nbs= p;            &= nbsp;           &mTes= tGuid1,

+           &nbs= p;            &= nbsp;           VARIABLE_= ATTRIBUTE_NV_BS_RT,

+           &nbs= p;            &= nbsp;           sizeof(Du= mmyData),

+           &nbs= p;            &= nbsp;           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,

+           &nbs= p;            &= nbsp;           &mTes= tGuid1,

+           &nbs= p;            &= nbsp;           VARIABLE_= ATTRIBUTE_NV_BS_RT_AT,

+           &nbs= p;            &= nbsp;           sizeof(Du= mmyData),

+           &nbs= p;            &= nbsp;           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) + siz= eof(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_W= RITE_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,

+           &nbs= p;            &= nbsp;           &mTes= tGuid1,

+           &nbs= p;            &= nbsp;           VARIABLE_= ATTRIBUTE_BS_RT_AT,

+           &nbs= p;            &= nbsp;           sizeof(Du= mmyData),

+           &nbs= p;            &= nbsp;           DummyData= );

+  UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );

+

+  // Set a policy to test against.

+  UT_ASSERT_NOT_EFI_ERROR( RegisterVariablePolicy( &Validatio= nPolicy.Header ) );

+

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

+  PolicyCheck =3D ValidateSetVariable( TEST_VAR_1_NAME,

+           &nbs= p;            &= nbsp;           &mTes= tGuid1,

+           &nbs= p;            &= nbsp;           EFI_VARIA= BLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS,

+           &nbs= p;            &= nbsp;           sizeof(Du= mmyData),

+           &nbs= p;            &= nbsp;           DummyData= );

+  UT_ASSERT_TRUE( EFI_ERROR( PolicyCheck ) );

+

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

+  PolicyCheck =3D ValidateSetVariable( TEST_VAR_1_NAME,

+           &nbs= p;            &= nbsp;           &mTes= tGuid1,

+           &nbs= p;            &= nbsp;           VARIABLE_= ATTRIBUTE_BS_RT_AT,

+           &nbs= p;            &= nbsp;           sizeof(Du= mmyData),

+           &nbs= p;            &= nbsp;           DummyData= );

+  UT_ASSERT_TRUE( EFI_ERROR( PolicyCheck ) );

+

+  // With a policy, make sure that attributes without the forbidd= en pass.

+  PolicyCheck =3D ValidateSetVariable( TEST_VAR_1_NAME,

+           &nbs= p;            &= nbsp;           &mTes= tGuid1,

+           &nbs= p;            &= nbsp;           VARIABLE_= ATTRIBUTE_NV_BS_RT,

+           &nbs= p;            &= nbsp;           sizeof(Du= mmyData),

+           &nbs= p;            &= nbsp;           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) + siz= eof(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_W= RITE_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( &Validatio= nPolicy.Header ) );

+

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

+  PolicyCheck =3D ValidateSetVariable( TEST_VAR_1_NAME,

+           &nbs= p;            &= nbsp;           &mTes= tGuid1,

+           &nbs= p;            &= nbsp;           VARIABLE_= ATTRIBUTE_NV_BS,

+           &nbs= p;            &= nbsp;           TEST_POLI= CY_MIN_SIZE_10-1,

+           &nbs= p;            &= nbsp;           DummyData= );

+  UT_ASSERT_STATUS_EQUAL( PolicyCheck, EFI_INVALID_PARAMETER );
+

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

+  PolicyCheck =3D ValidateSetVariable( TEST_VAR_1_NAME,

+           &nbs= p;            &= nbsp;           &mTes= tGuid1,

+           &nbs= p;            &= nbsp;           VARIABLE_= ATTRIBUTE_NV_BS,

+           &nbs= p;            &= nbsp;           0,

+           &nbs= p;            &= nbsp;           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) + siz= eof(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,

+           &nbs= p;            &= nbsp;           &mTes= tGuid1,

+           &nbs= p;            &= nbsp;           VARIABLE_= ATTRIBUTE_BS_RT_AT,

+           &nbs= p;            &= nbsp;           sizeof(Du= mmyData),

+           &nbs= p;            &= nbsp;           DummyData= );

+  UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );

+

+  // Set a policy to test against.

+  UT_ASSERT_NOT_EFI_ERROR( RegisterVariablePolicy( &Validatio= nPolicy.Header ) );

+

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

+  PolicyCheck =3D ValidateSetVariable( TEST_VAR_1_NAME,

+           &nbs= p;            &= nbsp;           &mTes= tGuid1,

+           &nbs= p;            &= nbsp;           VARIABLE_= ATTRIBUTE_BS_RT_AT,

+           &nbs= p;            &= nbsp;           sizeof(Du= mmyData),

+           &nbs= p;            &= nbsp;           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) + siz= eof(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,

+           &nbs= p;            &= nbsp;           &mTes= tGuid1,

+           &nbs= p;            &= nbsp;           VARIABLE_= ATTRIBUTE_BS_RT_AT,

+           &nbs= p;            &= nbsp;           sizeof(Du= mmyData),

+           &nbs= p;            &= nbsp;           DummyData= );

+  UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );

+

+  // Set a policy to test against.

+  UT_ASSERT_NOT_EFI_ERROR( RegisterVariablePolicy( &Validatio= nPolicy.Header ) );

+

+  // Set consistent expectations on what the calls are looking fo= r.

+  expect_memory_count( StubGetVariableNull, VariableName, TEST_VA= R_1_NAME, sizeof(TEST_VAR_1_NAME), 2 );

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

+  ExpectedDataSize =3D 0;

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

+

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

+  will_return( StubGetVariableNull, TEST_POLICY_ATTRIBUTES_NULL )= ;    // Attributes

+  will_return( StubGetVariableNull, 0 );    &= nbsp;           &nbs= p;             = // Size

+  will_return( StubGetVariableNull, NULL );   &nbs= p;            &= nbsp;          // DataPtr

+  will_return( StubGetVariableNull, EFI_NOT_FOUND );  &= nbsp;           &nbs= p;   // Status

+  PolicyCheck =3D ValidateSetVariable( TEST_VAR_1_NAME,

+           &nbs= p;            &= nbsp;           &mTes= tGuid1,

+           &nbs= p;            &= nbsp;           VARIABLE_= ATTRIBUTE_BS_RT_AT,

+           &nbs= p;            &= nbsp;           sizeof(Du= mmyData),

+           &nbs= p;            &= nbsp;           DummyData= );

+  UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );

+

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

+  will_return( StubGetVariableNull, TEST_POLICY_ATTRIBUTES_NULL )= ;    // Attributes

+  will_return( StubGetVariableNull, 10 );    =             &nb= sp;            // Si= ze

+  will_return( StubGetVariableNull, NULL );   &nbs= p;            &= nbsp;          // DataPtr

+  will_return( StubGetVariableNull, EFI_BUFFER_TOO_SMALL ); =           // Status

+  PolicyCheck =3D ValidateSetVariable( TEST_VAR_1_NAME,

+           &nbs= p;            &= nbsp;           &mTes= tGuid1,

+           &nbs= p;            &= nbsp;           VARIABLE_= ATTRIBUTE_BS_RT_AT,

+           &nbs= p;            &= nbsp;           sizeof(Du= mmyData),

+           &nbs= p;            &= nbsp;           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 populat= ed by init helper.

+      0,    // Will be populat= ed 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<= br>
+    },

+    {

+      TEST_GUID_2,

+      20,      =      // Value

+      0      &n= bsp;      // Padding

+    },

+    L"",

+    L""

+  };

+  EFI_STATUS  PolicyCheck;

+  UINT8       DummyData[12];

+  UINT8       ValidationStateVar;
+  UINTN       ExpectedDataSize;

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

+

+

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

+  PolicyCheck =3D ValidateSetVariable( TEST_VAR_1_NAME,

+           &nbs= p;            &= nbsp;           &mTes= tGuid1,

+           &nbs= p;            &= nbsp;           VARIABLE_= ATTRIBUTE_BS_RT_AT,

+           &nbs= p;            &= nbsp;           sizeof(Du= mmyData),

+           &nbs= p;            &= nbsp;           DummyData= );

+  UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );

+

+  // Set a policy to test against.

+  UT_ASSERT_NOT_EFI_ERROR( RegisterVariablePolicy( &Validatio= nPolicy.Header ) );

+

+  // Set consistent expectations on what the calls are looking fo= r.

+  expect_memory_count( StubGetVariableNull, VariableName, TEST_VA= R_2_NAME, sizeof(TEST_VAR_2_NAME), 5 );

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

+  ExpectedDataSize =3D 1;

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

+

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

+  will_return( StubGetVariableNull, TEST_POLICY_ATTRIBUTES_NULL )= ;    // Attributes

+  will_return( StubGetVariableNull, 0 );    &= nbsp;           &nbs= p;             = // Size

+  will_return( StubGetVariableNull, NULL );   &nbs= p;            &= nbsp;          // DataPtr

+  will_return( StubGetVariableNull, EFI_NOT_FOUND );  &= nbsp;           &nbs= p;   // Status

+  PolicyCheck =3D ValidateSetVariable( TEST_VAR_1_NAME,

+           &nbs= p;            &= nbsp;           &mTes= tGuid1,

+           &nbs= p;            &= nbsp;           VARIABLE_= ATTRIBUTE_BS_RT_AT,

+           &nbs= p;            &= nbsp;           sizeof(Du= mmyData),

+           &nbs= p;            &= nbsp;           DummyData= );

+  UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );

+

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

+  will_return( StubGetVariableNull, TEST_POLICY_ATTRIBUTES_NULL )= ;    // Attributes

+  will_return( StubGetVariableNull, 10 );    =             &nb= sp;            // Si= ze

+  will_return( StubGetVariableNull, NULL );   &nbs= p;            &= nbsp;          // DataPtr

+  will_return( StubGetVariableNull, EFI_BUFFER_TOO_SMALL ); =           // Status

+  PolicyCheck =3D ValidateSetVariable( TEST_VAR_1_NAME,

+           &nbs= p;            &= nbsp;           &mTes= tGuid1,

+           &nbs= p;            &= nbsp;           VARIABLE_= ATTRIBUTE_BS_RT_AT,

+           &nbs= p;            &= nbsp;           sizeof(Du= mmyData),

+           &nbs= p;            &= nbsp;           DummyData= );

+  UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );

+

+  // With a policy, check a state variable with the wrong value.<= br>
+  ValidationStateVar =3D 0;

+  will_return( StubGetVariableNull, TEST_POLICY_ATTRIBUTES_NULL )= ;    // Attributes

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

+  will_return( StubGetVariableNull, &ValidationStateVar );&nb= sp;           // DataPtr<= br>
+  will_return( StubGetVariableNull, EFI_SUCCESS );  &nb= sp;            =      // Status

+  PolicyCheck =3D ValidateSetVariable( TEST_VAR_1_NAME,

+           &nbs= p;            &= nbsp;           &mTes= tGuid1,

+           &nbs= p;            &= nbsp;           VARIABLE_= ATTRIBUTE_BS_RT_AT,

+           &nbs= p;            &= nbsp;           sizeof(Du= mmyData),

+           &nbs= p;            &= nbsp;           DummyData= );

+  UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );

+

+  // With a policy, check a state variable with another wrong val= ue.

+  ValidationStateVar =3D 10;

+  will_return( StubGetVariableNull, TEST_POLICY_ATTRIBUTES_NULL )= ;    // Attributes

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

+  will_return( StubGetVariableNull, &ValidationStateVar );&nb= sp;           // DataPtr<= br>
+  will_return( StubGetVariableNull, EFI_SUCCESS );  &nb= sp;            =      // Status

+  PolicyCheck =3D ValidateSetVariable( TEST_VAR_1_NAME,

+           &nbs= p;            &= nbsp;           &mTes= tGuid1,

+           &nbs= p;            &= nbsp;           VARIABLE_= ATTRIBUTE_BS_RT_AT,

+           &nbs= p;            &= nbsp;           sizeof(Du= mmyData),

+           &nbs= p;            &= nbsp;           DummyData= );

+  UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );

+

+  // With a policy, make sure that a call with a correct state va= riable fails.

+  ValidationStateVar =3D 20;

+  will_return( StubGetVariableNull, TEST_POLICY_ATTRIBUTES_NULL )= ;    // Attributes

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

+  will_return( StubGetVariableNull, &ValidationStateVar );&nb= sp;           // DataPtr<= br>
+  will_return( StubGetVariableNull, EFI_SUCCESS );  &nb= sp;            =      // Status

+  PolicyCheck =3D ValidateSetVariable( TEST_VAR_1_NAME,

+           &nbs= p;            &= nbsp;           &mTes= tGuid1,

+           &nbs= p;            &= nbsp;           VARIABLE_= ATTRIBUTE_BS_RT_AT,

+           &nbs= p;            &= nbsp;           sizeof(Du= mmyData),

+           &nbs= p;            &= nbsp;           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 populat= ed by init helper.

+      0,    // Will be populat= ed 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<= br>
+    },

+    {

+      TEST_GUID_2,

+      20,      =      // Value

+      0      &n= bsp;      // Padding

+    },

+    L"",

+    L""

+  };

+  EFI_STATUS  PolicyCheck;

+  UINT8       DummyData[12];

+  UINT8       ValidationStateVar;
+  UINTN       ExpectedDataSize;

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

+

+

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

+  PolicyCheck =3D ValidateSetVariable( TEST_VAR_1_NAME,

+           &nbs= p;            &= nbsp;           &mTes= tGuid1,

+           &nbs= p;            &= nbsp;           VARIABLE_= ATTRIBUTE_BS_RT_AT,

+           &nbs= p;            &= nbsp;           sizeof(Du= mmyData),

+           &nbs= p;            &= nbsp;           DummyData= );

+  UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );

+  PolicyCheck =3D ValidateSetVariable( TEST_VAR_3_NAME,

+           &nbs= p;            &= nbsp;           &mTes= tGuid1,

+           &nbs= p;            &= nbsp;           VARIABLE_= ATTRIBUTE_BS_RT_AT,

+           &nbs= p;            &= nbsp;           sizeof(Du= mmyData),

+           &nbs= p;            &= nbsp;           DummyData= );

+  UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );

+

+  // Set a policy to test against.

+  UT_ASSERT_NOT_EFI_ERROR( RegisterVariablePolicy( &Validatio= nPolicy.Header ) );

+

+  // Set consistent expectations on what the calls are looking fo= r.

+  expect_memory_count( StubGetVariableNull, VariableName, TEST_VA= R_2_NAME, sizeof(TEST_VAR_2_NAME), 4 );

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

+  ExpectedDataSize =3D 1;

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

+

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

+  will_return( StubGetVariableNull, TEST_POLICY_ATTRIBUTES_NULL )= ;    // Attributes

+  will_return( StubGetVariableNull, 0 );    &= nbsp;           &nbs= p;             = // Size

+  will_return( StubGetVariableNull, NULL );   &nbs= p;            &= nbsp;          // DataPtr

+  will_return( StubGetVariableNull, EFI_NOT_FOUND );  &= nbsp;           &nbs= p;   // Status

+  PolicyCheck =3D ValidateSetVariable( TEST_VAR_1_NAME,

+           &nbs= p;            &= nbsp;           &mTes= tGuid1,

+           &nbs= p;            &= nbsp;           VARIABLE_= ATTRIBUTE_BS_RT_AT,

+           &nbs= p;            &= nbsp;           sizeof(Du= mmyData),

+           &nbs= p;            &= nbsp;           DummyData= );

+  UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );

+  will_return( StubGetVariableNull, TEST_POLICY_ATTRIBUTES_NULL )= ;    // Attributes

+  will_return( StubGetVariableNull, 0 );    &= nbsp;           &nbs= p;             = // Size

+  will_return( StubGetVariableNull, NULL );   &nbs= p;            &= nbsp;          // DataPtr

+  will_return( StubGetVariableNull, EFI_NOT_FOUND );  &= nbsp;           &nbs= p;   // Status

+  PolicyCheck =3D ValidateSetVariable( TEST_VAR_3_NAME,

+           &nbs= p;            &= nbsp;           &mTes= tGuid1,

+           &nbs= p;            &= nbsp;           VARIABLE_= ATTRIBUTE_BS_RT_AT,

+           &nbs= p;            &= nbsp;           sizeof(Du= mmyData),

+           &nbs= p;            &= nbsp;           DummyData= );

+  UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );

+

+  // With a policy, make sure that a call with a correct state va= riable fails.

+  ValidationStateVar =3D 20;

+  will_return( StubGetVariableNull, TEST_POLICY_ATTRIBUTES_NULL )= ;    // Attributes

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

+  will_return( StubGetVariableNull, &ValidationStateVar );&nb= sp;           // DataPtr<= br>
+  will_return( StubGetVariableNull, EFI_SUCCESS );  &nb= sp;            =      // Status

+  PolicyCheck =3D ValidateSetVariable( TEST_VAR_1_NAME,

+           &nbs= p;            &= nbsp;           &mTes= tGuid1,

+           &nbs= p;            &= nbsp;           VARIABLE_= ATTRIBUTE_BS_RT_AT,

+           &nbs= p;            &= nbsp;           sizeof(Du= mmyData),

+           &nbs= p;            &= nbsp;           DummyData= );

+  UT_ASSERT_TRUE( EFI_ERROR( PolicyCheck ) );

+  will_return( StubGetVariableNull, TEST_POLICY_ATTRIBUTES_NULL )= ;    // Attributes

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

+  will_return( StubGetVariableNull, &ValidationStateVar );&nb= sp;           // DataPtr<= br>
+  will_return( StubGetVariableNull, EFI_SUCCESS );  &nb= sp;            =      // Status

+  PolicyCheck =3D ValidateSetVariable( TEST_VAR_3_NAME,

+           &nbs= p;            &= nbsp;           &mTes= tGuid1,

+           &nbs= p;            &= nbsp;           VARIABLE_= ATTRIBUTE_BS_RT_AT,

+           &nbs= p;            &= nbsp;           sizeof(Du= mmyData),

+           &nbs= p;            &= nbsp;           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 populat= ed by init helper.

+      0,    // Will be populat= ed 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<= br>
+    },

+    {

+      TEST_GUID_2,

+      20,      =      // Value

+      0      &n= bsp;      // Padding

+    },

+    L"",

+    L""

+  };

+  EFI_STATUS  PolicyCheck;

+  UINT8       DummyData[12];

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

+

+

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

+  PolicyCheck =3D ValidateSetVariable( TEST_VAR_1_NAME,

+           &nbs= p;            &= nbsp;           &mTes= tGuid1,

+           &nbs= p;            &= nbsp;           VARIABLE_= ATTRIBUTE_BS_RT_AT,

+           &nbs= p;            &= nbsp;           sizeof(Du= mmyData),

+           &nbs= p;            &= nbsp;           DummyData= );

+  UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );

+

+  // Set a policy to test against.

+  UT_ASSERT_NOT_EFI_ERROR( RegisterVariablePolicy( &Validatio= nPolicy.Header ) );

+

+  // Configure the stub to not care about parameters. We're testi= ng 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 v= ariable doesn't exist.

+  will_return( StubGetVariableNull, TEST_POLICY_ATTRIBUTES_NULL )= ;    // Attributes

+  will_return( StubGetVariableNull, 0 );    &= nbsp;           &nbs= p;             = // Size

+  will_return( StubGetVariableNull, NULL );   &nbs= p;            &= nbsp;          // DataPtr

+  will_return( StubGetVariableNull, EFI_NOT_FOUND );  &= nbsp;           &nbs= p;   // Status

+  PolicyCheck =3D ValidateSetVariable( TEST_VAR_1_NAME,

+           &nbs= p;            &= nbsp;           &mTes= tGuid1,

+           &nbs= p;            &= nbsp;           VARIABLE_= ATTRIBUTE_BS_RT_AT,

+           &nbs= p;            &= nbsp;           sizeof(Du= mmyData),

+           &nbs= p;            &= nbsp;           DummyData= );

+  UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );

+

+  // Verify that state variables that are the wrong size won't lo= ck the variable.

+  will_return( StubGetVariableNull, TEST_POLICY_ATTRIBUTES_NULL )= ;    // Attributes

+  will_return( StubGetVariableNull, 0 );    &= nbsp;           &nbs= p;             = // Size

+  will_return( StubGetVariableNull, NULL );   &nbs= p;            &= nbsp;          // DataPtr

+  will_return( StubGetVariableNull, EFI_BUFFER_TOO_SMALL ); =           // Status

+  PolicyCheck =3D ValidateSetVariable( TEST_VAR_1_NAME,

+           &nbs= p;            &= nbsp;           &mTes= tGuid1,

+           &nbs= p;            &= nbsp;           VARIABLE_= ATTRIBUTE_BS_RT_AT,

+           &nbs= p;            &= nbsp;           sizeof(Du= mmyData),

+           &nbs= p;            &= nbsp;           DummyData= );

+  UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );

+

+  // Verify that unexpected errors default to locked.

+  will_return( StubGetVariableNull, TEST_POLICY_ATTRIBUTES_NULL )= ;    // Attributes

+  will_return( StubGetVariableNull, 0 );    &= nbsp;           &nbs= p;             = // Size

+  will_return( StubGetVariableNull, NULL );   &nbs= p;            &= nbsp;          // DataPtr

+  will_return( StubGetVariableNull, EFI_UNSUPPORTED );  = ;            &n= bsp; // Status

+  PolicyCheck =3D ValidateSetVariable( TEST_VAR_1_NAME,

+           &nbs= p;            &= nbsp;           &mTes= tGuid1,

+           &nbs= p;            &= nbsp;           VARIABLE_= ATTRIBUTE_BS_RT_AT,

+           &nbs= p;            &= nbsp;           sizeof(Du= mmyData),

+           &nbs= p;            &= nbsp;           DummyData= );

+  UT_ASSERT_TRUE( EFI_ERROR( PolicyCheck ) );

+

+  will_return( StubGetVariableNull, TEST_POLICY_ATTRIBUTES_NULL )= ;    // Attributes

+  will_return( StubGetVariableNull, 0 );    &= nbsp;           &nbs= p;             = // Size

+  will_return( StubGetVariableNull, NULL );   &nbs= p;            &= nbsp;          // DataPtr

+  will_return( StubGetVariableNull, EFI_NOT_READY );  &= nbsp;           &nbs= p;   // Status

+  PolicyCheck =3D ValidateSetVariable( TEST_VAR_1_NAME,

+           &nbs= p;            &= nbsp;           &mTes= tGuid1,

+           &nbs= p;            &= nbsp;           VARIABLE_= ATTRIBUTE_BS_RT_AT,

+           &nbs= p;            &= nbsp;           sizeof(Du= mmyData),

+           &nbs= p;            &= nbsp;           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) + siz= eof(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 + sizeof(VARIABLE_POLICY_ENTRY));

+  UINTN       PolicyNameSize =3D si= zeof(L"Wild12Card34Placeholder");

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

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

+  CHAR16      *TwoWildcards =3D L"W= ild##Card34Placeholder";

+  CHAR16      *OneWildcard =3D L"Wi= ld#2Card34Placeholder";

+  CHAR16      *NoWildcards =3D L"Wi= ld12Card34Placeholder";

+

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

+  // NoWildcards should be the most restrictive.

+  ValidationPolicy.Header.MaxSize =3D 60;

+  ValidationPolicy.Header.Size =3D ValidationPolicy.Header.Offset= ToName;

+  UT_ASSERT_NOT_EFI_ERROR( RegisterVariablePolicy( &Validatio= nPolicy.Header ) );

+  ValidationPolicy.Header.Size +=3D (UINT16)PolicyNameSize;
+  ValidationPolicy.Header.MaxSize =3D 50;

+  CopyMem( PolicyName, FourWildcards, PolicyNameSize );

+  UT_ASSERT_NOT_EFI_ERROR( RegisterVariablePolicy( &Validatio= nPolicy.Header ) );

+  ValidationPolicy.Header.MaxSize =3D 40;

+  CopyMem( PolicyName, ThreeWildcards, PolicyNameSize );

+  UT_ASSERT_NOT_EFI_ERROR( RegisterVariablePolicy( &Validatio= nPolicy.Header ) );

+  ValidationPolicy.Header.MaxSize =3D 30;

+  CopyMem( PolicyName, TwoWildcards, PolicyNameSize );

+  UT_ASSERT_NOT_EFI_ERROR( RegisterVariablePolicy( &Validatio= nPolicy.Header ) );

+  ValidationPolicy.Header.MaxSize =3D 20;

+  CopyMem( PolicyName, OneWildcard, PolicyNameSize );

+  UT_ASSERT_NOT_EFI_ERROR( RegisterVariablePolicy( &Validatio= nPolicy.Header ) );

+  ValidationPolicy.Header.MaxSize =3D 10;

+  CopyMem( PolicyName, NoWildcards, PolicyNameSize );

+  UT_ASSERT_NOT_EFI_ERROR( RegisterVariablePolicy( &Validatio= nPolicy.Header ) );

+

+  // Verify that variables only matching the namespace have the m= ost flexible policy.

+  PolicyCheck =3D ValidateSetVariable( L"ArbitraryName"= ,

+           &nbs= p;            &= nbsp;            &am= p;mTestGuid1,

+           &nbs= p;            &= nbsp;            VAR= IABLE_ATTRIBUTE_BS_RT_AT,

+           &nbs= p;            &= nbsp;            65,=

+           &nbs= p;            &= nbsp;            Dum= myData );

+  UT_ASSERT_TRUE( EFI_ERROR( PolicyCheck ) );

+  PolicyCheck =3D ValidateSetVariable( L"ArbitraryName"= ,

+           &nbs= p;            &= nbsp;            &am= p;mTestGuid1,

+           &nbs= p;            &= nbsp;            VAR= IABLE_ATTRIBUTE_BS_RT_AT,

+           &nbs= p;            &= nbsp;            55,=

+           &nbs= p;            &= nbsp;            Dum= myData );

+  UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );

+

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

+  PolicyCheck =3D ValidateSetVariable( L"Wild77Card77Placeho= lder",

+           &nbs= p;            &= nbsp;            &am= p;mTestGuid1,

+           &nbs= p;            &= nbsp;            VAR= IABLE_ATTRIBUTE_BS_RT_AT,

+           &nbs= p;            &= nbsp;            55,=

+           &nbs= p;            &= nbsp;            Dum= myData );

+  UT_ASSERT_TRUE( EFI_ERROR( PolicyCheck ) );

+  PolicyCheck =3D ValidateSetVariable( L"Wild77Card77Placeho= lder",

+           &nbs= p;            &= nbsp;            &am= p;mTestGuid1,

+           &nbs= p;            &= nbsp;            VAR= IABLE_ATTRIBUTE_BS_RT_AT,

+           &nbs= p;            &= nbsp;            45,=

+           &nbs= p;            &= nbsp;            Dum= myData );

+  UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );

+

+  PolicyCheck =3D ValidateSetVariable( L"Wild77Card74Placeho= lder",

+           &nbs= p;            &= nbsp;            &am= p;mTestGuid1,

+           &nbs= p;            &= nbsp;            VAR= IABLE_ATTRIBUTE_BS_RT_AT,

+           &nbs= p;            &= nbsp;            45,=

+           &nbs= p;            &= nbsp;            Dum= myData );

+  UT_ASSERT_TRUE( EFI_ERROR( PolicyCheck ) );

+  PolicyCheck =3D ValidateSetVariable( L"Wild77Card74Placeho= lder",

+           &nbs= p;            &= nbsp;            &am= p;mTestGuid1,

+           &nbs= p;            &= nbsp;            VAR= IABLE_ATTRIBUTE_BS_RT_AT,

+           &nbs= p;            &= nbsp;            35,=

+           &nbs= p;            &= nbsp;            Dum= myData );

+  UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );

+

+  PolicyCheck =3D ValidateSetVariable( L"Wild77Card34Placeho= lder",

+           &nbs= p;            &= nbsp;            &am= p;mTestGuid1,

+           &nbs= p;            &= nbsp;            VAR= IABLE_ATTRIBUTE_BS_RT_AT,

+           &nbs= p;            &= nbsp;            35,=

+           &nbs= p;            &= nbsp;            Dum= myData );

+  UT_ASSERT_TRUE( EFI_ERROR( PolicyCheck ) );

+  PolicyCheck =3D ValidateSetVariable( L"Wild77Card34Placeho= lder",

+           &nbs= p;            &= nbsp;            &am= p;mTestGuid1,

+           &nbs= p;            &= nbsp;            VAR= IABLE_ATTRIBUTE_BS_RT_AT,

+           &nbs= p;            &= nbsp;            25,=

+           &nbs= p;            &= nbsp;            Dum= myData );

+  UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );

+

+  PolicyCheck =3D ValidateSetVariable( L"Wild72Card34Placeho= lder",

+           &nbs= p;            &= nbsp;            &am= p;mTestGuid1,

+           &nbs= p;            &= nbsp;            VAR= IABLE_ATTRIBUTE_BS_RT_AT,

+           &nbs= p;            &= nbsp;            25,=

+           &nbs= p;            &= nbsp;            Dum= myData );

+  UT_ASSERT_TRUE( EFI_ERROR( PolicyCheck ) );

+  PolicyCheck =3D ValidateSetVariable( L"Wild72Card34Placeho= lder",

+           &nbs= p;            &= nbsp;            &am= p;mTestGuid1,

+           &nbs= p;            &= nbsp;            VAR= IABLE_ATTRIBUTE_BS_RT_AT,

+           &nbs= p;            &= nbsp;            15,=

+           &nbs= p;            &= nbsp;            Dum= myData );

+  UT_ASSERT_NOT_EFI_ERROR( PolicyCheck );

+

+  PolicyCheck =3D ValidateSetVariable( L"Wild12Card34Placeho= lder",

+           &nbs= p;            &= nbsp;            &am= p;mTestGuid1,

+           &nbs= p;            &= nbsp;            VAR= IABLE_ATTRIBUTE_BS_RT_AT,

+           &nbs= p;            &= nbsp;            15,=

+           &nbs= p;            &= nbsp;            Dum= myData );

+  UT_ASSERT_TRUE( EFI_ERROR( PolicyCheck ) );

+  PolicyCheck =3D ValidateSetVariable( L"Wild12Card34Placeho= lder",

+           &nbs= p;            &= nbsp;            &am= p;mTestGuid1,

+           &nbs= p;            &= nbsp;            VAR= IABLE_ATTRIBUTE_BS_RT_AT,

+           &nbs= p;            &= nbsp;            5,<= br>
+           &nbs= p;            &= nbsp;            Dum= myData );

+  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) + siz= eof(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( &TestPol= icy.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) + siz= eof(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.<= br>
+  UT_ASSERT_TRUE( IsVariablePolicyEnabled() );

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

+  UT_ASSERT_NOT_EFI_ERROR( RegisterVariablePolicy( &TestPolic= y.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,

+           &nbs= p;            &= nbsp;           &mTes= tGuid1,

+           &nbs= p;            &= nbsp;           VARIABLE_= ATTRIBUTE_NV_BS,

+           &nbs= p;            &= nbsp;           sizeof(Du= mmyData),

+           &nbs= p;            &= nbsp;           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.<= br>
+  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) + siz= eof(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.<= br>
+  UT_ASSERT_TRUE( IsVariablePolicyEnabled() );

+  // Disable the policy enforcement.

+  UT_ASSERT_NOT_EFI_ERROR( DisableVariablePolicy() );

+

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

+  PolicyCheck =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.<= br>
+  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) + siz= eof(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_I= NVALID_PARAMETER );

+  DumpSize =3D 10;

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

+

+  // Now for the actual test case.

+

+  // Allocate a buffer to hold the output.

+  BufferSize =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, &D= umpSize ) );

+  UT_ASSERT_EQUAL( DumpSize, 0 );

+

+  // Now, set a new policy.

+  UT_ASSERT_NOT_EFI_ERROR( RegisterVariablePolicy( &TestPolic= y.Header ) );

+

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

+  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, &D= umpSize ) );

+  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) + siz= eof(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) + siz= eof(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( &TestPolic= y.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, &D= umpSize ) );

+  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 dum= ped.

+  UT_ASSERT_NOT_EFI_ERROR( RegisterVariablePolicy( &TestPolic= y2.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, &D= umpSize ) );

+

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

+  UT_ASSERT_MEM_EQUAL( DumpBuffer, &TestPolicy, TestPolicy.He= ader.Size );

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

+           &nbs= p;            &T= estPolicy2,

+           &nbs= p;            TestPo= licy2.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 exe= cuted successfully.

+  @retval other        &n= bsp;  Some error occured when executing this entry point.

+

+**/

+int

+main (

+  )

+{

+  EFI_STATUS         = ;         Status;

+  UNIT_TEST_FRAMEWORK_HANDLE  Framework =3D NULL;

+  UNIT_TEST_SUITE_HANDLE      ArchTests;=

+  UNIT_TEST_SUITE_HANDLE      PolicyTest= s;

+  UNIT_TEST_SUITE_HANDLE      UtilityTes= ts;

+#ifdef INTERNAL_UNIT_TEST

+  UNIT_TEST_SUITE_HANDLE      InternalTe= sts;

+#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_NAM= E, gEfiCallerBaseName, UNIT_TEST_VERSION );

+  if (EFI_ERROR( Status ))

+  {

+    DEBUG((DEBUG_ERROR, "Failed in InitUnitTestFra= mework. Status =3D %r\n", Status));

+    goto EXIT;

+  }

+

+

+  //

+  // Add all test suites and tests.

+  //

+  Status =3D CreateUnitTestSuite( &ArchTests, Framework, &quo= t;Variable Policy Architectural Tests", "VarPolicy.Arch", NU= LL, NULL );

+  if (EFI_ERROR( Status ))

+  {

+    DEBUG((DEBUG_ERROR, "Failed in CreateUnitTestS= uite for ArchTests\n"));

+    Status =3D EFI_OUT_OF_RESOURCES;

+    goto EXIT;

+  }

+  AddTestCase( ArchTests,

+           &nbs= p;    "Deinitialization should fail if not previously i= nitialized", "VarPolicy.Arch.OnlyDeinit",

+           &nbs= p;    ShouldFailDeinitWithoutInit, NULL, NULL, NULL );

+  AddTestCase( ArchTests,

+           &nbs= p;    "Initialization followed by deinitialization shou= ld succeed", "VarPolicy.Arch.InitDeinit",

+           &nbs= p;    ShouldBeAbleToInitAndDeinitTheLibrary, NULL, NULL, NUL= L );

+  AddTestCase( ArchTests,

+           &nbs= p;    "The initialization function fail if called twice= without a deinit", "VarPolicy.Arch.InitTwice",

+           &nbs= p;    ShouldNotBeAbleToInitializeTheLibraryTwice, NULL, LibC= leanup, NULL );

+  AddTestCase( ArchTests,

+           &nbs= p;    "API functions should be unavailable until librar= y is initialized", "VarPolicy.Arch.UninitApiOff",

+           &nbs= p;    ApiCommandsShouldNotRespondIfLibIsUninitialized, NULL,= LibCleanup, NULL );

+

+#ifdef INTERNAL_UNIT_TEST

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

+  if (EFI_ERROR( Status ))

+  {

+    DEBUG((DEBUG_ERROR, "Failed in CreateUnitTestS= uite for InternalTests\n"));

+    Status =3D EFI_OUT_OF_RESOURCES;

+    goto EXIT;

+  }

+  AddTestCase( InternalTests,

+           &nbs= p;    "Policy matching should use name and GUID", = "VarPolicy.Internal.NameGuid",

+           &nbs= p;    PoliciesShouldMatchByNameAndGuid, LibInitMocked, LibCl= eanup, NULL );

+  AddTestCase( InternalTests,

+           &nbs= p;    "# sign wildcards should match digits", &quo= t;VarPolicy.Internal.WildDigits",

+           &nbs= p;    WildcardPoliciesShouldMatchDigits, LibInitMocked, LibC= leanup, NULL );

+  AddTestCase( InternalTests,

+           &nbs= p;    "Digit wildcards should check edge cases", &= quot;VarPolicy.Internal.WildDigitsAdvanced",

+           &nbs= p;    WildcardPoliciesShouldMatchDigitsAdvanced, LibInitMock= ed, LibCleanup, NULL );

+  AddTestCase( InternalTests,

+           &nbs= p;    "Empty names should match an entire namespace&quo= t;, "VarPolicy.Internal.WildNamespace",

+           &nbs= p;    WildcardPoliciesShouldMatchNamespaces, LibInitMocked, = LibCleanup, NULL );

+  AddTestCase( InternalTests,

+           &nbs= p;    "Match priority should weight correctly based on = wildcards", "VarPolicy.Internal.Priorities",

+           &nbs= p;    MatchPrioritiesShouldFollowRules, LibInitMocked, LibCl= eanup, NULL );

+#endif // INTERNAL_UNIT_TEST

+

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

+  if (EFI_ERROR( Status ))

+  {

+    DEBUG((DEBUG_ERROR, "Failed in CreateUnitTestS= uite for PolicyTests\n"));

+    Status =3D EFI_OUT_OF_RESOURCES;

+    goto EXIT;

+  }

+  AddTestCase( PolicyTests,

+           &nbs= p;    "RegisterShouldAllowNamespaceWildcards", &qu= ot;VarPolicy.Policy.AllowNamespace",

+           &nbs= p;    RegisterShouldAllowNamespaceWildcards, LibInitMocked, = LibCleanup, NULL );

+  AddTestCase( PolicyTests,

+           &nbs= p;    "RegisterShouldAllowStateVarsForNamespaces",= "VarPolicy.Policy.AllowStateNamespace",

+           &nbs= p;    RegisterShouldAllowStateVarsForNamespaces, LibInitMock= ed, LibCleanup, NULL );

+  AddTestCase( PolicyTests,

+           &nbs= p;    "RegisterShouldRejectNullPointers", "Va= rPolicy.Policy.NullPointers",

+           &nbs= p;    RegisterShouldRejectNullPointers, LibInitMocked, LibCl= eanup, NULL );

+  AddTestCase( PolicyTests,

+           &nbs= p;    "RegisterShouldRejectBadRevisions", "Va= rPolicy.Policy.BadRevisions",

+           &nbs= p;    RegisterShouldRejectBadRevisions, LibInitMocked, LibCl= eanup, NULL );

+  AddTestCase( PolicyTests,

+           &nbs= p;    "RegisterShouldRejectBadSizes", "VarPol= icy.Policy.BadSizes",

+           &nbs= p;    RegisterShouldRejectBadSizes, LibInitMocked, LibCleanu= p, NULL );

+  AddTestCase( PolicyTests,

+           &nbs= p;    "RegisterShouldRejectBadOffsets", "VarP= olicy.Policy.BadOffsets",

+           &nbs= p;    RegisterShouldRejectBadOffsets, LibInitMocked, LibClea= nup, NULL );

+  AddTestCase( PolicyTests,

+           &nbs= p;    "RegisterShouldRejectMissingStateStrings", &= quot;VarPolicy.Policy.MissingStateString",

+           &nbs= p;    RegisterShouldRejectMissingStateStrings, LibInitMocked= , LibCleanup, NULL );

+  AddTestCase( PolicyTests,

+           &nbs= p;    "RegisterShouldRejectStringsMissingNull", &q= uot;VarPolicy.Policy.MissingNull",

+           &nbs= p;    RegisterShouldRejectStringsMissingNull, LibInitMocked,= LibCleanup, NULL );

+  AddTestCase( PolicyTests,

+           &nbs= p;    "RegisterShouldRejectMalformedStrings", &quo= t;VarPolicy.Policy.MalformedStrings",

+           &nbs= p;    RegisterShouldRejectMalformedStrings, LibInitMocked, L= ibCleanup, NULL );

+  AddTestCase( PolicyTests,

+           &nbs= p;    "RegisterShouldRejectUnpackedPolicies", &quo= t;VarPolicy.Policy.PolicyPacking",

+           &nbs= p;    RegisterShouldRejectUnpackedPolicies, LibInitMocked, L= ibCleanup, NULL );

+  AddTestCase( PolicyTests,

+           &nbs= p;    "RegisterShouldRejectInvalidNameCharacters",= "VarPolicy.Policy.InvalidCharacters",

+           &nbs= p;    RegisterShouldRejectInvalidNameCharacters, LibInitMock= ed, LibCleanup, NULL );

+  AddTestCase( PolicyTests,

+           &nbs= p;    "RegisterShouldRejectBadPolicyConstraints", = "VarPolicy.Policy.BadConstraints",

+           &nbs= p;    RegisterShouldRejectBadPolicyConstraints, LibInitMocke= d, LibCleanup, NULL );

+  AddTestCase( PolicyTests,

+           &nbs= p;    "RegisterShouldRejectUnknownLockPolicies", &= quot;VarPolicy.Policy.BadLocks",

+           &nbs= p;    RegisterShouldRejectUnknownLockPolicies, LibInitMocked= , LibCleanup, NULL );

+  AddTestCase( PolicyTests,

+           &nbs= p;    "RegisterShouldRejectPolicesWithTooManyWildcards&= quot;, "VarPolicy.Policy.TooManyWildcards",

+           &nbs= p;    RegisterShouldRejectPolicesWithTooManyWildcards, LibIn= itMocked, LibCleanup, NULL );

+  AddTestCase( PolicyTests,

+           &nbs= p;    "RegisterShouldRejectDuplicatePolicies", &qu= ot;VarPolicy.Policy.DuplicatePolicies",

+           &nbs= p;    RegisterShouldRejectDuplicatePolicies, LibInitMocked, = LibCleanup, NULL );

+  AddTestCase( PolicyTests,

+           &nbs= p;    "Variables that exceed min or max sizes should be= rejected", "VarPolicy.Policy.MinMax",

+           &nbs= p;    MinAndMaxSizePoliciesShouldBeHonored, LibInitMocked, L= ibCleanup, NULL );

+  AddTestCase( PolicyTests,

+           &nbs= p;    "AttributeMustPoliciesShouldBeHonored", &quo= t;VarPolicy.Policy.AttrMust",

+           &nbs= p;    AttributeMustPoliciesShouldBeHonored, LibInitMocked, L= ibCleanup, NULL );

+  AddTestCase( PolicyTests,

+           &nbs= p;    "AttributeCantPoliciesShouldBeHonored", &quo= t;VarPolicy.Policy.AttrCant",

+           &nbs= p;    AttributeCantPoliciesShouldBeHonored, LibInitMocked, L= ibCleanup, NULL );

+  AddTestCase( PolicyTests,

+           &nbs= p;    "VariablesShouldBeDeletableRegardlessOfSize"= , "VarPolicy.Policy.DeleteIgnoreSize",

+           &nbs= p;    VariablesShouldBeDeletableRegardlessOfSize, LibInitMoc= ked, LibCleanup, NULL );

+  AddTestCase( PolicyTests,

+           &nbs= p;    "LockNowPoliciesShouldBeHonored", "VarP= olicy.Policy.VARIABLE_POLICY_TYPE_LOCK_NOW",

+           &nbs= p;    LockNowPoliciesShouldBeHonored, LibInitMocked, LibClea= nup, NULL );

+  AddTestCase( PolicyTests,

+           &nbs= p;    "LockOnCreatePoliciesShouldBeHonored", "= ;VarPolicy.Policy.VARIABLE_POLICY_TYPE_LOCK_ON_CREATE",

+           &nbs= p;    LockOnCreatePoliciesShouldBeHonored, LibInitMocked, Li= bCleanup, NULL );

+  AddTestCase( PolicyTests,

+           &nbs= p;    "LockOnStatePoliciesShouldBeHonored", "= VarPolicy.Policy.LockState",

+           &nbs= p;    LockOnStatePoliciesShouldBeHonored, LibInitMocked, Lib= Cleanup, NULL );

+  AddTestCase( PolicyTests,

+           &nbs= p;    "LockOnStatePoliciesShouldApplyToNamespaces"= , "VarPolicy.Policy.NamespaceLockState",

+           &nbs= p;    LockOnStatePoliciesShouldApplyToNamespaces, LibInitMoc= ked, LibCleanup, NULL );

+  AddTestCase( PolicyTests,

+           &nbs= p;    "LockOnStateShouldHandleErrorsGracefully", &= quot;VarPolicy.Policy.LockStateErrors",

+           &nbs= p;    LockOnStateShouldHandleErrorsGracefully, LibInitMocked= , LibCleanup, NULL );

+  AddTestCase( PolicyTests,

+           &nbs= p;    "BestMatchPriorityShouldBeObeyed", "Var= Policy.Policy.BestMatch",

+           &nbs= p;    BestMatchPriorityShouldBeObeyed, LibInitMocked, LibCle= anup, NULL );

+

+  Status =3D CreateUnitTestSuite( &UtilityTests, Framework, &= quot;Variable Policy Utility Tests", "VarPolicy.Utility", NU= LL, NULL );

+  if (EFI_ERROR( Status ))

+  {

+    DEBUG((DEBUG_ERROR, "Failed in CreateUnitTestS= uite for UtilityTests\n"));

+    Status =3D EFI_OUT_OF_RESOURCES;

+    goto EXIT;

+  }

+  AddTestCase( UtilityTests,

+           &nbs= p;    "API commands that change state should not respon= d after interface is locked", "VarPolicy.Utility.InterfaceLock&qu= ot;,

+           &nbs= p;    ShouldBeAbleToLockInterface, LibInitMocked, LibCleanup= , NULL );

+  AddTestCase( UtilityTests,

+           &nbs= p;    "All policies should pass once enforcement is dis= abled", "VarPolicy.Utility.DisableEnforcement",

+           &nbs= p;    ShouldBeAbleToDisablePolicyEnforcement, LibInitMocked,= LibCleanup, NULL );

+  AddTestCase( UtilityTests,

+           &nbs= p;    "Disabling enforcement twice should produce an er= ror", "VarPolicy.Utility.DisableEnforcementTwice",

+           &nbs= p;    ShouldNotBeAbleToDisablePoliciesTwice, LibInitMocked, = LibCleanup, NULL );

+  AddTestCase( UtilityTests,

+           &nbs= p;    "ShouldBeAbleToAddNewPoliciesAfterDisabled",= "VarPolicy.Utility.AddAfterDisable",

+           &nbs= p;    ShouldBeAbleToAddNewPoliciesAfterDisabled, LibInitMock= ed, LibCleanup, NULL );

+  AddTestCase( UtilityTests,

+           &nbs= p;    "ShouldBeAbleToLockAfterDisabled", "Var= Policy.Utility.LockAfterDisable",

+           &nbs= p;    ShouldBeAbleToLockAfterDisabled, LibInitMocked, LibCle= anup, NULL );

+  AddTestCase( UtilityTests,

+           &nbs= p;    "Should be able to dump the policy table", &= quot;VarPolicy.Utility.DumpTable",

+           &nbs= p;    ShouldBeAbleToDumpThePolicyTable, LibInitMocked, LibCl= eanup, NULL );

+  AddTestCase( UtilityTests,

+           &nbs= p;    "ShouldBeAbleToDumpThePolicyTableAfterDisabled&qu= ot;, "VarPolicy.Utility.DumpTableAfterDisable",

+           &nbs= p;    ShouldBeAbleToDumpThePolicyTableAfterDisabled, LibInit= Mocked, 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 <Protocol/VariablePolicy.h>

+

+/**

+  This API function validates and registers a new policy with

+  the policy enforcement engine.

+

+  @param[in]  NewPolicy     Pointer to t= he incoming policy structure.

+

+  @retval     EFI_SUCCESS

+  @retval     EFI_INVALID_PARAMETER &nbs= p; NewPolicy is NULL or is internally inconsistent.

+  @retval     EFI_ALREADY_STARTED  =    An identical matching policy already exists.

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

+  @retval     EFI_UNSUPPORTED  &nbs= p;      Policy enforcement has been disabled. No r= eason to add more policies.

+  @retval     EFI_ABORTED   &n= bsp;         A calculation error ha= s prevented this function from completing.

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

+  @retval     EFI_NOT_READY   =         Library has not yet been initial= ized.

+

+**/

+EFI_STATUS

+EFIAPI

+RegisterVariablePolicy (

+  IN CONST VARIABLE_POLICY_ENTRY    *NewPolicy

+  );

+

+

+/**

+  This API function checks to see whether the parameters to SetVa= riable would

+  be allowed according to the current variable policies.

+

+  @param[in]  VariableName     &nbs= p; Same as EFI_SET_VARIABLE.

+  @param[in]  VendorGuid      =    Same as EFI_SET_VARIABLE.

+  @param[in]  Attributes      =    Same as EFI_SET_VARIABLE.

+  @param[in]  DataSize      &n= bsp;    Same as EFI_SET_VARIABLE.

+  @param[in]  Data       =         Same as EFI_SET_VARIABLE.

+

+  @retval     EFI_SUCCESS   &n= bsp;         A matching policy allo= ws this update.

+  @retval     EFI_SUCCESS   &n= bsp;         There are currently no= policies that restrict this update.

+  @retval     EFI_SUCCESS   &n= bsp;         The protections have b= een disable until the next reboot.

+  @retval     EFI_WRITE_PROTECTED  =    Variable is currently locked.

+  @retval     EFI_INVALID_PARAMETER &nbs= p; Attributes or size are invalid.

+  @retval     EFI_ABORTED   &n= bsp;         A lock policy exists, = but an error prevented evaluation.

+  @retval     EFI_NOT_READY   =         Library has not been initialized= .

+

+**/

+EFI_STATUS

+EFIAPI

+ValidateSetVariable (

+  IN  CHAR16        =             &nb= sp;  *VariableName,

+  IN  EFI_GUID       &nbs= p;             = *VendorGuid,

+  IN  UINT32        =             &nb= sp;  Attributes,

+  IN  UINTN        &= nbsp;           &nbs= p;   DataSize,

+  IN  VOID        &n= bsp;            = ;    *Data

+  );

+

+

+/**

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

+  already been called once, will return EFI_ALREADY_STARTED.

+

+  @retval     EFI_SUCCESS

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

+  @retval     EFI_WRITE_PROTECTED  = Interface has been locked until reboot.

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

+  @retval     EFI_NOT_READY   Libra= ry has not yet been initialized.

+

+**/

+EFI_STATUS

+EFIAPI

+DisableVariablePolicy (

+  VOID

+  );

+

+

+/**

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

+

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

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

+

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

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

+           &nbs= p;            &= nbsp; of the data returned.

+

+  @retval     EFI_SUCCESS   &n= bsp;         Policy data is in the = output buffer and Size has been updated.

+  @retval     EFI_INVALID_PARAMETER &nbs= p; Size is NULL, or Size is non-zero and Policy is NULL.

+  @retval     EFI_BUFFER_TOO_SMALL  = ;  Size is insufficient to hold policy. Size updated with required siz= e.

+  @retval     EFI_NOT_READY   =         Library has not yet been initial= ized.

+

+**/

+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    &n= bsp;    Library has not yet been initialized.

+

+**/

+BOOLEAN

+EFIAPI

+IsVariablePolicyEnabled (

+  VOID

+  );

+

+

+/**

+  This API function locks the interface so that no more policy up= dates

+  can be performed or changes made to the enforcement until the n= ext boot.

+

+  @retval     EFI_SUCCESS

+  @retval     EFI_NOT_READY   Libra= ry has not yet been initialized.

+

+**/

+EFI_STATUS

+EFIAPI

+LockVariablePolicy (

+  VOID

+  );

+

+

+/**

+  This API function returns whether or not the policy interface i= s locked

+  for the remainder of the boot.

+

+  @retval     TRUE

+  @retval     FALSE

+  @retval     FALSE    &n= bsp;    Library has not yet been initialized.

+

+**/

+BOOLEAN

+EFIAPI

+IsVariablePolicyInterfaceLocked (

+  VOID

+  );

+

+

+/**

+  This helper function initializes the library and sets

+  up any required internal structures or handlers.

+

+  Also registers the internal pointer for the GetVariable helper.=

+

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

+           &nbs= p;      check policy criteria that involve the exi= stence of other variables.

+

+  @retval     EFI_SUCCESS

+  @retval     EFI_ALREADY_STARTED  = The initialize function has been called more than once without a call to
+           &nbs= p;            &= nbsp;           deinitial= ize.

+

+**/

+EFI_STATUS

+EFIAPI

+InitVariablePolicyLib (

+  IN  EFI_GET_VARIABLE    GetVariableHelper
+  );

+

+

+/**

+  This helper function returns whether or not the library is curr= ently initialized.

+

+  @retval     TRUE

+  @retval     FALSE

+

+**/

+BOOLEAN

+EFIAPI

+IsVariablePolicyLibInitialized (

+  VOID

+  );

+

+

+/**

+  This helper function tears down  the library.

+

+  Should generally only be used for test harnesses.

+

+  @retval     EFI_SUCCESS

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

+

+**/

+EFI_STATUS

+EFIAPI

+DeinitVariablePolicyLib (

+  VOID

+  );

+

+

+#endif // _VARIABLE_POLICY_LIB_H_

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

+# Business logic for Variable Policy enforcement.

+#

+##

+# Copyright (c) Microsoft Corporation.

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

+##

+

+

+[Defines]

+  INF_VERSION         =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 VariableP= olicyLib|DXE_DRIVER DXE_SMM_DRIVER MM_STANDALONE

+

+#

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

+#

+#  VALID_ARCHITECTURES       &= nbsp;   =3D ANY

+#

+

+

+[Sources]

+  VariablePolicyLib.c

+  VariablePolicyExtraInitNull.c

+

+

+[Packages]

+  MdePkg/MdePkg.dec

+  MdeModulePkg/MdeModulePkg.dec

+

+

+[LibraryClasses]

+  DebugLib

+  BaseMemoryLib

+  MemoryAllocationLib

+  SafeIntLib

+  PcdLib

+

+

+[Pcd]

+  gEfiMdeModulePkgTokenSpaceGuid.PcdAllowVariablePolicyEnforcemen= tDisable     ## 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       &= nbsp;     #language en-US "Library containing the = business logic for the VariablePolicy engine"

+

+#string STR_MODULE_DESCRIPTION      &nbs= p;   #language en-US "Library containing 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/VariablePolicyLibR= untimeDxe.inf
@@ -0,0 +1,51 @@
+## @file VariablePolicyLibRuntimeDxe.inf

+# Business logic for Variable Policy enforcement.

+# This instance is specifically for RuntimeDxe and contains

+# extra routines to register for VirtualAddressChangeEvents.

+#

+# Copyright (c) Microsoft Corporation.

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

+##

+

+

+[Defines]

+  INF_VERSION         =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 VariableP= olicyLib|DXE_RUNTIME_DRIVER

+

+#

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

+#

+#  VALID_ARCHITECTURES       &= nbsp;   =3D ANY

+#

+

+

+[Sources]

+  VariablePolicyLib.c

+  VariablePolicyExtraInitRuntimeDxe.c

+

+

+[Packages]

+  MdePkg/MdePkg.dec

+  MdeModulePkg/MdeModulePkg.dec

+

+

+[LibraryClasses]

+  DebugLib

+  BaseMemoryLib

+  MemoryAllocationLib

+  SafeIntLib

+  UefiBootServicesTableLib

+  UefiRuntimeServicesTableLib

+  PcdLib

+

+

+[Pcd]

+  gEfiMdeModulePkgTokenSpaceGuid.PcdAllowVariablePolicyEnforcemen= tDisable     ## 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/VariablePolicyUnit= Test/VariablePolicyUnitTest.inf
@@ -0,0 +1,40 @@
+## @file VariablePolicyUnitTest.inf

+# UnitTest for...

+# Business logic for Variable Policy enforcement.

+#

+# Copyright (c) Microsoft Corporation.

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

+##

+

+

+[Defines]

+  INF_VERSION        &nbs= p;           =3D 0x000100= 06

+  BASE_NAME         =              = =3D VariablePolicyUnitTest

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

+  MODULE_TYPE        &nbs= p;           =3D HOST_APP= LICATION

+  VERSION_STRING        &= nbsp;        =3D 1.0

+

+#

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

+#

+#  VALID_ARCHITECTURES       &= nbsp;   =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<= br> index 2e0461b87c32..31339741b840 100644
--- a/MdeModulePkg/MdeModulePkg.dec
+++ b/MdeModulePkg/MdeModulePkg.dec
@@ -31,6 +31,9 @@ [LibraryClasses]
   ##  @libraryclass  Defines a set of methods to reset= whole system.

   ResetSystemLib|Include/Library/ResetSystemLib.h

 

+  ##  @libraryclass  Business logic for storing and tes= ting variable policies

+  VariablePolicyLib|Include/Library/VariablePolicyLib.h

+

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

   ResetUtilityLib|Include/Library/ResetUtilityLib.h

 

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

 # (C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR&= gt;

 # Copyright (c) 2007 - 2019, Intel Corporation. All rights reserved.&= lt;BR>

+# Copyright (c) Microsoft Corporation.

 #

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

 #

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

   DxeServicesTableLib|MdePkg/Library/DxeServicesTableLib/DxeServ= icesTableLib.inf

   UefiBootManagerLib|MdeModulePkg/Library/UefiBootManagerLib/Uef= iBootManagerLib.inf

+  VariablePolicyLib|MdeModulePkg/Library/VariablePolicyLib/Variab= lePolicyLib.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/DxeRuntimeCap= suleLib.inf

+  VariablePolicyLib|MdeModulePkg/Library/VariablePolicyLib/Variab= lePolicyLibRuntimeDxe.inf

 

 [LibraryClasses.common.SMM_CORE]

   HobLib|MdePkg/Library/DxeHobLib/DxeHobLib.inf

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

   MdeModulePkg/Library/TpmMeasurementLibNull/TpmMeasurementLibNu= ll.inf

   MdeModulePkg/Library/AuthVariableLibNull/AuthVariableLibNull.i= nf

+  MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.inf
+  MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLibRuntime= Dxe.inf

   MdeModulePkg/Library/VarCheckLib/VarCheckLib.inf

   MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLib.inf

   MdeModulePkg/Library/VarCheckPcdLib/VarCheckPcdLib.inf

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

 !include UnitTestFrameworkPkg/UnitTestFrameworkPkgHost.dsc.inc

 

+[LibraryClasses]

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

+

 [Components]

   MdeModulePkg/Library/DxeResetSystemLib/UnitTest/MockUefiRuntim= eServicesTableLib.inf

 

   #

   # Build MdeModulePkg HOST_APPLICATION Tests

   #

+  MdeModulePkg/Library/VariablePolicyLib/VariablePolicyUnitTest/V= ariablePolicyUnitTest.inf {

+    <LibraryClasses>

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

+

+    <PcdsFixedAtBuild>

+      gEfiMdeModulePkgTokenSpaceGuid.PcdAllow= VariablePolicyEnforcementDisable|TRUE

+  }

+

   MdeModulePkg/Library/DxeResetSystemLib/UnitTest/DxeResetSystem= LibUnitTestHost.inf {

     <LibraryClasses>

       ResetSystemLib|MdeModulePkg/Library/Dx= eResetSystemLib/DxeResetSystemLib.inf

--
2.26.2.windows.1.8.g01c50adf56.20200515075929


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

View/Reply Online (#60643): https://nam06.safelinks.protection.outlook.com/?url=3Dhttps%3A%2F%2Fedk2.gr= oups.io%2Fg%2Fdevel%2Fmessage%2F60643&amp;data=3D02%7C01%7Cbret.barkele= w%40microsoft.com%7C5f525d9b2e954b4b474d08d807a3da45%7C72f988bf86f141af91ab= 2d7cd011db47%7C1%7C0%7C637267747622315664&amp;sdata=3DNShPJaGWqn%2F4krA= ZWL9B1QUdajPc1uWC3%2BZPd3wcz4E%3D&amp;reserved=3D0
Mute This Topic: https://nam06.safelinks.protection.outlook.com/?url=3Dhttps%3A%2F%2Fgroups.= io%2Fmt%2F74646432%2F1852292&amp;data=3D02%7C01%7Cbret.barkelew%40micro= soft.com%7C5f525d9b2e954b4b474d08d807a3da45%7C72f988bf86f141af91ab2d7cd011d= b47%7C1%7C0%7C637267747622315664&amp;sdata=3Daq1LOygDYZbMpRGiibZCOCfMPf= fZtEFQLR8K4LKmUYk%3D&amp;reserved=3D0
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://nam06.safelinks.protection.outlook.com/?url=3Dhttps%3A%2F%2Fedk2.gr= oups.io%2Fg%2Fdevel%2Funsub&amp;data=3D02%7C01%7Cbret.barkelew%40micros= oft.com%7C5f525d9b2e954b4b474d08d807a3da45%7C72f988bf86f141af91ab2d7cd011db= 47%7C1%7C0%7C637267747622315664&amp;sdata=3DCGyCvVr0DX3Z%2F%2BKh43OWSOb= WZZG58YFT6f94FhOY1LA%3D&amp;reserved=3D0  [bret.barkelew@microsoft.com]
-=3D-=3D-=3D-=3D-=3D-=3D

--_000_CY4PR21MB074358CF8FE24CBA96894524EF9A0CY4PR21MB0743namp_--