2 title: UEFI Variable Policy Whitepaper
4 copyright: Copyright (c) Microsoft Corporation.
11 UEFI Variable Policy spec aims to describe the DXE protocol interface
12 which allows enforcing certain rules on certain UEFI variables. The
13 protocol allows communication with the Variable Policy Engine which
14 performs the policy enforcement.
16 The Variable Policy is comprised of a set of policy entries which
17 describe, per UEFI variable (identified by namespace GUID and variable
18 name) the following rules:
20 - Required variable attributes
21 - Prohibited variable attributes
22 - Minimum variable size
23 - Maximum variable size
25 - Locking "immediately"
27 - Locking based on a state of another variable
29 The spec assumes that the Variable Policy Engine runs in a trusted
30 enclave, potentially off the main CPU that runs UEFI. For that reason,
31 it is assumed that the Variable Policy Engine has no concept of UEFI
32 events, and that the communication from the DXE driver to the trusted
33 enclave is proprietary.
35 At power-on, the Variable Policy Engine is:
37 - Enabled -- present policy entries are evaluated on variable access
39 - Unlocked -- new policy entries can be registered.
41 Policy is expected to be clear on power-on. Policy is volatile and not
42 preserved across system reset.
49 DISABLE_VARIABLE_POLICY DisableVariablePolicy;
50 IS_VARIABLE_POLICY_ENABLED IsVariablePolicyEnabled;
51 REGISTER_VARIABLE_POLICY RegisterVariablePolicy;
52 DUMP_VARIABLE_POLICY DumpVariablePolicy;
53 LOCK_VARIABLE_POLICY LockVariablePolicy;
54 } _VARIABLE_POLICY_PROTOCOL;
56 typedef _VARIABLE_POLICY_PROTOCOL VARIABLE_POLICY_PROTOCOL;
58 extern EFI_GUID gVariablePolicyProtocolGuid;
62 ## Include/Protocol/VariablePolicy.h
63 gVariablePolicyProtocolGuid = { 0x81D1675C, 0x86F6, 0x48DF, { 0xBD, 0x95, 0x9A, 0x6E, 0x4F, 0x09, 0x25, 0xC3 } }
66 ### DisableVariablePolicy
73 DisableVariablePolicy (
78 `DisableVariablePolicy` call disables the Variable Policy Engine, so
79 that the present policy entries are no longer taken into account on
80 variable access calls. This call effectively turns off the variable
81 policy verification for this boot. This also disables UEFI
82 Authenticated Variable protections including Secure Boot.
83 `DisableVariablePolicy` can only be called once during boot. If called
84 more than once, it will return `EFI_ALREADY_STARTED`. Note, this process
85 is irreversible until the next system reset -- there is no
86 "EnablePolicy" protocol function.
88 _IMPORTANT NOTE:_ It is strongly recommended that VariablePolicy *NEVER*
89 be disabled in "normal, production boot conditions". It is expected to always
90 be enforced. The most likely reasons to disable are for Manufacturing and
91 Refurbishing scenarios. If in doubt, leave the `gEfiMdeModulePkgTokenSpaceGuid.PcdAllowVariablePolicyEnforcementDisable`
92 PCD set to `FALSE` and VariablePolicy will always be enabled.
94 ### IsVariablePolicyEnabled
101 IsVariablePolicyEnabled (
106 `IsVariablePolicyEnabled` accepts a pointer to a Boolean in which it
107 will store `TRUE` if Variable Policy Engine is enabled, or `FALSE` if
108 Variable Policy Engine is disabled. The function returns `EFI_SUCCESS`.
110 ### RegisterVariablePolicy
117 RegisterVariablePolicy (
118 IN CONST VARIABLE_POLICY_ENTRY *PolicyEntry
122 `RegisterVariablePolicy` call accepts a pointer to a policy entry
123 structure and returns the status of policy registration. If the
124 Variable Policy Engine is not locked and the policy structures are
125 valid, the function will return `EFI_SUCCESS`. If the Variable Policy
126 Engine is locked, `RegisterVariablePolicy` call will return
127 `EFI_WRITE_PROTECTED` and will not register the policy entry. Bulk
128 registration is not supported at this time due to the requirements
129 around error handling on each policy registration.
131 Upon successful registration of a policy entry, Variable Policy Engine
132 will then evaluate this entry on subsequent variable access calls (as
133 long as Variable Policy Engine hasn't been disabled).
135 ### DumpVariablePolicy
148 `DumpVariablePolicy` call accepts a pointer to a buffer and a pointer to
149 the size of the buffer as parameters and returns the status of placing
150 the policy into the buffer. On first call to `DumpVariablePolicy` one
151 should pass `NULL` as the buffer and a pointer to 0 as the `Size` variable
152 and `DumpVariablePolicy` will return `EFI_BUFFER_TOO_SMALL` and will
153 populate the `Size` parameter with the size of the needed buffer to
154 store the policy. This way, the caller can allocate the buffer of
155 correct size and call `DumpVariablePolicy` again. The function will
156 populate the buffer with policy and return `EFI_SUCCESS`.
158 ### LockVariablePolicy
170 `LockVariablePolicy` locks the Variable Policy Engine, i.e. prevents any
171 new policy entries from getting registered in this boot
172 (`RegisterVariablePolicy` calls will fail with `EFI_WRITE_PROTECTED`
173 status code returned).
177 The structure below is meant for the DXE protocol calling interface,
178 when communicating to the Variable Policy Engine, thus the pragma pack
179 directive. How these policies are stored in memory is up to the
191 UINT32 AttributesMustHave;
192 UINT32 AttributesCantHave;
193 UINT8 LockPolicyType;
195 // UINT8 LockPolicy[]; // Variable Length Field
196 // CHAR16 Name[]; // Variable Length Field
197 } VARIABLE_POLICY_ENTRY;
200 The struct `VARIABLE_POLICY_ENTRY` above describes the layout for a policy
201 entry. The first element, `Size`, is the size of the policy entry, then
202 followed by `OffsetToName` -- the number of bytes from the beginning of
203 the struct to the name of the UEFI variable targeted by the policy
204 entry. The name can contain wildcards to match more than one variable,
205 more on this in the Wildcards section. The rest of the struct elements
206 are self-explanatory.
209 #define VARIABLE_POLICY_TYPE_NO_LOCK 0
210 #define VARIABLE_POLICY_TYPE_LOCK_NOW 1
211 #define VARIABLE_POLICY_TYPE_LOCK_ON_CREATE 2
212 #define VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE 3
215 `LockPolicyType` can have the following values:
217 - `VARIABLE_POLICY_TYPE_NO_LOCK` -- means that no variable locking is performed. However,
218 the attribute and size constraints are still enforced. LockPolicy
220 - `VARIABLE_POLICY_TYPE_LOCK_NOW` -- means that the variable starts being locked
221 immediately after policy entry registration. If the variable doesn't
222 exist at this point, being LockedNow means it cannot be created on
223 this boot. LockPolicy field is size 0.
224 - `VARIABLE_POLICY_TYPE_LOCK_ON_CREATE` -- means that the variable starts being locked
225 after it is created. This allows for variable creation and
226 protection after LockVariablePolicy() function has been called. The
227 LockPolicy field is size 0.
228 - `VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE` -- means that the Variable Policy Engine will
229 examine the state/contents of another variable to determine if the
230 variable referenced in the policy entry is locked.
237 // CHAR16 Name[]; // Variable Length Field
238 } VARIABLE_LOCK_ON_VAR_STATE_POLICY;
241 If `LockPolicyType` is `VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE`, then the final element in the
242 policy entry struct is of type `VARIABLE_LOCK_ON_VAR_STATE_POLICY`, which
243 lists the namespace GUID, name (no wildcards here), and value of the
244 variable which state determines the locking of the variable referenced
245 in the policy entry. The "locking" variable must be 1 byte in terms of
246 payload size. If the Referenced variable contents match the Value of the
247 `VARIABLE_LOCK_ON_VAR_STATE_POLICY` structure, the lock will be considered
248 active and the target variable will be locked. If the Reference variable
249 does not exist (ie. returns `EFI_NOT_FOUND`), this policy will be
252 ## Variable Name Wildcards
254 Two types of wildcards can be used in the UEFI variable name field in a
257 1. If the Name is a zero-length array (easily checked by comparing
258 fields `Size` and `OffsetToName` -- if they're the same, then the
259 `Name` is zero-length), then all variables in the namespace specified
260 by the provided GUID are targeted by the policy entry.
261 2. Character "#" in the `Name` corresponds to one numeric character
262 (0-9, A-F, a-f). For example, string "Boot####" in the `Name`
263 field of the policy entry will make it so that the policy entry will
264 target variables named "Boot0001", "Boot0002", etc.
266 Given the above two types of wildcards, one variable can be targeted by
267 more than one policy entry, thus there is a need to establish the
268 precedence rule: a more specific match is applied. When a variable
269 access operation is performed, Variable Policy Engine should first check
270 the variable being accessed against the policy entries without
271 wildcards, then with 1 wildcard, then with 2 wildcards, etc., followed
272 in the end by policy entries that match the whole namespace. One can
273 still imagine a situation where two policy entries with the same number
274 of wildcards match the same variable -- for example, policy entries with
275 Names "Boot00##" and "Boot##01" will both match variable "Boot0001".
276 Such situation can (and should) be avoided by designing mutually
277 exclusive Name strings with wildcards, however, if it occurs, then the
278 policy entry that was registered first will be used. After the most
279 specific match is selected, all other policies are ignored.
283 This functionality is current supported by two kinds of tests: there is a host-based
284 unit test for the core business logic (this test accompanies the `VariablePolicyLib`
285 implementation that lives in `MdeModulePkg/Library`) and there is a functional test
286 for the protocol and its interfaces (this test lives in the `MdeModulePkg/Test/ShellTest`
289 ### Host-Based Unit Test
291 There is a test that can be run as part of the Host-Based Unit Testing
292 infrastructure provided by EDK2 PyTools (documented elsewhere). It will test
293 all internal guarantees and is where you will find test cases for most of the
294 policy matching and security of the Variable Policy Engine.
296 ### Shell-Based Functional Test
298 This test -- [Variable Policy Functional Unit Test](https://github.com/microsoft/mu_plus/tree/release/202005/UefiTestingPkg/FunctionalSystemTests/VarPolicyUnitTestApp) -- can be built as a
299 UEFI Shell application and run to validate that the Variable Policy Engine
300 is correctly installed and enforcing policies on the target system.
302 NOTE: This test _must_ be run prior to calling `DisableVariablePolicy` for all
303 test cases to pass. For this reason, it is recommended to run this on a test-built
304 FW for complete results, and then again on a production-built FW for release
309 The below examples are hypothetical scenarios based on real-world requirements
310 that demonstrate how Variable Policies could be constructed to solve various
313 ### UEFI Setup Variables (Example 1)
315 Variables containing values of the setup options exposed via UEFI
316 menu (setup variables). These would be locked based on a state of
317 another variable, "ReadyToBoot", which would be set to 1 at the
318 ReadyToBoot event. Thus, the policy for the setup variables would be
319 of type `LockOnVarState`, with the "ReadyToBoot" listed as the name of
320 the variable, appropriate GUID listed as the namespace, and 1 as
321 value. Entry into the trusted UEFI menu app doesn't signal
322 ReadyToBoot, but booting to any device does, and the setup variables
323 are write-protected. The "ReadyToBoot" variable would need to be
324 locked-on-create. *(THIS IS ESSENTIALLY LOCK ON EVENT, BUT SINCE THE
325 POLICY ENGINE IS NOT IN THE UEFI ENVIRONMENT VARIABLES ARE USED)*
327 For example, "AllowPXEBoot" variable locked by "ReadyToBoot" variable.
329 (NOTE: In the below example, the emphasized fields ('Namespace', 'Value', and 'Name')
330 are members of the `VARIABLE_LOCK_ON_VAR_STATE_POLICY` structure.)
338 AttributesMustHave | ...
339 AttributesCantHave | ...
340 LockPolicyType | `VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE`
343 _Name_ | "ReadyToBoot"
344 //Name | "AllowPXEBoot"
346 ### Manufacturing VPD (Example 2)
348 Manufacturing Variable Provisioning Data (VPD) is stored in
349 variables and is created while in Manufacturing (MFG) Mode. In MFG
350 Mode Variable Policy Engine is disabled, thus these VPD variables
351 can be created. These variables are locked with lock policy type
352 `LockNow`, so that these variables can't be tampered with in Customer
353 Mode. To overwrite or clear VPD, the device would need to MFG mode,
354 which is standard practice for refurbishing/remanufacturing
357 Example: "DisplayPanelCalibration" variable...
365 AttributesMustHave | ...
366 AttributesCantHave | ...
367 LockPolicyType | `VARIABLE_POLICY_TYPE_LOCK_NOW`
368 // Name | "DisplayPanelCalibration"
370 ### 3rd Party Calibration Data (Example 3)
372 Bluetooth pre-pairing variables are locked-on-create because these
373 get created by an OS application when Variable Policy is in effect.
375 Example: "KeyboardBTPairing" variable
383 AttributesMustHave | ...
384 AttributesCantHave | ...
385 LockPolicyType | `VARIABLE_POLICY_TYPE_LOCK_ON_CREATE`
386 // Name | "KeyboardBTPairing"
388 ### Software-based Variable Policy (Example 4)
390 Example: "Boot####" variables (a name string with wildcards that
391 will match variables "Boot0000" to "BootFFFF") locked by "LockBootOrder"
400 AttributesMustHave | ...
401 AttributesCantHave | ...
402 LockPolicyType | `VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE`
405 _Name_ | "LockBootOrder"