]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Universal/Variable/RuntimeDxe/TcgMorLockSmm.c
MdeModulePkg/Variable: Parameterize GetNextVariableInternal () stores
[mirror_edk2.git] / MdeModulePkg / Universal / Variable / RuntimeDxe / TcgMorLockSmm.c
index d06317ca9cf4ea6a947e7b5058f7be3c0aaafdc0..6d80eb64341a487561bad771cdef809b272fd72b 100644 (file)
@@ -4,14 +4,8 @@
   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
+SPDX-License-Identifier: BSD-2-Clause-Patent\r
 \r
 **/\r
 \r
@@ -33,6 +27,8 @@ VARIABLE_TYPE  mMorVariableType[] = {
   {MEMORY_OVERWRITE_REQUEST_CONTROL_LOCK_NAME,  &gEfiMemoryOverwriteRequestControlLockGuid},\r
 };\r
 \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
@@ -45,6 +41,7 @@ typedef enum {
   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
@@ -112,7 +109,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
@@ -169,7 +166,10 @@ SetVariableCheckHandlerMorLock (
   // Basic Check\r
   //\r
   if (Attributes == 0 || DataSize == 0 || Data == NULL) {\r
-    return EFI_WRITE_PROTECTED;\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
@@ -309,19 +309,21 @@ SetVariableCheckHandlerMorLock (
 /**\r
   This service is an MOR/MorLock checker handler for the SetVariable().\r
 \r
-  @param  VariableName the name of the vendor's variable, as a\r
-                       Null-Terminated Unicode String\r
-  @param  VendorGuid   Unify identifier for vendor.\r
-  @param  Attributes   Point to memory location to return the attributes of variable. If the point\r
-                       is NULL, the parameter would be ignored.\r
-  @param  DataSize     The size in bytes of Data-Buffer.\r
-  @param  Data         Point to the content of the variable.\r
-\r
-  @retval  EFI_SUCCESS            The MOR/MorLock check pass, and Variable driver can store the variable data.\r
-  @retval  EFI_INVALID_PARAMETER  The MOR/MorLock data or data size or attributes is not allowed for MOR variable.\r
+  @param[in]  VariableName the name of the vendor's variable, as a\r
+                           Null-Terminated Unicode String\r
+  @param[in]  VendorGuid   Unify identifier for vendor.\r
+  @param[in]  Attributes   Attributes bitmask to set for the variable.\r
+  @param[in]  DataSize     The size in bytes of Data-Buffer.\r
+  @param[in]  Data         Point to the content of the variable.\r
+\r
+  @retval  EFI_SUCCESS            The MOR/MorLock check pass, and Variable\r
+                                  driver can store the variable data.\r
+  @retval  EFI_INVALID_PARAMETER  The MOR/MorLock data or data size or\r
+                                  attributes is not allowed for MOR variable.\r
   @retval  EFI_ACCESS_DENIED      The MOR/MorLock is locked.\r
-  @retval  EFI_ALREADY_STARTED    The MorLock variable is handled inside this function.\r
-                                  Variable driver can just return EFI_SUCCESS.\r
+  @retval  EFI_ALREADY_STARTED    The MorLock variable is handled inside this\r
+                                  function. Variable driver can just return\r
+                                  EFI_SUCCESS.\r
 **/\r
 EFI_STATUS\r
 SetVariableCheckHandlerMor (\r
@@ -356,6 +358,13 @@ 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
@@ -377,9 +386,9 @@ SetVariableCheckHandlerMor (
 }\r
 \r
 /**\r
-  Initialization for MOR Lock Control.\r
+  Initialization for MOR Control Lock.\r
 \r
-  @retval EFI_SUCEESS     MorLock initialization success.\r
+  @retval EFI_SUCCESS     MorLock initialization success.\r
   @return Others          Some error occurs.\r
 **/\r
 EFI_STATUS\r
@@ -387,8 +396,117 @@ 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
+\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
-  // Set variable to report capability to OS\r
+  // We provided a zero-sized buffer, so the above call can never succeed.\r
   //\r
-  return SetMorLockVariable (0);\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
+  // 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
+  VariableLockRequestToLock (\r
+    NULL,                                   // This\r
+    MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME,\r
+    &gEfiMemoryOverwriteControlDataGuid\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
+  VariableLockRequestToLock (\r
+    NULL,                                       // This\r
+    MEMORY_OVERWRITE_REQUEST_CONTROL_LOCK_NAME,\r
+    &gEfiMemoryOverwriteRequestControlLockGuid\r
+    );\r
 }\r