This module initilizes MemoryOverwriteRequestControlLock variable.\r
This module adds Variable Hook and check MemoryOverwriteRequestControlLock.\r
\r
-Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>\r
-This program and the accompanying materials\r
-are licensed and made available under the terms and conditions of the BSD License\r
-which accompanies this distribution. The full text of the license may be found at\r
-http://opensource.org/licenses/bsd-license.php\r
-\r
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) Microsoft Corporation.\r
+SPDX-License-Identifier: BSD-2-Clause-Patent\r
\r
**/\r
\r
#include <Library/BaseMemoryLib.h>\r
#include "Variable.h"\r
\r
+#include <Protocol/VariablePolicy.h>\r
+#include <Library/VariablePolicyHelperLib.h>\r
+#include <Library/VariablePolicyLib.h>\r
+\r
typedef struct {\r
- CHAR16 *VariableName;\r
- EFI_GUID *VendorGuid;\r
+ CHAR16 *VariableName;\r
+ EFI_GUID *VendorGuid;\r
} VARIABLE_TYPE;\r
\r
VARIABLE_TYPE mMorVariableType[] = {\r
- {MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME, &gEfiMemoryOverwriteControlDataGuid},\r
- {MEMORY_OVERWRITE_REQUEST_CONTROL_LOCK_NAME, &gEfiMemoryOverwriteRequestControlLockGuid},\r
+ { MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME, &gEfiMemoryOverwriteControlDataGuid },\r
+ { MEMORY_OVERWRITE_REQUEST_CONTROL_LOCK_NAME, &gEfiMemoryOverwriteRequestControlLockGuid },\r
};\r
\r
-#define MOR_LOCK_DATA_UNLOCKED 0x0\r
-#define MOR_LOCK_DATA_LOCKED_WITHOUT_KEY 0x1\r
-#define MOR_LOCK_DATA_LOCKED_WITH_KEY 0x2\r
+BOOLEAN mMorPassThru = FALSE;\r
+\r
+#define MOR_LOCK_DATA_UNLOCKED 0x0\r
+#define MOR_LOCK_DATA_LOCKED_WITHOUT_KEY 0x1\r
+#define MOR_LOCK_DATA_LOCKED_WITH_KEY 0x2\r
\r
#define MOR_LOCK_V1_SIZE 1\r
#define MOR_LOCK_V2_KEY_SIZE 8\r
\r
typedef enum {\r
MorLockStateUnlocked = 0,\r
- MorLockStateLocked = 1,\r
+ MorLockStateLocked = 1,\r
} MOR_LOCK_STATE;\r
\r
+BOOLEAN mMorLockInitializationRequired = FALSE;\r
UINT8 mMorLockKey[MOR_LOCK_V2_KEY_SIZE];\r
BOOLEAN mMorLockKeyEmpty = TRUE;\r
BOOLEAN mMorLockPassThru = FALSE;\r
-MOR_LOCK_STATE mMorLockState = MorLockStateUnlocked;\r
+MOR_LOCK_STATE mMorLockState = MorLockStateUnlocked;\r
\r
/**\r
Returns if this is MOR related variable.\r
**/\r
BOOLEAN\r
IsAnyMorVariable (\r
- IN CHAR16 *VariableName,\r
- IN EFI_GUID *VendorGuid\r
+ IN CHAR16 *VariableName,\r
+ IN EFI_GUID *VendorGuid\r
)\r
{\r
- UINTN Index;\r
+ UINTN Index;\r
\r
- for (Index = 0; Index < sizeof(mMorVariableType)/sizeof(mMorVariableType[0]); Index++) {\r
+ for (Index = 0; Index < sizeof (mMorVariableType)/sizeof (mMorVariableType[0]); Index++) {\r
if ((StrCmp (VariableName, mMorVariableType[Index].VariableName) == 0) &&\r
- (CompareGuid (VendorGuid, mMorVariableType[Index].VendorGuid))) {\r
+ (CompareGuid (VendorGuid, mMorVariableType[Index].VendorGuid)))\r
+ {\r
return TRUE;\r
}\r
}\r
+\r
return FALSE;\r
}\r
\r
**/\r
BOOLEAN\r
IsMorLockVariable (\r
- IN CHAR16 *VariableName,\r
- IN EFI_GUID *VendorGuid\r
+ IN CHAR16 *VariableName,\r
+ IN EFI_GUID *VendorGuid\r
)\r
{\r
if ((StrCmp (VariableName, MEMORY_OVERWRITE_REQUEST_CONTROL_LOCK_NAME) == 0) &&\r
- (CompareGuid (VendorGuid, &gEfiMemoryOverwriteRequestControlLockGuid))) {\r
+ (CompareGuid (VendorGuid, &gEfiMemoryOverwriteRequestControlLockGuid)))\r
+ {\r
return TRUE;\r
}\r
+\r
return FALSE;\r
}\r
\r
@retval EFI_DEVICE_ERROR The variable could not be saved due to a hardware failure.\r
@retval EFI_WRITE_PROTECTED The variable in question is read-only.\r
@retval EFI_WRITE_PROTECTED The variable in question cannot be deleted.\r
- @retval EFI_SECURITY_VIOLATION The variable could not be written due to EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS\r
+ @retval EFI_SECURITY_VIOLATION The variable could not be written due to EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS\r
set but the AuthInfo does NOT pass the validation check carried\r
out by the firmware.\r
@retval EFI_NOT_FOUND The variable trying to be updated or deleted was not found.\r
EFI_STATUS Status;\r
\r
mMorLockPassThru = TRUE;\r
- Status = VariableServiceSetVariable (\r
- MEMORY_OVERWRITE_REQUEST_CONTROL_LOCK_NAME,\r
- &gEfiMemoryOverwriteRequestControlLockGuid,\r
- EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
- sizeof(Data),\r
- &Data\r
- );\r
+ Status = VariableServiceSetVariable (\r
+ MEMORY_OVERWRITE_REQUEST_CONTROL_LOCK_NAME,\r
+ &gEfiMemoryOverwriteRequestControlLockGuid,\r
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
+ sizeof (Data),\r
+ &Data\r
+ );\r
mMorLockPassThru = FALSE;\r
return Status;\r
}\r
**/\r
EFI_STATUS\r
SetVariableCheckHandlerMorLock (\r
- IN CHAR16 *VariableName,\r
- IN EFI_GUID *VendorGuid,\r
- IN UINT32 Attributes,\r
- IN UINTN DataSize,\r
- IN VOID *Data\r
+ IN CHAR16 *VariableName,\r
+ IN EFI_GUID *VendorGuid,\r
+ IN UINT32 Attributes,\r
+ IN UINTN DataSize,\r
+ IN VOID *Data\r
)\r
{\r
EFI_STATUS Status;\r
//\r
// Basic Check\r
//\r
- if (Attributes == 0 || DataSize == 0 || Data == NULL) {\r
- return EFI_WRITE_PROTECTED;\r
+ if ((Attributes == 0) || (DataSize == 0) || (Data == NULL)) {\r
+ //\r
+ // Permit deletion for passthru request, deny it otherwise.\r
+ //\r
+ return mMorLockPassThru ? EFI_SUCCESS : EFI_WRITE_PROTECTED;\r
}\r
\r
if ((Attributes != (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS)) ||\r
- ((DataSize != MOR_LOCK_V1_SIZE) && (DataSize != MOR_LOCK_V2_KEY_SIZE))) {\r
+ ((DataSize != MOR_LOCK_V1_SIZE) && (DataSize != MOR_LOCK_V2_KEY_SIZE)))\r
+ {\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
// Need set here because the data value on flash is different\r
//\r
Status = SetMorLockVariable (MOR_LOCK_DATA_LOCKED_WITH_KEY);\r
- if (EFI_ERROR(Status)) {\r
+ if (EFI_ERROR (Status)) {\r
//\r
// SetVar fail, do not provision the key\r
//\r
if (mMorLockKeyEmpty || (DataSize != MOR_LOCK_V2_KEY_SIZE)) {\r
return EFI_ACCESS_DENIED;\r
}\r
+\r
if ((CompareMem (Data, mMorLockKey, MOR_LOCK_V2_KEY_SIZE) == 0)) {\r
//\r
// Key match - unlock\r
//\r
// Unlock Success\r
//\r
- mMorLockState = MorLockStateUnlocked;\r
+ mMorLockState = MorLockStateUnlocked;\r
mMorLockKeyEmpty = TRUE;\r
- ZeroMem (mMorLockKey, sizeof(mMorLockKey));\r
+ ZeroMem (mMorLockKey, sizeof (mMorLockKey));\r
//\r
// return EFI_ALREADY_STARTED to skip variable set.\r
//\r
//\r
// Key mismatch - Prevent Dictionary Attack\r
//\r
- mMorLockState = MorLockStateLocked;\r
+ mMorLockState = MorLockStateLocked;\r
mMorLockKeyEmpty = TRUE;\r
- ZeroMem (mMorLockKey, sizeof(mMorLockKey));\r
+ ZeroMem (mMorLockKey, sizeof (mMorLockKey));\r
return EFI_ACCESS_DENIED;\r
}\r
}\r
**/\r
EFI_STATUS\r
SetVariableCheckHandlerMor (\r
- IN CHAR16 *VariableName,\r
- IN EFI_GUID *VendorGuid,\r
- IN UINT32 Attributes,\r
- IN UINTN DataSize,\r
- IN VOID *Data\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
return EFI_SUCCESS;\r
}\r
\r
+ // Permit deletion when policy is disabled.\r
+ if (!IsVariablePolicyEnabled () && ((Attributes == 0) || (DataSize == 0))) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
//\r
// MorLock variable\r
//\r
// Mor Variable\r
//\r
\r
+ //\r
+ // Permit deletion for passthru request.\r
+ //\r
+ if (((Attributes == 0) || (DataSize == 0)) && mMorPassThru) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
//\r
// Basic Check\r
//\r
if ((Attributes != (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS)) ||\r
- (DataSize != sizeof(UINT8)) ||\r
- (Data == NULL)) {\r
+ (DataSize != sizeof (UINT8)) ||\r
+ (Data == NULL))\r
+ {\r
return EFI_INVALID_PARAMETER;\r
}\r
+\r
if (mMorLockState == MorLockStateLocked) {\r
//\r
// If lock, deny access\r
//\r
return EFI_ACCESS_DENIED;\r
}\r
+\r
//\r
// grant access\r
//\r
VOID\r
)\r
{\r
+ mMorLockInitializationRequired = TRUE;\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Delayed initialization for MOR Control Lock at EndOfDxe.\r
+\r
+ This function performs any operations queued by MorLockInit().\r
+**/\r
+VOID\r
+MorLockInitAtEndOfDxe (\r
+ VOID\r
+ )\r
+{\r
+ UINTN MorSize;\r
+ EFI_STATUS MorStatus;\r
+ EFI_STATUS Status;\r
+ VARIABLE_POLICY_ENTRY *NewPolicy;\r
+\r
+ if (!mMorLockInitializationRequired) {\r
+ //\r
+ // The EFI_SMM_FAULT_TOLERANT_WRITE_PROTOCOL has never been installed, thus\r
+ // the variable write service is unavailable. This should never happen.\r
+ //\r
+ ASSERT (FALSE);\r
+ return;\r
+ }\r
+\r
+ //\r
+ // Check if the MOR variable exists.\r
+ //\r
+ MorSize = 0;\r
+ MorStatus = VariableServiceGetVariable (\r
+ MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME,\r
+ &gEfiMemoryOverwriteControlDataGuid,\r
+ NULL, // Attributes\r
+ &MorSize,\r
+ NULL // Data\r
+ );\r
+ //\r
+ // We provided a zero-sized buffer, so the above call can never succeed.\r
+ //\r
+ ASSERT (EFI_ERROR (MorStatus));\r
+\r
+ if (MorStatus == EFI_BUFFER_TOO_SMALL) {\r
+ //\r
+ // The MOR variable exists.\r
+ //\r
+ // Some OSes don't follow the TCG's Platform Reset Attack Mitigation spec\r
+ // in that the OS should never create the MOR variable, only read and write\r
+ // it -- these OSes (unintentionally) create MOR if the platform firmware\r
+ // does not produce it. Whether this is the case (from the last OS boot)\r
+ // can be deduced from the absence of the TCG / TCG2 protocols, as edk2's\r
+ // MOR implementation depends on (one of) those protocols.\r
+ //\r
+ if (VariableHaveTcgProtocols ()) {\r
+ //\r
+ // The MOR variable originates from the platform firmware; set the MOR\r
+ // Control Lock variable to report the locking capability to the OS.\r
+ //\r
+ SetMorLockVariable (0);\r
+ return;\r
+ }\r
+\r
+ //\r
+ // The MOR variable's origin is inexplicable; delete it.\r
+ //\r
+ DEBUG ((\r
+ DEBUG_WARN,\r
+ "%a: deleting unexpected / unsupported variable %g:%s\n",\r
+ __FUNCTION__,\r
+ &gEfiMemoryOverwriteControlDataGuid,\r
+ MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME\r
+ ));\r
+\r
+ mMorPassThru = TRUE;\r
+ VariableServiceSetVariable (\r
+ MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME,\r
+ &gEfiMemoryOverwriteControlDataGuid,\r
+ 0, // Attributes\r
+ 0, // DataSize\r
+ NULL // Data\r
+ );\r
+ mMorPassThru = FALSE;\r
+ }\r
+\r
//\r
- // Set variable to report capability to OS\r
+ // The MOR variable is absent; the platform firmware does not support it.\r
+ // Lock the variable so that no other module may create it.\r
//\r
- return SetMorLockVariable (0);\r
+ NewPolicy = NULL;\r
+ Status = CreateBasicVariablePolicy (\r
+ &gEfiMemoryOverwriteControlDataGuid,\r
+ MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME,\r
+ VARIABLE_POLICY_NO_MIN_SIZE,\r
+ VARIABLE_POLICY_NO_MAX_SIZE,\r
+ VARIABLE_POLICY_NO_MUST_ATTR,\r
+ VARIABLE_POLICY_NO_CANT_ATTR,\r
+ VARIABLE_POLICY_TYPE_LOCK_NOW,\r
+ &NewPolicy\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ Status = RegisterVariablePolicy (NewPolicy);\r
+ }\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((DEBUG_ERROR, "%a - Failed to lock variable %s! %r\n", __FUNCTION__, MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME, Status));\r
+ ASSERT_EFI_ERROR (Status);\r
+ }\r
+\r
+ if (NewPolicy != NULL) {\r
+ FreePool (NewPolicy);\r
+ }\r
+\r
+ //\r
+ // Delete the MOR Control Lock variable too (should it exists for some\r
+ // reason) and prevent other modules from creating it.\r
+ //\r
+ mMorLockPassThru = TRUE;\r
+ VariableServiceSetVariable (\r
+ MEMORY_OVERWRITE_REQUEST_CONTROL_LOCK_NAME,\r
+ &gEfiMemoryOverwriteRequestControlLockGuid,\r
+ 0, // Attributes\r
+ 0, // DataSize\r
+ NULL // Data\r
+ );\r
+ mMorLockPassThru = FALSE;\r
+\r
+ NewPolicy = NULL;\r
+ Status = CreateBasicVariablePolicy (\r
+ &gEfiMemoryOverwriteRequestControlLockGuid,\r
+ MEMORY_OVERWRITE_REQUEST_CONTROL_LOCK_NAME,\r
+ VARIABLE_POLICY_NO_MIN_SIZE,\r
+ VARIABLE_POLICY_NO_MAX_SIZE,\r
+ VARIABLE_POLICY_NO_MUST_ATTR,\r
+ VARIABLE_POLICY_NO_CANT_ATTR,\r
+ VARIABLE_POLICY_TYPE_LOCK_NOW,\r
+ &NewPolicy\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ Status = RegisterVariablePolicy (NewPolicy);\r
+ }\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((DEBUG_ERROR, "%a - Failed to lock variable %s! %r\n", __FUNCTION__, MEMORY_OVERWRITE_REQUEST_CONTROL_LOCK_NAME, Status));\r
+ ASSERT_EFI_ERROR (Status);\r
+ }\r
+\r
+ if (NewPolicy != NULL) {\r
+ FreePool (NewPolicy);\r
+ }\r
}\r