2 TCG MOR (Memory Overwrite Request) Lock Control support (SMM version).
4 This module initilizes MemoryOverwriteRequestControlLock variable.
5 This module adds Variable Hook and check MemoryOverwriteRequestControlLock.
7 Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
8 SPDX-License-Identifier: BSD-2-Clause-Patent
13 #include <Guid/MemoryOverwriteControl.h>
14 #include <IndustryStandard/MemoryOverwriteRequestControlLock.h>
15 #include <Library/DebugLib.h>
16 #include <Library/BaseLib.h>
17 #include <Library/BaseMemoryLib.h>
25 VARIABLE_TYPE mMorVariableType
[] = {
26 {MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME
, &gEfiMemoryOverwriteControlDataGuid
},
27 {MEMORY_OVERWRITE_REQUEST_CONTROL_LOCK_NAME
, &gEfiMemoryOverwriteRequestControlLockGuid
},
30 BOOLEAN mMorPassThru
= FALSE
;
32 #define MOR_LOCK_DATA_UNLOCKED 0x0
33 #define MOR_LOCK_DATA_LOCKED_WITHOUT_KEY 0x1
34 #define MOR_LOCK_DATA_LOCKED_WITH_KEY 0x2
36 #define MOR_LOCK_V1_SIZE 1
37 #define MOR_LOCK_V2_KEY_SIZE 8
40 MorLockStateUnlocked
= 0,
41 MorLockStateLocked
= 1,
44 BOOLEAN mMorLockInitializationRequired
= FALSE
;
45 UINT8 mMorLockKey
[MOR_LOCK_V2_KEY_SIZE
];
46 BOOLEAN mMorLockKeyEmpty
= TRUE
;
47 BOOLEAN mMorLockPassThru
= FALSE
;
48 MOR_LOCK_STATE mMorLockState
= MorLockStateUnlocked
;
51 Returns if this is MOR related variable.
53 @param VariableName the name of the vendor's variable, it's a Null-Terminated Unicode String
54 @param VendorGuid Unify identifier for vendor.
56 @retval TRUE The variable is MOR related.
57 @retval FALSE The variable is NOT MOR related.
61 IN CHAR16
*VariableName
,
62 IN EFI_GUID
*VendorGuid
67 for (Index
= 0; Index
< sizeof(mMorVariableType
)/sizeof(mMorVariableType
[0]); Index
++) {
68 if ((StrCmp (VariableName
, mMorVariableType
[Index
].VariableName
) == 0) &&
69 (CompareGuid (VendorGuid
, mMorVariableType
[Index
].VendorGuid
))) {
77 Returns if this is MOR lock variable.
79 @param VariableName the name of the vendor's variable, it's a Null-Terminated Unicode String
80 @param VendorGuid Unify identifier for vendor.
82 @retval TRUE The variable is MOR lock variable.
83 @retval FALSE The variable is NOT MOR lock variable.
87 IN CHAR16
*VariableName
,
88 IN EFI_GUID
*VendorGuid
91 if ((StrCmp (VariableName
, MEMORY_OVERWRITE_REQUEST_CONTROL_LOCK_NAME
) == 0) &&
92 (CompareGuid (VendorGuid
, &gEfiMemoryOverwriteRequestControlLockGuid
))) {
99 Set MOR lock variable.
101 @param Data MOR Lock variable data.
103 @retval EFI_SUCCESS The firmware has successfully stored the variable and its data as
104 defined by the Attributes.
105 @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied, or the
106 DataSize exceeds the maximum allowed.
107 @retval EFI_INVALID_PARAMETER VariableName is an empty Unicode string.
108 @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the variable and its data.
109 @retval EFI_DEVICE_ERROR The variable could not be saved due to a hardware failure.
110 @retval EFI_WRITE_PROTECTED The variable in question is read-only.
111 @retval EFI_WRITE_PROTECTED The variable in question cannot be deleted.
112 @retval EFI_SECURITY_VIOLATION The variable could not be written due to EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
113 set but the AuthInfo does NOT pass the validation check carried
115 @retval EFI_NOT_FOUND The variable trying to be updated or deleted was not found.
124 mMorLockPassThru
= TRUE
;
125 Status
= VariableServiceSetVariable (
126 MEMORY_OVERWRITE_REQUEST_CONTROL_LOCK_NAME
,
127 &gEfiMemoryOverwriteRequestControlLockGuid
,
128 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
132 mMorLockPassThru
= FALSE
;
137 This service is an MorLock checker handler for the SetVariable().
139 @param VariableName the name of the vendor's variable, as a
140 Null-Terminated Unicode String
141 @param VendorGuid Unify identifier for vendor.
142 @param Attributes Point to memory location to return the attributes of variable. If the point
143 is NULL, the parameter would be ignored.
144 @param DataSize The size in bytes of Data-Buffer.
145 @param Data Point to the content of the variable.
147 @retval EFI_SUCCESS The MorLock check pass, and Variable driver can store the variable data.
148 @retval EFI_INVALID_PARAMETER The MorLock data or data size or attributes is not allowed.
149 @retval EFI_ACCESS_DENIED The MorLock is locked.
150 @retval EFI_WRITE_PROTECTED The MorLock deletion is not allowed.
151 @retval EFI_ALREADY_STARTED The MorLock variable is handled inside this function.
152 Variable driver can just return EFI_SUCCESS.
155 SetVariableCheckHandlerMorLock (
156 IN CHAR16
*VariableName
,
157 IN EFI_GUID
*VendorGuid
,
158 IN UINT32 Attributes
,
168 if (Attributes
== 0 || DataSize
== 0 || Data
== NULL
) {
170 // Permit deletion for passthru request, deny it otherwise.
172 return mMorLockPassThru
? EFI_SUCCESS
: EFI_WRITE_PROTECTED
;
175 if ((Attributes
!= (EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
)) ||
176 ((DataSize
!= MOR_LOCK_V1_SIZE
) && (DataSize
!= MOR_LOCK_V2_KEY_SIZE
))) {
177 return EFI_INVALID_PARAMETER
;
181 // Do not check if the request is passthru.
183 if (mMorLockPassThru
) {
187 if (mMorLockState
== MorLockStateUnlocked
) {
191 if (DataSize
== MOR_LOCK_V1_SIZE
) {
193 // V1 - lock permanently
195 if (*(UINT8
*)Data
== MOR_LOCK_DATA_UNLOCKED
) {
199 Status
= SetMorLockVariable (MOR_LOCK_DATA_UNLOCKED
);
200 if (!EFI_ERROR (Status
)) {
202 // return EFI_ALREADY_STARTED to skip variable set.
204 return EFI_ALREADY_STARTED
;
211 } else if (*(UINT8
*)Data
== MOR_LOCK_DATA_LOCKED_WITHOUT_KEY
) {
215 Status
= SetMorLockVariable (MOR_LOCK_DATA_LOCKED_WITHOUT_KEY
);
216 if (!EFI_ERROR (Status
)) {
220 mMorLockState
= MorLockStateLocked
;
222 // return EFI_ALREADY_STARTED to skip variable set.
224 return EFI_ALREADY_STARTED
;
232 return EFI_INVALID_PARAMETER
;
234 } else if (DataSize
== MOR_LOCK_V2_KEY_SIZE
) {
236 // V2 lock and provision the key
240 // Need set here because the data value on flash is different
242 Status
= SetMorLockVariable (MOR_LOCK_DATA_LOCKED_WITH_KEY
);
243 if (EFI_ERROR(Status
)) {
245 // SetVar fail, do not provision the key
250 // Lock success, provision the key
252 mMorLockKeyEmpty
= FALSE
;
253 CopyMem (mMorLockKey
, Data
, MOR_LOCK_V2_KEY_SIZE
);
254 mMorLockState
= MorLockStateLocked
;
256 // return EFI_ALREADY_STARTED to skip variable set.
258 return EFI_ALREADY_STARTED
;
262 return EFI_OUT_OF_RESOURCES
;
268 if (mMorLockKeyEmpty
|| (DataSize
!= MOR_LOCK_V2_KEY_SIZE
)) {
269 return EFI_ACCESS_DENIED
;
271 if ((CompareMem (Data
, mMorLockKey
, MOR_LOCK_V2_KEY_SIZE
) == 0)) {
273 // Key match - unlock
277 // Need set here because the data value on flash is different
279 Status
= SetMorLockVariable (MOR_LOCK_DATA_UNLOCKED
);
280 if (EFI_ERROR (Status
)) {
289 mMorLockState
= MorLockStateUnlocked
;
290 mMorLockKeyEmpty
= TRUE
;
291 ZeroMem (mMorLockKey
, sizeof(mMorLockKey
));
293 // return EFI_ALREADY_STARTED to skip variable set.
295 return EFI_ALREADY_STARTED
;
299 // Key mismatch - Prevent Dictionary Attack
301 mMorLockState
= MorLockStateLocked
;
302 mMorLockKeyEmpty
= TRUE
;
303 ZeroMem (mMorLockKey
, sizeof(mMorLockKey
));
304 return EFI_ACCESS_DENIED
;
310 This service is an MOR/MorLock checker handler for the SetVariable().
312 @param[in] VariableName the name of the vendor's variable, as a
313 Null-Terminated Unicode String
314 @param[in] VendorGuid Unify identifier for vendor.
315 @param[in] Attributes Attributes bitmask to set for the variable.
316 @param[in] DataSize The size in bytes of Data-Buffer.
317 @param[in] Data Point to the content of the variable.
319 @retval EFI_SUCCESS The MOR/MorLock check pass, and Variable
320 driver can store the variable data.
321 @retval EFI_INVALID_PARAMETER The MOR/MorLock data or data size or
322 attributes is not allowed for MOR variable.
323 @retval EFI_ACCESS_DENIED The MOR/MorLock is locked.
324 @retval EFI_ALREADY_STARTED The MorLock variable is handled inside this
325 function. Variable driver can just return
329 SetVariableCheckHandlerMor (
330 IN CHAR16
*VariableName
,
331 IN EFI_GUID
*VendorGuid
,
332 IN UINT32 Attributes
,
338 // do not handle non-MOR variable
340 if (!IsAnyMorVariable (VariableName
, VendorGuid
)) {
347 if (IsMorLockVariable (VariableName
, VendorGuid
)) {
348 return SetVariableCheckHandlerMorLock (
362 // Permit deletion for passthru request.
364 if (((Attributes
== 0) || (DataSize
== 0)) && mMorPassThru
) {
371 if ((Attributes
!= (EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
)) ||
372 (DataSize
!= sizeof(UINT8
)) ||
374 return EFI_INVALID_PARAMETER
;
376 if (mMorLockState
== MorLockStateLocked
) {
378 // If lock, deny access
380 return EFI_ACCESS_DENIED
;
389 Initialization for MOR Control Lock.
391 @retval EFI_SUCCESS MorLock initialization success.
392 @return Others Some error occurs.
399 mMorLockInitializationRequired
= TRUE
;
404 Delayed initialization for MOR Control Lock at EndOfDxe.
406 This function performs any operations queued by MorLockInit().
409 MorLockInitAtEndOfDxe (
414 EFI_STATUS MorStatus
;
416 if (!mMorLockInitializationRequired
) {
418 // The EFI_SMM_FAULT_TOLERANT_WRITE_PROTOCOL has never been installed, thus
419 // the variable write service is unavailable. This should never happen.
426 // Check if the MOR variable exists.
429 MorStatus
= VariableServiceGetVariable (
430 MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME
,
431 &gEfiMemoryOverwriteControlDataGuid
,
437 // We provided a zero-sized buffer, so the above call can never succeed.
439 ASSERT (EFI_ERROR (MorStatus
));
441 if (MorStatus
== EFI_BUFFER_TOO_SMALL
) {
443 // The MOR variable exists.
445 // Some OSes don't follow the TCG's Platform Reset Attack Mitigation spec
446 // in that the OS should never create the MOR variable, only read and write
447 // it -- these OSes (unintentionally) create MOR if the platform firmware
448 // does not produce it. Whether this is the case (from the last OS boot)
449 // can be deduced from the absence of the TCG / TCG2 protocols, as edk2's
450 // MOR implementation depends on (one of) those protocols.
452 if (VariableHaveTcgProtocols ()) {
454 // The MOR variable originates from the platform firmware; set the MOR
455 // Control Lock variable to report the locking capability to the OS.
457 SetMorLockVariable (0);
462 // The MOR variable's origin is inexplicable; delete it.
466 "%a: deleting unexpected / unsupported variable %g:%s\n",
468 &gEfiMemoryOverwriteControlDataGuid
,
469 MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME
473 VariableServiceSetVariable (
474 MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME
,
475 &gEfiMemoryOverwriteControlDataGuid
,
480 mMorPassThru
= FALSE
;
484 // The MOR variable is absent; the platform firmware does not support it.
485 // Lock the variable so that no other module may create it.
487 VariableLockRequestToLock (
489 MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME
,
490 &gEfiMemoryOverwriteControlDataGuid
494 // Delete the MOR Control Lock variable too (should it exists for some
495 // reason) and prevent other modules from creating it.
497 mMorLockPassThru
= TRUE
;
498 VariableServiceSetVariable (
499 MEMORY_OVERWRITE_REQUEST_CONTROL_LOCK_NAME
,
500 &gEfiMemoryOverwriteRequestControlLockGuid
,
505 mMorLockPassThru
= FALSE
;
507 VariableLockRequestToLock (
509 MEMORY_OVERWRITE_REQUEST_CONTROL_LOCK_NAME
,
510 &gEfiMemoryOverwriteRequestControlLockGuid