]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Universal/Variable/RuntimeDxe/TcgMorLockSmm.c
MdeModulePkg: Apply uncrustify changes
[mirror_edk2.git] / MdeModulePkg / Universal / Variable / RuntimeDxe / TcgMorLockSmm.c
index 20ec98e8e8800997500dffdef5c083e64ac9108d..296afd2ec4141318b67fefd68c08e71d5b78c6db 100644 (file)
@@ -4,14 +4,9 @@
   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
@@ -23,32 +18,39 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 #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
@@ -61,18 +63,20 @@ MOR_LOCK_STATE  mMorLockState = MorLockStateUnlocked;
 **/\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
@@ -87,14 +91,16 @@ IsAnyMorVariable (
 **/\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
@@ -112,7 +118,7 @@ IsMorLockVariable (
   @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
@@ -125,13 +131,13 @@ SetMorLockVariable (
   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
@@ -156,11 +162,11 @@ SetMorLockVariable (
 **/\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
@@ -168,12 +174,16 @@ SetVariableCheckHandlerMorLock (
   //\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
@@ -240,7 +250,7 @@ SetVariableCheckHandlerMorLock (
       // 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
@@ -268,6 +278,7 @@ SetVariableCheckHandlerMorLock (
     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
@@ -286,9 +297,9 @@ SetVariableCheckHandlerMorLock (
         //\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
@@ -298,9 +309,9 @@ SetVariableCheckHandlerMorLock (
       //\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
@@ -327,11 +338,11 @@ SetVariableCheckHandlerMorLock (
 **/\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
@@ -341,6 +352,11 @@ SetVariableCheckHandlerMor (
     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
@@ -358,20 +374,30 @@ SetVariableCheckHandlerMor (
   // 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
@@ -389,8 +415,155 @@ MorLockInit (
   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