]> git.proxmox.com Git - mirror_edk2.git/commitdiff
MdeModulePkg: Define the VariablePolicyLib
authorBret Barkelew <brbarkel@microsoft.com>
Mon, 9 Nov 2020 06:45:11 +0000 (14:45 +0800)
committermergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
Tue, 17 Nov 2020 01:03:43 +0000 (01:03 +0000)
https://bugzilla.tianocore.org/show_bug.cgi?id=2522

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>
Reviewed-by: Dandan Bi <dandan.bi@intel.com>
Acked-by: Jian J Wang <jian.j.wang@intel.com>
MdeModulePkg/Include/Library/VariablePolicyLib.h [new file with mode: 0644]
MdeModulePkg/Library/VariablePolicyLib/ReadMe.md [new file with mode: 0644]
MdeModulePkg/Library/VariablePolicyLib/VariablePolicyExtraInitNull.c [new file with mode: 0644]
MdeModulePkg/Library/VariablePolicyLib/VariablePolicyExtraInitRuntimeDxe.c [new file with mode: 0644]
MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.c [new file with mode: 0644]
MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.inf [new file with mode: 0644]
MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.uni [new file with mode: 0644]
MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLibRuntimeDxe.inf [new file with mode: 0644]
MdeModulePkg/MdeModulePkg.ci.yaml
MdeModulePkg/MdeModulePkg.dec
MdeModulePkg/MdeModulePkg.dsc

diff --git a/MdeModulePkg/Include/Library/VariablePolicyLib.h b/MdeModulePkg/Include/Library/VariablePolicyLib.h
new file mode 100644 (file)
index 0000000..efd1840
--- /dev/null
@@ -0,0 +1,207 @@
+/** @file -- VariablePolicyLib.h\r
+Business logic for Variable Policy enforcement.\r
+\r
+Copyright (c) Microsoft Corporation.\r
+SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+\r
+#ifndef _VARIABLE_POLICY_LIB_H_\r
+#define _VARIABLE_POLICY_LIB_H_\r
+\r
+#include <Protocol/VariablePolicy.h>\r
+\r
+/**\r
+  This API function validates and registers a new policy with\r
+  the policy enforcement engine.\r
+\r
+  @param[in]  NewPolicy     Pointer to the incoming policy structure.\r
+\r
+  @retval     EFI_SUCCESS\r
+  @retval     EFI_INVALID_PARAMETER   NewPolicy is NULL or is internally inconsistent.\r
+  @retval     EFI_ALREADY_STARTED     An identical matching policy already exists.\r
+  @retval     EFI_WRITE_PROTECTED     The interface has been locked until the next reboot.\r
+  @retval     EFI_UNSUPPORTED         Policy enforcement has been disabled. No reason to add more policies.\r
+  @retval     EFI_ABORTED             A calculation error has prevented this function from completing.\r
+  @retval     EFI_OUT_OF_RESOURCES    Cannot grow the table to hold any more policies.\r
+  @retval     EFI_NOT_READY           Library has not yet been initialized.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+RegisterVariablePolicy (\r
+  IN CONST VARIABLE_POLICY_ENTRY    *NewPolicy\r
+  );\r
+\r
+\r
+/**\r
+  This API function checks to see whether the parameters to SetVariable would\r
+  be allowed according to the current variable policies.\r
+\r
+  @param[in]  VariableName       Same as EFI_SET_VARIABLE.\r
+  @param[in]  VendorGuid         Same as EFI_SET_VARIABLE.\r
+  @param[in]  Attributes         Same as EFI_SET_VARIABLE.\r
+  @param[in]  DataSize           Same as EFI_SET_VARIABLE.\r
+  @param[in]  Data               Same as EFI_SET_VARIABLE.\r
+\r
+  @retval     EFI_SUCCESS             A matching policy allows this update.\r
+  @retval     EFI_SUCCESS             There are currently no policies that restrict this update.\r
+  @retval     EFI_SUCCESS             The protections have been disable until the next reboot.\r
+  @retval     EFI_WRITE_PROTECTED     Variable is currently locked.\r
+  @retval     EFI_INVALID_PARAMETER   Attributes or size are invalid.\r
+  @retval     EFI_ABORTED             A lock policy exists, but an error prevented evaluation.\r
+  @retval     EFI_NOT_READY           Library has not been initialized.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ValidateSetVariable (\r
+  IN  CHAR16                       *VariableName,\r
+  IN  EFI_GUID                     *VendorGuid,\r
+  IN  UINT32                       Attributes,\r
+  IN  UINTN                        DataSize,\r
+  IN  VOID                         *Data\r
+  );\r
+\r
+\r
+/**\r
+  This API function disables the variable policy enforcement. If it's\r
+  already been called once, will return EFI_ALREADY_STARTED.\r
+\r
+  @retval     EFI_SUCCESS\r
+  @retval     EFI_ALREADY_STARTED   Has already been called once this boot.\r
+  @retval     EFI_WRITE_PROTECTED   Interface has been locked until reboot.\r
+  @retval     EFI_WRITE_PROTECTED   Interface option is disabled by platform PCD.\r
+  @retval     EFI_NOT_READY   Library has not yet been initialized.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DisableVariablePolicy (\r
+  VOID\r
+  );\r
+\r
+\r
+/**\r
+  This API function will dump the entire contents of the variable policy table.\r
+\r
+  Similar to GetVariable, the first call can be made with a 0 size and it will return\r
+  the size of the buffer required to hold the entire table.\r
+\r
+  @param[out]     Policy  Pointer to the policy buffer. Can be NULL if Size is 0.\r
+  @param[in,out]  Size    On input, the size of the output buffer. On output, the size\r
+                          of the data returned.\r
+\r
+  @retval     EFI_SUCCESS             Policy data is in the output buffer and Size has been updated.\r
+  @retval     EFI_INVALID_PARAMETER   Size is NULL, or Size is non-zero and Policy is NULL.\r
+  @retval     EFI_BUFFER_TOO_SMALL    Size is insufficient to hold policy. Size updated with required size.\r
+  @retval     EFI_NOT_READY           Library has not yet been initialized.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DumpVariablePolicy (\r
+  OUT     UINT8         *Policy,\r
+  IN OUT  UINT32        *Size\r
+  );\r
+\r
+\r
+/**\r
+  This API function returns whether or not the policy engine is\r
+  currently being enforced.\r
+\r
+  @retval     TRUE\r
+  @retval     FALSE\r
+  @retval     FALSE         Library has not yet been initialized.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+IsVariablePolicyEnabled (\r
+  VOID\r
+  );\r
+\r
+\r
+/**\r
+  This API function locks the interface so that no more policy updates\r
+  can be performed or changes made to the enforcement until the next boot.\r
+\r
+  @retval     EFI_SUCCESS\r
+  @retval     EFI_NOT_READY   Library has not yet been initialized.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+LockVariablePolicy (\r
+  VOID\r
+  );\r
+\r
+\r
+/**\r
+  This API function returns whether or not the policy interface is locked\r
+  for the remainder of the boot.\r
+\r
+  @retval     TRUE\r
+  @retval     FALSE\r
+  @retval     FALSE         Library has not yet been initialized.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+IsVariablePolicyInterfaceLocked (\r
+  VOID\r
+  );\r
+\r
+\r
+/**\r
+  This helper function initializes the library and sets\r
+  up any required internal structures or handlers.\r
+\r
+  Also registers the internal pointer for the GetVariable helper.\r
+\r
+  @param[in]  GetVariableHelper A function pointer matching the EFI_GET_VARIABLE prototype that will be used to\r
+                  check policy criteria that involve the existence of other variables.\r
+\r
+  @retval     EFI_SUCCESS\r
+  @retval     EFI_ALREADY_STARTED   The initialize function has been called more than once without a call to\r
+                                    deinitialize.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+InitVariablePolicyLib (\r
+  IN  EFI_GET_VARIABLE    GetVariableHelper\r
+  );\r
+\r
+\r
+/**\r
+  This helper function returns whether or not the library is currently initialized.\r
+\r
+  @retval     TRUE\r
+  @retval     FALSE\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+IsVariablePolicyLibInitialized (\r
+  VOID\r
+  );\r
+\r
+\r
+/**\r
+  This helper function tears down  the library.\r
+\r
+  Should generally only be used for test harnesses.\r
+\r
+  @retval     EFI_SUCCESS\r
+  @retval     EFI_NOT_READY     Deinitialize was called without first calling initialize.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DeinitVariablePolicyLib (\r
+  VOID\r
+  );\r
+\r
+\r
+#endif // _VARIABLE_POLICY_LIB_H_\r
diff --git a/MdeModulePkg/Library/VariablePolicyLib/ReadMe.md b/MdeModulePkg/Library/VariablePolicyLib/ReadMe.md
new file mode 100644 (file)
index 0000000..c2f9850
--- /dev/null
@@ -0,0 +1,406 @@
+---\r
+title:      UEFI Variable Policy Whitepaper\r
+version:    1.0\r
+copyright:  Copyright (c) Microsoft Corporation.\r
+---\r
+\r
+# UEFI Variable Policy\r
+\r
+## Summary\r
+\r
+UEFI Variable Policy spec aims to describe the DXE protocol interface\r
+which allows enforcing certain rules on certain UEFI variables. The\r
+protocol allows communication with the Variable Policy Engine which\r
+performs the policy enforcement.\r
+\r
+The Variable Policy is comprised of a set of policy entries which\r
+describe, per UEFI variable (identified by namespace GUID and variable\r
+name) the following rules:\r
+\r
+-   Required variable attributes\r
+-   Prohibited variable attributes\r
+-   Minimum variable size\r
+-   Maximum variable size\r
+-   Locking:\r
+    -   Locking "immediately"\r
+    -   Locking on creation\r
+    -   Locking based on a state of another variable\r
+\r
+The spec assumes that the Variable Policy Engine runs in a trusted\r
+enclave, potentially off the main CPU that runs UEFI. For that reason,\r
+it is assumed that the Variable Policy Engine has no concept of UEFI\r
+events, and that the communication from the DXE driver to the trusted\r
+enclave is proprietary.\r
+\r
+At power-on, the Variable Policy Engine is:\r
+\r
+-   Enabled -- present policy entries are evaluated on variable access\r
+    calls.\r
+-   Unlocked -- new policy entries can be registered.\r
+\r
+Policy is expected to be clear on power-on. Policy is volatile and not\r
+preserved across system reset.\r
+\r
+## DXE Protocol\r
+\r
+```h\r
+typedef struct {\r
+  UINT64                        Revision;\r
+  DISABLE_VARIABLE_POLICY       DisableVariablePolicy;\r
+  IS_VARIABLE_POLICY_ENABLED    IsVariablePolicyEnabled;\r
+  REGISTER_VARIABLE_POLICY      RegisterVariablePolicy;\r
+  DUMP_VARIABLE_POLICY          DumpVariablePolicy;\r
+  LOCK_VARIABLE_POLICY          LockVariablePolicy;\r
+} _VARIABLE_POLICY_PROTOCOL;\r
+\r
+typedef _VARIABLE_POLICY_PROTOCOL VARIABLE_POLICY_PROTOCOL;\r
+\r
+extern EFI_GUID gVariablePolicyProtocolGuid;\r
+```\r
+\r
+```text\r
+## Include/Protocol/VariablePolicy.h\r
+  gVariablePolicyProtocolGuid = { 0x81D1675C, 0x86F6, 0x48DF, { 0xBD, 0x95, 0x9A, 0x6E, 0x4F, 0x09, 0x25, 0xC3 } }\r
+```\r
+\r
+### DisableVariablePolicy\r
+\r
+Function prototype:\r
+\r
+```c\r
+EFI_STATUS\r
+EFIAPI\r
+DisableVariablePolicy (\r
+  VOID\r
+  );\r
+```\r
+\r
+`DisableVariablePolicy` call disables the Variable Policy Engine, so\r
+that the present policy entries are no longer taken into account on\r
+variable access calls. This call effectively turns off the variable\r
+policy verification for this boot. This also disables UEFI\r
+Authenticated Variable protections including Secure Boot.\r
+`DisableVariablePolicy` can only be called once during boot. If called\r
+more than once, it will return `EFI_ALREADY_STARTED`. Note, this process\r
+is irreversible until the next system reset -- there is no\r
+"EnablePolicy" protocol function.\r
+\r
+_IMPORTANT NOTE:_ It is strongly recommended that VariablePolicy *NEVER*\r
+be disabled in "normal, production boot conditions". It is expected to always\r
+be enforced. The most likely reasons to disable are for Manufacturing and\r
+Refurbishing scenarios. If in doubt, leave the `gEfiMdeModulePkgTokenSpaceGuid.PcdAllowVariablePolicyEnforcementDisable`\r
+PCD set to `FALSE` and VariablePolicy will always be enabled.\r
+\r
+### IsVariablePolicyEnabled\r
+\r
+Function prototype:\r
+\r
+```c\r
+EFI_STATUS\r
+EFIAPI\r
+IsVariablePolicyEnabled (\r
+  OUT BOOLEAN   *State\r
+  );\r
+```\r
+\r
+`IsVariablePolicyEnabled` accepts a pointer to a Boolean in which it\r
+will store `TRUE` if Variable Policy Engine is enabled, or `FALSE` if\r
+Variable Policy Engine is disabled. The function returns `EFI_SUCCESS`.\r
+\r
+### RegisterVariablePolicy\r
+\r
+Function prototype:\r
+\r
+```c\r
+EFI_STATUS\r
+EFIAPI\r
+RegisterVariablePolicy (\r
+  IN CONST VARIABLE_POLICY_ENTRY  *PolicyEntry\r
+  );\r
+```\r
+\r
+`RegisterVariablePolicy` call accepts a pointer to a policy entry\r
+structure and returns the status of policy registration. If the\r
+Variable Policy Engine is not locked and the policy structures are\r
+valid, the function will return `EFI_SUCCESS`. If the Variable Policy\r
+Engine is locked, `RegisterVariablePolicy` call will return\r
+`EFI_WRITE_PROTECTED` and will not register the policy entry. Bulk\r
+registration is not supported at this time due to the requirements\r
+around error handling on each policy registration.\r
+\r
+Upon successful registration of a policy entry, Variable Policy Engine\r
+will then evaluate this entry on subsequent variable access calls (as\r
+long as Variable Policy Engine hasn't been disabled).\r
+\r
+### DumpVariablePolicy\r
+\r
+Function prototype:\r
+\r
+```c\r
+EFI_STATUS\r
+EFIAPI\r
+DumpVariablePolicy (\r
+  OUT     UINT8     *Policy,\r
+  IN OUT  UINT32    *Size\r
+  );\r
+```\r
+\r
+`DumpVariablePolicy` call accepts a pointer to a buffer and a pointer to\r
+the size of the buffer as parameters and returns the status of placing\r
+the policy into the buffer. On first call to `DumpVariablePolicy` one\r
+should pass `NULL` as the buffer and a pointer to 0 as the `Size` variable\r
+and `DumpVariablePolicy` will return `EFI_BUFFER_TOO_SMALL` and will\r
+populate the `Size` parameter with the size of the needed buffer to\r
+store the policy. This way, the caller can allocate the buffer of\r
+correct size and call `DumpVariablePolicy` again. The function will\r
+populate the buffer with policy and return `EFI_SUCCESS`.\r
+\r
+### LockVariablePolicy\r
+\r
+Function prototype:\r
+\r
+```c\r
+EFI_STATUS\r
+EFIAPI\r
+LockVariablePolicy (\r
+  VOID\r
+  );\r
+```\r
+\r
+`LockVariablePolicy` locks the Variable Policy Engine, i.e. prevents any\r
+new policy entries from getting registered in this boot\r
+(`RegisterVariablePolicy` calls will fail with `EFI_WRITE_PROTECTED`\r
+status code returned).\r
+\r
+## Policy Structure\r
+\r
+The structure below is meant for the DXE protocol calling interface,\r
+when communicating to the Variable Policy Engine, thus the pragma pack\r
+directive. How these policies are stored in memory is up to the\r
+implementation.\r
+\r
+```c\r
+#pragma pack(1)\r
+typedef struct {\r
+  UINT32    Version;\r
+  UINT16    Size;\r
+  UINT16    OffsetToName;\r
+  EFI_GUID  Namespace;\r
+  UINT32    MinSize;\r
+  UINT32    MaxSize;\r
+  UINT32    AttributesMustHave;\r
+  UINT32    AttributesCantHave;\r
+  UINT8     LockPolicyType;\r
+  UINT8     Reserved[3];\r
+  // UINT8  LockPolicy[]; // Variable Length Field\r
+  // CHAR16 Name[];       // Variable Length Field\r
+} VARIABLE_POLICY_ENTRY;\r
+```\r
+\r
+The struct `VARIABLE_POLICY_ENTRY` above describes the layout for a policy\r
+entry. The first element, `Size`, is the size of the policy entry, then\r
+followed by `OffsetToName` -- the number of bytes from the beginning of\r
+the struct to the name of the UEFI variable targeted by the policy\r
+entry. The name can contain wildcards to match more than one variable,\r
+more on this in the Wildcards section. The rest of the struct elements\r
+are self-explanatory.\r
+\r
+```cpp\r
+#define VARIABLE_POLICY_TYPE_NO_LOCK            0\r
+#define VARIABLE_POLICY_TYPE_LOCK_NOW           1\r
+#define VARIABLE_POLICY_TYPE_LOCK_ON_CREATE     2\r
+#define VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE  3\r
+```\r
+\r
+`LockPolicyType` can have the following values:\r
+\r
+-   `VARIABLE_POLICY_TYPE_NO_LOCK` -- means that no variable locking is performed. However,\r
+    the attribute and size constraints are still enforced. LockPolicy\r
+    field is size 0.\r
+-   `VARIABLE_POLICY_TYPE_LOCK_NOW` -- means that the variable starts being locked\r
+    immediately after policy entry registration. If the variable doesn't\r
+    exist at this point, being LockedNow means it cannot be created on\r
+    this boot. LockPolicy field is size 0.\r
+-   `VARIABLE_POLICY_TYPE_LOCK_ON_CREATE` -- means that the variable starts being locked\r
+    after it is created. This allows for variable creation and\r
+    protection after LockVariablePolicy() function has been called. The\r
+    LockPolicy field is size 0.\r
+-   `VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE` -- means that the Variable Policy Engine will\r
+    examine the state/contents of another variable to determine if the\r
+    variable referenced in the policy entry is locked.\r
+\r
+```c\r
+typedef struct {\r
+  EFI_GUID  Namespace;\r
+  UINT8     Value;\r
+  UINT8     Reserved;\r
+  // CHAR16 Name[];   // Variable Length Field\r
+} VARIABLE_LOCK_ON_VAR_STATE_POLICY;\r
+```\r
+\r
+If `LockPolicyType` is `VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE`, then the final element in the\r
+policy entry struct is of type `VARIABLE_LOCK_ON_VAR_STATE_POLICY`, which\r
+lists the namespace GUID, name (no wildcards here), and value of the\r
+variable which state determines the locking of the variable referenced\r
+in the policy entry. The "locking" variable must be 1 byte in terms of\r
+payload size. If the Referenced variable contents match the Value of the\r
+`VARIABLE_LOCK_ON_VAR_STATE_POLICY` structure, the lock will be considered\r
+active and the target variable will be locked. If the Reference variable\r
+does not exist (ie. returns `EFI_NOT_FOUND`), this policy will be\r
+considered inactive.\r
+\r
+## Variable Name Wildcards\r
+\r
+Two types of wildcards can be used in the UEFI variable name field in a\r
+policy entry:\r
+\r
+1.  If the Name is a zero-length array (easily checked by comparing\r
+    fields `Size` and `OffsetToName` -- if they're the same, then the\r
+    `Name` is zero-length), then all variables in the namespace specified\r
+    by the provided GUID are targeted by the policy entry.\r
+2.  Character "#" in the `Name` corresponds to one numeric character\r
+    (0-9, A-F, a-f). For example, string "Boot####" in the `Name`\r
+    field of the policy entry will make it so that the policy entry will\r
+    target variables named "Boot0001", "Boot0002", etc.\r
+\r
+Given the above two types of wildcards, one variable can be targeted by\r
+more than one policy entry, thus there is a need to establish the\r
+precedence rule: a more specific match is applied. When a variable\r
+access operation is performed, Variable Policy Engine should first check\r
+the variable being accessed against the policy entries without\r
+wildcards, then with 1 wildcard, then with 2 wildcards, etc., followed\r
+in the end by policy entries that match the whole namespace. One can\r
+still imagine a situation where two policy entries with the same number\r
+of wildcards match the same variable -- for example, policy entries with\r
+Names "Boot00##" and "Boot##01" will both match variable "Boot0001".\r
+Such situation can (and should) be avoided by designing mutually\r
+exclusive Name strings with wildcards, however, if it occurs, then the\r
+policy entry that was registered first will be used. After the most\r
+specific match is selected, all other policies are ignored.\r
+\r
+## Available Testing\r
+\r
+This functionality is current supported by two kinds of tests: there is a host-based\r
+unit test for the core business logic (this test accompanies the `VariablePolicyLib`\r
+implementation that lives in `MdeModulePkg/Library`) and there is a functional test\r
+for the protocol and its interfaces (this test lives in the `MdeModulePkg/Test/ShellTest`\r
+directory).\r
+\r
+### Host-Based Unit Test\r
+\r
+There is a test that can be run as part of the Host-Based Unit Testing\r
+infrastructure provided by EDK2 PyTools (documented elsewhere). It will test\r
+all internal guarantees and is where you will find test cases for most of the\r
+policy matching and security of the Variable Policy Engine.\r
+\r
+### Shell-Based Functional Test\r
+\r
+This test -- [Variable Policy Functional Unit Test](https://github.com/microsoft/mu_plus/tree/release/202005/UefiTestingPkg/FunctionalSystemTests/VarPolicyUnitTestApp) -- can be built as a\r
+UEFI Shell application and run to validate that the Variable Policy Engine\r
+is correctly installed and enforcing policies on the target system.\r
+\r
+NOTE: This test _must_ be run prior to calling `DisableVariablePolicy` for all\r
+test cases to pass. For this reason, it is recommended to run this on a test-built\r
+FW for complete results, and then again on a production-built FW for release\r
+results.\r
+\r
+## Use Cases\r
+\r
+The below examples are hypothetical scenarios based on real-world requirements\r
+that demonstrate how Variable Policies could be constructed to solve various\r
+problems.\r
+\r
+### UEFI Setup Variables (Example 1)\r
+\r
+Variables containing values of the setup options exposed via UEFI\r
+menu (setup variables). These would be locked based on a state of\r
+another variable, "ReadyToBoot", which would be set to 1 at the\r
+ReadyToBoot event. Thus, the policy for the setup variables would be\r
+of type `LockOnVarState`, with the "ReadyToBoot" listed as the name of\r
+the variable, appropriate GUID listed as the namespace, and 1 as\r
+value. Entry into the trusted UEFI menu app doesn't signal\r
+ReadyToBoot, but booting to any device does, and the setup variables\r
+are write-protected. The "ReadyToBoot" variable would need to be\r
+locked-on-create. *(THIS IS ESSENTIALLY LOCK ON EVENT, BUT SINCE THE\r
+POLICY ENGINE IS NOT IN THE UEFI ENVIRONMENT VARIABLES ARE USED)*\r
+\r
+For example, "AllowPXEBoot" variable locked by "ReadyToBoot" variable.\r
+\r
+(NOTE: In the below example, the emphasized fields ('Namespace', 'Value', and 'Name')\r
+are members of the `VARIABLE_LOCK_ON_VAR_STATE_POLICY` structure.)\r
+\r
+Size                  | ...\r
+----                  | ---\r
+OffsetToName          | ...\r
+NameSpace             | ...\r
+MinSize               | ...\r
+MaxSize               | ...\r
+AttributesMustHave    | ...\r
+AttributesCantHave    | ...\r
+LockPolicyType        | `VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE`\r
+_Namespace_           | ...\r
+_Value_               | 1\r
+_Name_                | "ReadyToBoot"\r
+//Name                | "AllowPXEBoot"\r
+\r
+### Manufacturing VPD (Example 2)\r
+\r
+Manufacturing Variable Provisioning Data (VPD) is stored in\r
+variables and is created while in Manufacturing (MFG) Mode. In MFG\r
+Mode Variable Policy Engine is disabled, thus these VPD variables\r
+can be created. These variables are locked with lock policy type\r
+`LockNow`, so that these variables can't be tampered with in Customer\r
+Mode. To overwrite or clear VPD, the device would need to MFG mode,\r
+which is standard practice for refurbishing/remanufacturing\r
+scenarios.\r
+\r
+Example: "DisplayPanelCalibration" variable...\r
+\r
+Size                  | ...\r
+----                  | ---\r
+OffsetToName          | ...\r
+NameSpace             | ...\r
+MinSize               | ...\r
+MaxSize               | ...\r
+AttributesMustHave    | ...\r
+AttributesCantHave    | ...\r
+LockPolicyType        | `VARIABLE_POLICY_TYPE_LOCK_NOW`\r
+// Name               | "DisplayPanelCalibration"\r
+\r
+### 3rd Party Calibration Data (Example 3)\r
+\r
+Bluetooth pre-pairing variables are locked-on-create because these\r
+get created by an OS application when Variable Policy is in effect.\r
+\r
+Example: "KeyboardBTPairing" variable\r
+\r
+Size                  | ...\r
+----                  | ---\r
+OffsetToName          | ...\r
+NameSpace             | ...\r
+MinSize               | ...\r
+MaxSize               | ...\r
+AttributesMustHave    | ...\r
+AttributesCantHave    | ...\r
+LockPolicyType        | `VARIABLE_POLICY_TYPE_LOCK_ON_CREATE`\r
+// Name               | "KeyboardBTPairing"\r
+\r
+### Software-based Variable Policy (Example 4)\r
+\r
+Example: "Boot####" variables (a name string with wildcards that\r
+will match variables "Boot0000" to "BootFFFF") locked by "LockBootOrder"\r
+variable.\r
+\r
+Size                  | ...\r
+----                  | ---\r
+OffsetToName          | ...\r
+NameSpace             | ...\r
+MinSize               | ...\r
+MaxSize               | ...\r
+AttributesMustHave    | ...\r
+AttributesCantHave    | ...\r
+LockPolicyType        | `VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE`\r
+_Namespace_           | ...\r
+_Value_               | 1\r
+_Name_                | "LockBootOrder"\r
+//Name                | "Boot####"\r
diff --git a/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyExtraInitNull.c b/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyExtraInitNull.c
new file mode 100644 (file)
index 0000000..ad2ee0b
--- /dev/null
@@ -0,0 +1,46 @@
+/** @file -- VariablePolicyExtraInitNull.c\r
+This file contains extra init and deinit routines that don't do anything\r
+extra.\r
+\r
+Copyright (c) Microsoft Corporation.\r
+SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+\r
+#include <Library/UefiRuntimeServicesTableLib.h>\r
+\r
+\r
+/**\r
+  An extra init hook that enables the RuntimeDxe library instance to\r
+  register VirtualAddress change callbacks. Among other things.\r
+\r
+  @retval     EFI_SUCCESS   Everything is good. Continue with init.\r
+  @retval     Others        Uh... don't continue.\r
+\r
+**/\r
+EFI_STATUS\r
+VariablePolicyExtraInit (\r
+  VOID\r
+  )\r
+{\r
+  // NULL implementation.\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  An extra deinit hook that enables the RuntimeDxe library instance to\r
+  register VirtualAddress change callbacks. Among other things.\r
+\r
+  @retval     EFI_SUCCESS   Everything is good. Continue with deinit.\r
+  @retval     Others        Uh... don't continue.\r
+\r
+**/\r
+EFI_STATUS\r
+VariablePolicyExtraDeinit (\r
+  VOID\r
+  )\r
+{\r
+  // NULL implementation.\r
+  return EFI_SUCCESS;\r
+}\r
diff --git a/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyExtraInitRuntimeDxe.c b/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyExtraInitRuntimeDxe.c
new file mode 100644 (file)
index 0000000..3ca8704
--- /dev/null
@@ -0,0 +1,85 @@
+/** @file -- VariablePolicyExtraInitRuntimeDxe.c\r
+This file contains extra init and deinit routines that register and unregister\r
+VariableAddressChange callbacks.\r
+\r
+Copyright (c) Microsoft Corporation.\r
+SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/UefiRuntimeServicesTableLib.h>\r
+\r
+extern EFI_GET_VARIABLE   mGetVariableHelper;\r
+extern UINT8              *mPolicyTable;\r
+STATIC BOOLEAN            mIsVirtualAddrConverted;\r
+STATIC EFI_EVENT          mVariablePolicyLibVirtualAddressChangeEvent  = NULL;\r
+\r
+/**\r
+  For the RuntimeDxe version of this lib, convert internal pointer addresses to virtual addresses.\r
+\r
+  @param[in] Event      Event whose notification function is being invoked.\r
+  @param[in] Context    The pointer to the notification function's context, which\r
+                        is implementation-dependent.\r
+**/\r
+STATIC\r
+VOID\r
+EFIAPI\r
+VariablePolicyLibVirtualAddressCallback (\r
+  IN  EFI_EVENT   Event,\r
+  IN  VOID        *Context\r
+  )\r
+{\r
+  gRT->ConvertPointer (0, (VOID **)&mPolicyTable);\r
+  gRT->ConvertPointer (0, (VOID **)&mGetVariableHelper);\r
+  mIsVirtualAddrConverted = TRUE;\r
+}\r
+\r
+\r
+/**\r
+  An extra init hook that enables the RuntimeDxe library instance to\r
+  register VirtualAddress change callbacks. Among other things.\r
+\r
+  @retval     EFI_SUCCESS   Everything is good. Continue with init.\r
+  @retval     Others        Uh... don't continue.\r
+\r
+**/\r
+EFI_STATUS\r
+VariablePolicyExtraInit (\r
+  VOID\r
+  )\r
+{\r
+  return gBS->CreateEventEx (EVT_NOTIFY_SIGNAL,\r
+                              TPL_NOTIFY,\r
+                              VariablePolicyLibVirtualAddressCallback,\r
+                              NULL,\r
+                              &gEfiEventVirtualAddressChangeGuid,\r
+                              &mVariablePolicyLibVirtualAddressChangeEvent);\r
+}\r
+\r
+\r
+/**\r
+  An extra deinit hook that enables the RuntimeDxe library instance to\r
+  register VirtualAddress change callbacks. Among other things.\r
+\r
+  @retval     EFI_SUCCESS   Everything is good. Continue with deinit.\r
+  @retval     Others        Uh... don't continue.\r
+\r
+**/\r
+EFI_STATUS\r
+VariablePolicyExtraDeinit (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+  Status = EFI_SUCCESS;\r
+  if (mIsVirtualAddrConverted) {\r
+    Status = gBS->CloseEvent (mVariablePolicyLibVirtualAddressChangeEvent);\r
+  }\r
+  else {\r
+    Status = EFI_SUCCESS;\r
+  }\r
+\r
+  return Status;\r
+}\r
diff --git a/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.c b/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.c
new file mode 100644 (file)
index 0000000..5029ddb
--- /dev/null
@@ -0,0 +1,830 @@
+/** @file -- VariablePolicyLib.c\r
+Business logic for Variable Policy enforcement.\r
+\r
+Copyright (c) Microsoft Corporation.\r
+SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+\r
+#include <Uefi.h>\r
+\r
+#include <Library/SafeIntLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/PcdLib.h>\r
+\r
+#include <Protocol/VariablePolicy.h>\r
+#include <Library/VariablePolicyLib.h>\r
+\r
+\r
+// IMPORTANT NOTE: This library is currently rife with multiple return statements\r
+//                 for error handling. A refactor should remove these at some point.\r
+\r
+//\r
+// This library was designed with advanced unit-test features.\r
+// This define handles the configuration.\r
+#ifdef INTERNAL_UNIT_TEST\r
+#undef STATIC\r
+#define STATIC    // Nothing...\r
+#endif\r
+\r
+// An abstracted GetVariable interface that enables configuration regardless of the environment.\r
+EFI_GET_VARIABLE            mGetVariableHelper = NULL;\r
+\r
+// Master switch to lock this entire interface. Does not stop enforcement,\r
+// just prevents the configuration from being changed for the rest of the boot.\r
+STATIC  BOOLEAN             mInterfaceLocked = FALSE;\r
+\r
+// Master switch to disable the entire interface for a single boot.\r
+// This will disable all policy enforcement for the duration of the boot.\r
+STATIC  BOOLEAN             mProtectionDisabled = FALSE;\r
+\r
+// Table to hold all the current policies.\r
+UINT8                       *mPolicyTable = NULL;\r
+STATIC  UINT32              mCurrentTableSize = 0;\r
+STATIC  UINT32              mCurrentTableUsage = 0;\r
+STATIC  UINT32              mCurrentTableCount = 0;\r
+\r
+#define POLICY_TABLE_STEP_SIZE        0x1000\r
+\r
+// NOTE: DO NOT USE THESE MACROS on any structure that has not been validated.\r
+//       Current table data has already been sanitized.\r
+#define GET_NEXT_POLICY(CurPolicy)    (VARIABLE_POLICY_ENTRY*)((UINT8*)CurPolicy + CurPolicy->Size)\r
+#define GET_POLICY_NAME(CurPolicy)    (CHAR16*)((UINTN)CurPolicy + CurPolicy->OffsetToName)\r
+\r
+#define MATCH_PRIORITY_EXACT    0\r
+#define MATCH_PRIORITY_MAX      MATCH_PRIORITY_EXACT\r
+#define MATCH_PRIORITY_MIN      MAX_UINT8\r
+\r
+\r
+/**\r
+  An extra init hook that enables the RuntimeDxe library instance to\r
+  register VirtualAddress change callbacks. Among other things.\r
+\r
+  @retval     EFI_SUCCESS   Everything is good. Continue with init.\r
+  @retval     Others        Uh... don't continue.\r
+\r
+**/\r
+EFI_STATUS\r
+VariablePolicyExtraInit (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  An extra deinit hook that enables the RuntimeDxe library instance to\r
+  register VirtualAddress change callbacks. Among other things.\r
+\r
+  @retval     EFI_SUCCESS   Everything is good. Continue with deinit.\r
+  @retval     Others        Uh... don't continue.\r
+\r
+**/\r
+EFI_STATUS\r
+VariablePolicyExtraDeinit (\r
+  VOID\r
+  );\r
+\r
+\r
+/**\r
+  This helper function determines whether the structure of an incoming policy\r
+  is valid and internally consistent.\r
+\r
+  @param[in]  NewPolicy     Pointer to the incoming policy structure.\r
+\r
+  @retval     TRUE\r
+  @retval     FALSE   Pointer is NULL, size is wrong, strings are empty, or\r
+                      substructures overlap.\r
+\r
+**/\r
+STATIC\r
+BOOLEAN\r
+IsValidVariablePolicyStructure (\r
+  IN CONST VARIABLE_POLICY_ENTRY    *NewPolicy\r
+  )\r
+{\r
+  EFI_STATUS    Status;\r
+  UINTN         EntryEnd;\r
+  CHAR16        *CheckChar;\r
+  UINTN         WildcardCount;\r
+\r
+  // Sanitize some quick values.\r
+  if (NewPolicy == NULL || NewPolicy->Size == 0 ||\r
+      // Structure size should be at least as long as the minumum structure and a NULL string.\r
+      NewPolicy->Size < sizeof(VARIABLE_POLICY_ENTRY) ||\r
+      // Check for the known revision.\r
+      NewPolicy->Version != VARIABLE_POLICY_ENTRY_REVISION) {\r
+    return FALSE;\r
+  }\r
+\r
+  // Calculate the theoretical end of the structure and make sure\r
+  // that the structure can fit in memory.\r
+  Status = SafeUintnAdd( (UINTN)NewPolicy, NewPolicy->Size, &EntryEnd );\r
+  if (EFI_ERROR( Status )) {\r
+    return FALSE;\r
+  }\r
+\r
+  // Check for a valid Max Size.\r
+  if (NewPolicy->MaxSize == 0) {\r
+    return FALSE;\r
+  }\r
+\r
+  // Check for the valid list of lock policies.\r
+  if (NewPolicy->LockPolicyType != VARIABLE_POLICY_TYPE_NO_LOCK &&\r
+      NewPolicy->LockPolicyType != VARIABLE_POLICY_TYPE_LOCK_NOW &&\r
+      NewPolicy->LockPolicyType != VARIABLE_POLICY_TYPE_LOCK_ON_CREATE &&\r
+      NewPolicy->LockPolicyType != VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE)\r
+  {\r
+    return FALSE;\r
+  }\r
+\r
+  // If the policy type is VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE, make sure that the matching state variable Name\r
+  // terminates before the OffsetToName for the matching policy variable Name.\r
+  if (NewPolicy->LockPolicyType == VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE) {\r
+    // Adjust CheckChar to the offset of the LockPolicy->Name.\r
+    Status = SafeUintnAdd( (UINTN)NewPolicy + sizeof(VARIABLE_POLICY_ENTRY),\r
+                            sizeof(VARIABLE_LOCK_ON_VAR_STATE_POLICY),\r
+                            (UINTN*)&CheckChar );\r
+    if (EFI_ERROR( Status ) || EntryEnd <= (UINTN)CheckChar) {\r
+      return FALSE;\r
+    }\r
+    while (*CheckChar != CHAR_NULL) {\r
+      if (EntryEnd <= (UINTN)CheckChar) {\r
+        return FALSE;\r
+      }\r
+      CheckChar++;\r
+    }\r
+    // At this point we should have either exeeded the structure or be pointing at the last char in LockPolicy->Name.\r
+    // We should check to make sure that the policy Name comes immediately after this charcter.\r
+    if ((UINTN)++CheckChar != (UINTN)NewPolicy + NewPolicy->OffsetToName) {\r
+      return FALSE;\r
+    }\r
+  // If the policy type is any other value, make sure that the LockPolicy structure has a zero length.\r
+  } else {\r
+    if (NewPolicy->OffsetToName != sizeof(VARIABLE_POLICY_ENTRY)) {\r
+      return FALSE;\r
+    }\r
+  }\r
+\r
+  // Check to make sure that the name has a terminating character\r
+  // before the end of the structure.\r
+  // We've already checked that the name is within the bounds of the structure.\r
+  if (NewPolicy->Size != NewPolicy->OffsetToName) {\r
+    CheckChar = (CHAR16*)((UINTN)NewPolicy + NewPolicy->OffsetToName);\r
+    WildcardCount = 0;\r
+    while (*CheckChar != CHAR_NULL) {\r
+      // Make sure there aren't excessive wildcards.\r
+      if (*CheckChar == '#') {\r
+        WildcardCount++;\r
+        if (WildcardCount > MATCH_PRIORITY_MIN) {\r
+          return FALSE;\r
+        }\r
+      }\r
+      // Make sure you're still within the bounds of the policy structure.\r
+      if (EntryEnd <= (UINTN)CheckChar) {\r
+        return FALSE;\r
+      }\r
+      CheckChar++;\r
+    }\r
+\r
+    // Finally, we should be pointed at the very last character in Name, so we should be right\r
+    // up against the end of the structure.\r
+    if ((UINTN)++CheckChar != EntryEnd) {\r
+      return FALSE;\r
+    }\r
+  }\r
+\r
+  return TRUE;\r
+}\r
+\r
+\r
+/**\r
+  This helper function evaluates a policy and determines whether it matches the target\r
+  variable. If matched, will also return a value corresponding to the priority of the match.\r
+\r
+  The rules for "best match" are listed in the Variable Policy Spec.\r
+  Perfect name matches will return 0.\r
+  Single wildcard characters will return the number of wildcard characters.\r
+  Full namespaces will return MAX_UINT8.\r
+\r
+  @param[in]  EvalEntry         Pointer to the policy entry being evaluated.\r
+  @param[in]  VariableName      Same as EFI_SET_VARIABLE.\r
+  @param[in]  VendorGuid        Same as EFI_SET_VARIABLE.\r
+  @param[out] MatchPriority     [Optional] On finding a match, this value contains the priority of the match.\r
+                                Lower number == higher priority. Only valid if a match found.\r
+\r
+  @retval     TRUE          Current entry matches the target variable.\r
+  @retval     FALSE         Current entry does not match at all.\r
+\r
+**/\r
+STATIC\r
+BOOLEAN\r
+EvaluatePolicyMatch (\r
+  IN CONST  VARIABLE_POLICY_ENTRY   *EvalEntry,\r
+  IN CONST  CHAR16                  *VariableName,\r
+  IN CONST  EFI_GUID                *VendorGuid,\r
+  OUT       UINT8                   *MatchPriority    OPTIONAL\r
+  )\r
+{\r
+  BOOLEAN     Result;\r
+  CHAR16      *PolicyName;\r
+  UINT8       CalculatedPriority;\r
+  UINTN       Index;\r
+\r
+  Result = FALSE;\r
+  CalculatedPriority = MATCH_PRIORITY_EXACT;\r
+\r
+  // Step 1: If the GUID doesn't match, we're done. No need to evaluate anything else.\r
+  if (!CompareGuid( &EvalEntry->Namespace, VendorGuid )) {\r
+    goto Exit;\r
+  }\r
+\r
+  // If the GUID matches, check to see whether there is a Name associated\r
+  // with the policy. If not, this policy matches the entire namespace.\r
+  // Missing Name is indicated by size being equal to name.\r
+  if (EvalEntry->Size == EvalEntry->OffsetToName) {\r
+    CalculatedPriority = MATCH_PRIORITY_MIN;\r
+    Result = TRUE;\r
+    goto Exit;\r
+  }\r
+\r
+  // Now that we know the name exists, get it.\r
+  PolicyName = GET_POLICY_NAME( EvalEntry );\r
+\r
+  // Evaluate the name against the policy name and check for a match.\r
+  // Account for any wildcards.\r
+  Index = 0;\r
+  Result = TRUE;\r
+  // Keep going until the end of both strings.\r
+  while (PolicyName[Index] != CHAR_NULL || VariableName[Index] != CHAR_NULL) {\r
+    // If we don't have a match...\r
+    if (PolicyName[Index] != VariableName[Index] || PolicyName[Index] == '#') {\r
+      // If this is a numerical wildcard, we can consider\r
+      // it a match if we alter the priority.\r
+      if (PolicyName[Index] == L'#' &&\r
+            ((L'0' <= VariableName[Index] && VariableName[Index] <= L'9') ||\r
+             (L'A' <= VariableName[Index] && VariableName[Index] <= L'F') ||\r
+             (L'a' <= VariableName[Index] && VariableName[Index] <= L'f'))) {\r
+        if (CalculatedPriority < MATCH_PRIORITY_MIN) {\r
+          CalculatedPriority++;\r
+        }\r
+      // Otherwise, not a match.\r
+      } else {\r
+        Result = FALSE;\r
+        goto Exit;\r
+      }\r
+    }\r
+    Index++;\r
+  }\r
+\r
+Exit:\r
+  if (Result && MatchPriority != NULL) {\r
+    *MatchPriority = CalculatedPriority;\r
+  }\r
+  return Result;\r
+}\r
+\r
+\r
+/**\r
+  This helper function walks the current policy table and returns a pointer\r
+  to the best match, if any are found. Leverages EvaluatePolicyMatch() to\r
+  determine "best".\r
+\r
+  @param[in]  VariableName       Same as EFI_SET_VARIABLE.\r
+  @param[in]  VendorGuid         Same as EFI_SET_VARIABLE.\r
+  @param[out] ReturnPriority     [Optional] If pointer is provided, return the\r
+                                 priority of the match. Same as EvaluatePolicyMatch().\r
+                                 Only valid if a match is returned.\r
+\r
+  @retval     VARIABLE_POLICY_ENTRY*    Best match that was found.\r
+  @retval     NULL                      No match was found.\r
+\r
+**/\r
+STATIC\r
+VARIABLE_POLICY_ENTRY*\r
+GetBestPolicyMatch (\r
+  IN CONST  CHAR16            *VariableName,\r
+  IN CONST  EFI_GUID          *VendorGuid,\r
+  OUT       UINT8             *ReturnPriority  OPTIONAL\r
+  )\r
+{\r
+  VARIABLE_POLICY_ENTRY   *BestResult;\r
+  VARIABLE_POLICY_ENTRY   *CurrentEntry;\r
+  UINT8                   MatchPriority;\r
+  UINT8                   CurrentPriority;\r
+  UINTN                   Index;\r
+\r
+  BestResult = NULL;\r
+  MatchPriority = MATCH_PRIORITY_EXACT;\r
+\r
+  // Walk all entries in the table, looking for matches.\r
+  CurrentEntry = (VARIABLE_POLICY_ENTRY*)mPolicyTable;\r
+  for (Index = 0; Index < mCurrentTableCount; Index++) {\r
+    // Check for a match.\r
+    if (EvaluatePolicyMatch( CurrentEntry, VariableName, VendorGuid, &CurrentPriority )) {\r
+      // If match is better, take it.\r
+      if (BestResult == NULL || CurrentPriority < MatchPriority) {\r
+        BestResult = CurrentEntry;\r
+        MatchPriority = CurrentPriority;\r
+      }\r
+\r
+      // If you've hit the highest-priority match, can exit now.\r
+      if (MatchPriority == 0) {\r
+        break;\r
+      }\r
+    }\r
+\r
+    // If we're still in the loop, move to the next entry.\r
+    CurrentEntry = GET_NEXT_POLICY( CurrentEntry );\r
+  }\r
+\r
+  // If a return priority was requested, return it.\r
+  if (ReturnPriority != NULL) {\r
+    *ReturnPriority = MatchPriority;\r
+  }\r
+\r
+  return BestResult;\r
+}\r
+\r
+\r
+/**\r
+  This API function validates and registers a new policy with\r
+  the policy enforcement engine.\r
+\r
+  @param[in]  NewPolicy     Pointer to the incoming policy structure.\r
+\r
+  @retval     EFI_SUCCESS\r
+  @retval     EFI_INVALID_PARAMETER   NewPolicy is NULL or is internally inconsistent.\r
+  @retval     EFI_ALREADY_STARTED     An identical matching policy already exists.\r
+  @retval     EFI_WRITE_PROTECTED     The interface has been locked until the next reboot.\r
+  @retval     EFI_UNSUPPORTED         Policy enforcement has been disabled. No reason to add more policies.\r
+  @retval     EFI_ABORTED             A calculation error has prevented this function from completing.\r
+  @retval     EFI_OUT_OF_RESOURCES    Cannot grow the table to hold any more policies.\r
+  @retval     EFI_NOT_READY           Library has not yet been initialized.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+RegisterVariablePolicy (\r
+  IN CONST VARIABLE_POLICY_ENTRY    *NewPolicy\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  VARIABLE_POLICY_ENTRY     *MatchPolicy;\r
+  UINT8                     MatchPriority;\r
+  UINT32                    NewSize;\r
+  UINT8                     *NewTable;\r
+\r
+  if (!IsVariablePolicyLibInitialized()) {\r
+    return EFI_NOT_READY;\r
+  }\r
+  if (mInterfaceLocked) {\r
+    return EFI_WRITE_PROTECTED;\r
+  }\r
+\r
+  if (!IsValidVariablePolicyStructure( NewPolicy )) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  // Check to see whether an exact matching policy already exists.\r
+  MatchPolicy = GetBestPolicyMatch( GET_POLICY_NAME( NewPolicy ),\r
+                                    &NewPolicy->Namespace,\r
+                                    &MatchPriority );\r
+  if (MatchPolicy != NULL && MatchPriority == MATCH_PRIORITY_EXACT) {\r
+    return EFI_ALREADY_STARTED;\r
+  }\r
+\r
+  // If none exists, create it.\r
+  // If we need more space, allocate that now.\r
+  Status = SafeUint32Add( mCurrentTableUsage, NewPolicy->Size, &NewSize );\r
+  if (EFI_ERROR( Status )) {\r
+    return EFI_ABORTED;\r
+  }\r
+  if (NewSize > mCurrentTableSize) {\r
+    // Use NewSize to calculate the new table size in units of POLICY_TABLE_STEP_SIZE.\r
+    NewSize = (NewSize % POLICY_TABLE_STEP_SIZE) > 0 ?\r
+                (NewSize / POLICY_TABLE_STEP_SIZE) + 1 :\r
+                (NewSize / POLICY_TABLE_STEP_SIZE);\r
+    // Calculate the new table size in absolute bytes.\r
+    Status = SafeUint32Mult( NewSize, POLICY_TABLE_STEP_SIZE, &NewSize );\r
+    if (EFI_ERROR( Status )) {\r
+      return EFI_ABORTED;\r
+    }\r
+\r
+    // Reallocate and copy the table.\r
+    NewTable = AllocatePool( NewSize );\r
+    if (NewTable == NULL) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+    CopyMem( NewTable, mPolicyTable, mCurrentTableUsage );\r
+    mCurrentTableSize = NewSize;\r
+    if (mPolicyTable != NULL) {\r
+      FreePool( mPolicyTable );\r
+    }\r
+    mPolicyTable = NewTable;\r
+  }\r
+  // Copy the policy into the table.\r
+  CopyMem( mPolicyTable + mCurrentTableUsage, NewPolicy, NewPolicy->Size );\r
+  mCurrentTableUsage += NewPolicy->Size;\r
+  mCurrentTableCount += 1;\r
+\r
+  // We're done here.\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  This API function checks to see whether the parameters to SetVariable would\r
+  be allowed according to the current variable policies.\r
+\r
+  @param[in]  VariableName       Same as EFI_SET_VARIABLE.\r
+  @param[in]  VendorGuid         Same as EFI_SET_VARIABLE.\r
+  @param[in]  Attributes         Same as EFI_SET_VARIABLE.\r
+  @param[in]  DataSize           Same as EFI_SET_VARIABLE.\r
+  @param[in]  Data               Same as EFI_SET_VARIABLE.\r
+\r
+  @retval     EFI_SUCCESS             A matching policy allows this update.\r
+  @retval     EFI_SUCCESS             There are currently no policies that restrict this update.\r
+  @retval     EFI_SUCCESS             The protections have been disable until the next reboot.\r
+  @retval     EFI_WRITE_PROTECTED     Variable is currently locked.\r
+  @retval     EFI_INVALID_PARAMETER   Attributes or size are invalid.\r
+  @retval     EFI_ABORTED             A lock policy exists, but an error prevented evaluation.\r
+  @retval     EFI_NOT_READY           Library has not been initialized.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ValidateSetVariable (\r
+  IN  CHAR16                       *VariableName,\r
+  IN  EFI_GUID                     *VendorGuid,\r
+  IN  UINT32                       Attributes,\r
+  IN  UINTN                        DataSize,\r
+  IN  VOID                         *Data\r
+  )\r
+{\r
+  BOOLEAN                             IsDel;\r
+  VARIABLE_POLICY_ENTRY               *ActivePolicy;\r
+  EFI_STATUS                          Status;\r
+  EFI_STATUS                          ReturnStatus;\r
+  VARIABLE_LOCK_ON_VAR_STATE_POLICY   *StateVarPolicy;\r
+  CHAR16                              *StateVarName;\r
+  UINTN                               StateVarSize;\r
+  UINT8                               StateVar;\r
+\r
+  ReturnStatus = EFI_SUCCESS;\r
+\r
+  if (!IsVariablePolicyLibInitialized()) {\r
+    ReturnStatus = EFI_NOT_READY;\r
+    goto Exit;\r
+  }\r
+\r
+  // Bail if the protections are currently disabled.\r
+  if (mProtectionDisabled) {\r
+    ReturnStatus = EFI_SUCCESS;\r
+    goto Exit;\r
+  }\r
+\r
+  // Determine whether this is a delete operation.\r
+  // If so, it will affect which tests are applied.\r
+  if ((DataSize == 0) && ((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0)) {\r
+    IsDel = TRUE;\r
+  } else {\r
+    IsDel = FALSE;\r
+  }\r
+\r
+  // Find an active policy if one exists.\r
+  ActivePolicy = GetBestPolicyMatch( VariableName, VendorGuid, NULL );\r
+\r
+  // If we have an active policy, check it against the incoming data.\r
+  if (ActivePolicy != NULL) {\r
+    //\r
+    // Only enforce size and attribute constraints when updating data, not deleting.\r
+    if (!IsDel) {\r
+      // Check for size constraints.\r
+      if ((ActivePolicy->MinSize > 0 && DataSize < ActivePolicy->MinSize) ||\r
+          (ActivePolicy->MaxSize > 0 && DataSize > ActivePolicy->MaxSize)) {\r
+        ReturnStatus = EFI_INVALID_PARAMETER;\r
+        DEBUG(( DEBUG_VERBOSE, "%a - Bad Size. 0x%X <> 0x%X-0x%X\n", __FUNCTION__,\r
+                DataSize, ActivePolicy->MinSize, ActivePolicy->MaxSize ));\r
+        goto Exit;\r
+      }\r
+\r
+      // Check for attribute constraints.\r
+      if ((ActivePolicy->AttributesMustHave & Attributes) != ActivePolicy->AttributesMustHave ||\r
+          (ActivePolicy->AttributesCantHave & Attributes) != 0) {\r
+        ReturnStatus = EFI_INVALID_PARAMETER;\r
+        DEBUG(( DEBUG_VERBOSE, "%a - Bad Attributes. 0x%X <> 0x%X:0x%X\n", __FUNCTION__,\r
+                Attributes, ActivePolicy->AttributesMustHave, ActivePolicy->AttributesCantHave ));\r
+        goto Exit;\r
+      }\r
+    }\r
+\r
+    //\r
+    // Lock policy check.\r
+    //\r
+    // Check for immediate lock.\r
+    if (ActivePolicy->LockPolicyType == VARIABLE_POLICY_TYPE_LOCK_NOW) {\r
+      ReturnStatus = EFI_WRITE_PROTECTED;\r
+      goto Exit;\r
+    // Check for lock on create.\r
+    } else if (ActivePolicy->LockPolicyType == VARIABLE_POLICY_TYPE_LOCK_ON_CREATE) {\r
+      StateVarSize = 0;\r
+      Status = mGetVariableHelper( VariableName,\r
+                                   VendorGuid,\r
+                                   NULL,\r
+                                   &StateVarSize,\r
+                                   NULL );\r
+      if (Status == EFI_BUFFER_TOO_SMALL) {\r
+        ReturnStatus = EFI_WRITE_PROTECTED;\r
+        goto Exit;\r
+      }\r
+    // Check for lock on state variable.\r
+    } else if (ActivePolicy->LockPolicyType == VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE) {\r
+      StateVarPolicy = (VARIABLE_LOCK_ON_VAR_STATE_POLICY*)((UINT8*)ActivePolicy + sizeof(VARIABLE_POLICY_ENTRY));\r
+      StateVarName = (CHAR16*)((UINT8*)StateVarPolicy + sizeof(VARIABLE_LOCK_ON_VAR_STATE_POLICY));\r
+      StateVarSize = sizeof(StateVar);\r
+      Status = mGetVariableHelper( StateVarName,\r
+                                   &StateVarPolicy->Namespace,\r
+                                   NULL,\r
+                                   &StateVarSize,\r
+                                   &StateVar );\r
+\r
+      // If the variable was found, check the state. If matched, this variable is locked.\r
+      if (!EFI_ERROR( Status )) {\r
+        if (StateVar == StateVarPolicy->Value) {\r
+          ReturnStatus = EFI_WRITE_PROTECTED;\r
+          goto Exit;\r
+        }\r
+      // EFI_NOT_FOUND and EFI_BUFFER_TOO_SMALL indicate that the state doesn't match.\r
+      } else if (Status != EFI_NOT_FOUND && Status != EFI_BUFFER_TOO_SMALL) {\r
+        // We don't know what happened, but it isn't good.\r
+        ReturnStatus = EFI_ABORTED;\r
+        goto Exit;\r
+      }\r
+    }\r
+  }\r
+\r
+Exit:\r
+  DEBUG(( DEBUG_VERBOSE, "%a - Variable (%g:%s) returning %r.\n", __FUNCTION__, VendorGuid, VariableName, ReturnStatus ));\r
+  return ReturnStatus;\r
+}\r
+\r
+\r
+/**\r
+  This API function disables the variable policy enforcement. If it's\r
+  already been called once, will return EFI_ALREADY_STARTED.\r
+\r
+  @retval     EFI_SUCCESS\r
+  @retval     EFI_ALREADY_STARTED   Has already been called once this boot.\r
+  @retval     EFI_WRITE_PROTECTED   Interface has been locked until reboot.\r
+  @retval     EFI_WRITE_PROTECTED   Interface option is disabled by platform PCD.\r
+  @retval     EFI_NOT_READY         Library has not yet been initialized.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DisableVariablePolicy (\r
+  VOID\r
+  )\r
+{\r
+  if (!IsVariablePolicyLibInitialized()) {\r
+    return EFI_NOT_READY;\r
+  }\r
+  if (mProtectionDisabled) {\r
+    return EFI_ALREADY_STARTED;\r
+  }\r
+  if (mInterfaceLocked) {\r
+    return EFI_WRITE_PROTECTED;\r
+  }\r
+  if (!PcdGetBool (PcdAllowVariablePolicyEnforcementDisable)) {\r
+    return EFI_WRITE_PROTECTED;\r
+  }\r
+  mProtectionDisabled = TRUE;\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  This API function will dump the entire contents of the variable policy table.\r
+\r
+  Similar to GetVariable, the first call can be made with a 0 size and it will return\r
+  the size of the buffer required to hold the entire table.\r
+\r
+  @param[out]     Policy  Pointer to the policy buffer. Can be NULL if Size is 0.\r
+  @param[in,out]  Size    On input, the size of the output buffer. On output, the size\r
+                          of the data returned.\r
+\r
+  @retval     EFI_SUCCESS             Policy data is in the output buffer and Size has been updated.\r
+  @retval     EFI_INVALID_PARAMETER   Size is NULL, or Size is non-zero and Policy is NULL.\r
+  @retval     EFI_BUFFER_TOO_SMALL    Size is insufficient to hold policy. Size updated with required size.\r
+  @retval     EFI_NOT_READY           Library has not yet been initialized.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DumpVariablePolicy (\r
+  OUT     UINT8         *Policy,\r
+  IN OUT  UINT32        *Size\r
+  )\r
+{\r
+  if (!IsVariablePolicyLibInitialized()) {\r
+    return EFI_NOT_READY;\r
+  }\r
+\r
+  // Check the parameters.\r
+  if (Size == NULL || (*Size > 0 && Policy == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  // Make sure the size is sufficient to hold the policy table.\r
+  if (*Size < mCurrentTableUsage) {\r
+    *Size = mCurrentTableUsage;\r
+    return EFI_BUFFER_TOO_SMALL;\r
+  }\r
+\r
+  // If we're still here, copy the table and bounce.\r
+  CopyMem( Policy, mPolicyTable, mCurrentTableUsage );\r
+  *Size = mCurrentTableUsage;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  This API function returns whether or not the policy engine is\r
+  currently being enforced.\r
+\r
+  @retval     TRUE\r
+  @retval     FALSE\r
+  @retval     FALSE         Library has not yet been initialized.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+IsVariablePolicyEnabled (\r
+  VOID\r
+  )\r
+{\r
+  if (!IsVariablePolicyLibInitialized()) {\r
+    return FALSE;\r
+  }\r
+  return !mProtectionDisabled;\r
+}\r
+\r
+\r
+/**\r
+  This API function locks the interface so that no more policy updates\r
+  can be performed or changes made to the enforcement until the next boot.\r
+\r
+  @retval     EFI_SUCCESS\r
+  @retval     EFI_NOT_READY   Library has not yet been initialized.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+LockVariablePolicy (\r
+  VOID\r
+  )\r
+{\r
+  if (!IsVariablePolicyLibInitialized()) {\r
+    return EFI_NOT_READY;\r
+  }\r
+  if (mInterfaceLocked) {\r
+    return EFI_WRITE_PROTECTED;\r
+  }\r
+  mInterfaceLocked = TRUE;\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  This API function returns whether or not the policy interface is locked\r
+  for the remainder of the boot.\r
+\r
+  @retval     TRUE\r
+  @retval     FALSE\r
+  @retval     FALSE         Library has not yet been initialized.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+IsVariablePolicyInterfaceLocked (\r
+  VOID\r
+  )\r
+{\r
+  if (!IsVariablePolicyLibInitialized()) {\r
+    return FALSE;\r
+  }\r
+  return mInterfaceLocked;\r
+}\r
+\r
+\r
+/**\r
+  This helper function initializes the library and sets\r
+  up any required internal structures or handlers.\r
+\r
+  Also registers the internal pointer for the GetVariable helper.\r
+\r
+  @param[in]  GetVariableHelper A function pointer matching the EFI_GET_VARIABLE prototype that will be used to\r
+                  check policy criteria that involve the existence of other variables.\r
+\r
+  @retval     EFI_SUCCESS\r
+  @retval     EFI_ALREADY_STARTED   The initialize function has been called more than once without a call to\r
+                                    deinitialize.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+InitVariablePolicyLib (\r
+  IN  EFI_GET_VARIABLE    GetVariableHelper\r
+  )\r
+{\r
+  EFI_STATUS    Status;\r
+\r
+  Status = EFI_SUCCESS;\r
+\r
+  if (mGetVariableHelper != NULL) {\r
+    return EFI_ALREADY_STARTED;\r
+  }\r
+\r
+  if (!EFI_ERROR( Status )) {\r
+    Status = VariablePolicyExtraInit();\r
+  }\r
+\r
+  if (!EFI_ERROR( Status )) {\r
+    // Save an internal pointer to the GetVariableHelper.\r
+    mGetVariableHelper = GetVariableHelper;\r
+\r
+    // Initialize the global state.\r
+    mInterfaceLocked = FALSE;\r
+    mProtectionDisabled = FALSE;\r
+    mPolicyTable = NULL;\r
+    mCurrentTableSize = 0;\r
+    mCurrentTableUsage = 0;\r
+    mCurrentTableCount = 0;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  This helper function returns whether or not the library is currently initialized.\r
+\r
+  @retval     TRUE\r
+  @retval     FALSE\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+IsVariablePolicyLibInitialized (\r
+  VOID\r
+  )\r
+{\r
+  return (mGetVariableHelper != NULL);\r
+}\r
+\r
+\r
+/**\r
+  This helper function tears down  the library.\r
+\r
+  Should generally only be used for test harnesses.\r
+\r
+  @retval     EFI_SUCCESS\r
+  @retval     EFI_NOT_READY     Deinitialize was called without first calling initialize.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DeinitVariablePolicyLib (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS    Status;\r
+\r
+  Status = EFI_SUCCESS;\r
+\r
+  if (mGetVariableHelper == NULL) {\r
+    return EFI_NOT_READY;\r
+  }\r
+\r
+  if (!EFI_ERROR( Status )) {\r
+    Status = VariablePolicyExtraDeinit();\r
+  }\r
+\r
+  if (!EFI_ERROR( Status )) {\r
+    mGetVariableHelper = NULL;\r
+    mInterfaceLocked = FALSE;\r
+    mProtectionDisabled = FALSE;\r
+    mCurrentTableSize = 0;\r
+    mCurrentTableUsage = 0;\r
+    mCurrentTableCount = 0;\r
+\r
+    if (mPolicyTable != NULL) {\r
+      FreePool( mPolicyTable );\r
+      mPolicyTable = NULL;\r
+    }\r
+  }\r
+\r
+  return Status;\r
+}\r
diff --git a/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.inf b/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.inf
new file mode 100644 (file)
index 0000000..3fe6043
--- /dev/null
@@ -0,0 +1,48 @@
+## @file VariablePolicyLib.inf\r
+# Business logic for Variable Policy enforcement.\r
+#\r
+# Copyright (c) Microsoft Corporation.\r
+# SPDX-License-Identifier: BSD-2-Clause-Patent\r
+##\r
+\r
+\r
+[Defines]\r
+  INF_VERSION         = 0x00010017\r
+  BASE_NAME           = VariablePolicyLib\r
+  FILE_GUID           = E9ECD342-159A-4F24-9FDF-65724027C594\r
+  VERSION_STRING      = 1.0\r
+  MODULE_TYPE         = DXE_DRIVER\r
+  LIBRARY_CLASS       = VariablePolicyLib|DXE_DRIVER DXE_SMM_DRIVER MM_STANDALONE\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+#  VALID_ARCHITECTURES           = ANY\r
+#\r
+\r
+\r
+[Sources]\r
+  VariablePolicyLib.c\r
+  VariablePolicyExtraInitNull.c\r
+\r
+\r
+[Packages]\r
+  MdePkg/MdePkg.dec\r
+  MdeModulePkg/MdeModulePkg.dec\r
+\r
+\r
+[LibraryClasses]\r
+  DebugLib\r
+  BaseMemoryLib\r
+  MemoryAllocationLib\r
+  SafeIntLib\r
+  PcdLib\r
+\r
+\r
+[Pcd]\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdAllowVariablePolicyEnforcementDisable     ## CONSUMES\r
+\r
+\r
+[BuildOptions]\r
+  MSFT:NOOPT_*_*_CC_FLAGS   = -DINTERNAL_UNIT_TEST\r
+  GCC:NOOPT_*_*_CC_FLAGS    = -DINTERNAL_UNIT_TEST\r
diff --git a/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.uni b/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.uni
new file mode 100644 (file)
index 0000000..2227ec4
--- /dev/null
@@ -0,0 +1,12 @@
+// /** @file\r
+// VariablePolicyLib.uni\r
+//\r
+// Copyright (c) Microsoft Corporation.\r
+// SPDX-License-Identifier: BSD-2-Clause-Patent\r
+//\r
+// **/\r
+\r
+\r
+#string STR_MODULE_ABSTRACT             #language en-US "Library containing the business logic for the VariablePolicy engine"\r
+\r
+#string STR_MODULE_DESCRIPTION          #language en-US "Library containing the business logic for the VariablePolicy engine"\r
diff --git a/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLibRuntimeDxe.inf b/MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLibRuntimeDxe.inf
new file mode 100644 (file)
index 0000000..8b83657
--- /dev/null
@@ -0,0 +1,51 @@
+## @file VariablePolicyLibRuntimeDxe.inf\r
+# Business logic for Variable Policy enforcement.\r
+# This instance is specifically for RuntimeDxe and contains\r
+# extra routines to register for VirtualAddressChangeEvents.\r
+#\r
+# Copyright (c) Microsoft Corporation.\r
+# SPDX-License-Identifier: BSD-2-Clause-Patent\r
+##\r
+\r
+\r
+[Defines]\r
+  INF_VERSION         = 0x00010017\r
+  BASE_NAME           = VariablePolicyLibRuntimeDxe\r
+  FILE_GUID           = 205F7F0E-8EAC-4914-8390-1B90DD7E2A27\r
+  VERSION_STRING      = 1.0\r
+  MODULE_TYPE         = DXE_RUNTIME_DRIVER\r
+  LIBRARY_CLASS       = VariablePolicyLib|DXE_RUNTIME_DRIVER\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+#  VALID_ARCHITECTURES           = ANY\r
+#\r
+\r
+\r
+[Sources]\r
+  VariablePolicyLib.c\r
+  VariablePolicyExtraInitRuntimeDxe.c\r
+\r
+\r
+[Packages]\r
+  MdePkg/MdePkg.dec\r
+  MdeModulePkg/MdeModulePkg.dec\r
+\r
+\r
+[LibraryClasses]\r
+  DebugLib\r
+  BaseMemoryLib\r
+  MemoryAllocationLib\r
+  SafeIntLib\r
+  UefiBootServicesTableLib\r
+  UefiRuntimeServicesTableLib\r
+  PcdLib\r
+\r
+\r
+[Pcd]\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdAllowVariablePolicyEnforcementDisable     ## CONSUMES\r
+\r
+\r
+[Guids]\r
+  gEfiEventVirtualAddressChangeGuid\r
index 1a7e955185d8610b2be7bef90af731aaf66957cf..20d53fc5a5fa8442dc8b2e6cec2d426cd32049b0 100644 (file)
             "FVMAIN",\r
             "VARCHECKPCD",\r
             "Getxx",\r
-            "lzturbo"\r
+            "lzturbo",\r
+            "musthave",\r
+            "canthave"\r
         ],\r
         "AdditionalIncludePaths": [] # Additional paths to spell check relative to package root (wildcards supported)\r
     }\r
index 82aecc40d9a9ae72df4961364f28cf43f51a817d..51c7057bfd1bb68399a6c5098a3960104bb09fdc 100644 (file)
@@ -31,6 +31,9 @@
   ##  @libraryclass  Defines a set of methods to reset whole system.\r
   ResetSystemLib|Include/Library/ResetSystemLib.h\r
 \r
+  ##  @libraryclass  Business logic for storing and testing variable policies\r
+  VariablePolicyLib|Include/Library/VariablePolicyLib.h\r
+\r
   ##  @libraryclass  Defines a set of helper functions for resetting the system.\r
   ResetUtilityLib|Include/Library/ResetUtilityLib.h\r
 \r
index fbbc9933f5e8d1e71f1fadd2f92f4aa3c664343d..3c8bf8009c55cb5314226b2427d86613b3ce82f2 100644 (file)
@@ -3,6 +3,7 @@
 #\r
 # (C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR>\r
 # Copyright (c) 2007 - 2019, Intel Corporation. All rights reserved.<BR>\r
+# Copyright (c) Microsoft Corporation.\r
 #\r
 #    SPDX-License-Identifier: BSD-2-Clause-Patent\r
 #\r
@@ -58,6 +59,7 @@
   DxeServicesLib|MdePkg/Library/DxeServicesLib/DxeServicesLib.inf\r
   DxeServicesTableLib|MdePkg/Library/DxeServicesTableLib/DxeServicesTableLib.inf\r
   UefiBootManagerLib|MdeModulePkg/Library/UefiBootManagerLib/UefiBootManagerLib.inf\r
+  VariablePolicyLib|MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.inf\r
   #\r
   # Generic Modules\r
   #\r
   DebugLib|MdePkg/Library/UefiDebugLibConOut/UefiDebugLibConOut.inf\r
   LockBoxLib|MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxDxeLib.inf\r
   CapsuleLib|MdeModulePkg/Library/DxeCapsuleLibFmp/DxeRuntimeCapsuleLib.inf\r
+  VariablePolicyLib|MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLibRuntimeDxe.inf\r
 \r
 [LibraryClasses.common.SMM_CORE]\r
   HobLib|MdePkg/Library/DxeHobLib/DxeHobLib.inf\r
   MdeModulePkg/Library/BootLogoLib/BootLogoLib.inf\r
   MdeModulePkg/Library/TpmMeasurementLibNull/TpmMeasurementLibNull.inf\r
   MdeModulePkg/Library/AuthVariableLibNull/AuthVariableLibNull.inf\r
+  MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.inf\r
+  MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLibRuntimeDxe.inf\r
   MdeModulePkg/Library/VarCheckLib/VarCheckLib.inf\r
   MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLib.inf\r
   MdeModulePkg/Library/VarCheckPcdLib/VarCheckPcdLib.inf\r