]> git.proxmox.com Git - mirror_edk2.git/commitdiff
MdeModulePkg: Add MorLockSmm to variable driver.
authorYao, Jiewen <jiewen.yao@intel.com>
Tue, 19 Jan 2016 13:20:50 +0000 (13:20 +0000)
committerjyao1 <jyao1@Edk2>
Tue, 19 Jan 2016 13:20:50 +0000 (13:20 +0000)
Microsoft published secure MOR implementation at https://msdn.microsoft.com/en-us/library/windows/hardware/mt270973(v=vs.85).aspx
with revision 2 update. See URL for tech detail.
Previous revision 1 is handled in SecurityPkg\Tcg\ MemoryOverwriteRequestControlLock.
But the VarCheck API can not satisfy revision 2 requirement.
So we decide include MOR lock control into variable driver directly.

This patch add standalone TcgMorLockSmm implementation.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: "Yao, Jiewen" <jiewen.yao@intel.com>
Reviewed-by: "Zhang, Chao B" <chao.b.zhang@intel.com>
Reviewed-by: "Zeng, Star" <star.zeng@intel.com>
git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@19688 6f19259b-4bc3-4df7-8a09-765794883524

MdeModulePkg/Universal/Variable/RuntimeDxe/TcgMorLockSmm.c [new file with mode: 0644]

diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/TcgMorLockSmm.c b/MdeModulePkg/Universal/Variable/RuntimeDxe/TcgMorLockSmm.c
new file mode 100644 (file)
index 0000000..461b0fc
--- /dev/null
@@ -0,0 +1,394 @@
+/** @file\r
+  TCG MOR (Memory Overwrite Request) Lock Control support (SMM version).\r
+\r
+  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
+\r
+**/\r
+\r
+#include <PiDxe.h>\r
+#include <Guid/MemoryOverwriteControl.h>\r
+#include <IndustryStandard/MemoryOverwriteRequestControlLock.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include "Variable.h"\r
+\r
+typedef struct {\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
+};\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
+} MOR_LOCK_STATE;\r
+\r
+UINT8           mMorLockKey[MOR_LOCK_V2_KEY_SIZE];\r
+BOOLEAN         mMorLockKeyEmpty = TRUE;\r
+BOOLEAN         mMorLockPassThru = FALSE;\r
+MOR_LOCK_STATE  mMorLockState = MorLockStateUnlocked;\r
+\r
+/**\r
+  Returns if this is MOR related variable.\r
+\r
+  @param  VariableName the name of the vendor's variable, it's a Null-Terminated Unicode String\r
+  @param  VendorGuid   Unify identifier for vendor.\r
+\r
+  @retval  TRUE            The variable is MOR related.\r
+  @retval  FALSE           The variable is NOT MOR related.\r
+**/\r
+BOOLEAN\r
+IsAnyMorVariable (\r
+  IN CHAR16                                 *VariableName,\r
+  IN EFI_GUID                               *VendorGuid\r
+  )\r
+{\r
+  UINTN   Index;\r
+\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
+      return TRUE;\r
+    }\r
+  }\r
+  return FALSE;\r
+}\r
+\r
+/**\r
+  Returns if this is MOR lock variable.\r
+\r
+  @param  VariableName the name of the vendor's variable, it's a Null-Terminated Unicode String\r
+  @param  VendorGuid   Unify identifier for vendor.\r
+\r
+  @retval  TRUE            The variable is MOR lock variable.\r
+  @retval  FALSE           The variable is NOT MOR lock variable.\r
+**/\r
+BOOLEAN\r
+IsMorLockVariable (\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
+    return TRUE;\r
+  }\r
+  return FALSE;\r
+}\r
+\r
+/**\r
+  Set MOR lock variable.\r
+\r
+  @param  Data         MOR Lock variable data.\r
+\r
+  @retval  EFI_SUCCESS            The firmware has successfully stored the variable and its data as\r
+                                  defined by the Attributes.\r
+  @retval  EFI_INVALID_PARAMETER  An invalid combination of attribute bits was supplied, or the\r
+                                  DataSize exceeds the maximum allowed.\r
+  @retval  EFI_INVALID_PARAMETER  VariableName is an empty Unicode string.\r
+  @retval  EFI_OUT_OF_RESOURCES   Not enough storage is available to hold the variable and its data.\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
+                                  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
+**/\r
+EFI_STATUS\r
+SetMorLockVariable (\r
+  IN UINT8  Data\r
+  )\r
+{\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
+  mMorLockPassThru = FALSE;\r
+  return Status;\r
+}\r
+\r
+/**\r
+  This service is an 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 MorLock check pass, and Variable driver can store the variable data.\r
+  @retval  EFI_INVALID_PARAMETER  The MorLock data or data size or attributes is not allowed.\r
+  @retval  EFI_ACCESS_DENIED      The MorLock is locked.\r
+  @retval  EFI_WRITE_PROTECTED    The MorLock deletion is not allowed.\r
+  @retval  EFI_ALREADY_STARTED    The MorLock variable is handled inside this function.\r
+                                  Variable driver can just return EFI_SUCCESS.\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
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+  //\r
+  // Basic Check\r
+  //\r
+  if (Attributes == 0 || DataSize == 0 || Data == NULL) {\r
+    return 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
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Do not check if the request is passthru.\r
+  //\r
+  if (mMorLockPassThru) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  if (mMorLockState == MorLockStateUnlocked) {\r
+    //\r
+    // In Unlocked State\r
+    //\r
+    if (DataSize == MOR_LOCK_V1_SIZE) {\r
+      //\r
+      // V1 - lock permenantly\r
+      //\r
+      if (*(UINT8 *)Data == MOR_LOCK_DATA_UNLOCKED) {\r
+        //\r
+        // Unlock\r
+        //\r
+        Status = SetMorLockVariable (MOR_LOCK_DATA_UNLOCKED);\r
+        if (!EFI_ERROR (Status)) {\r
+          //\r
+          // return EFI_ALREADY_STARTED to skip variable set.\r
+          //\r
+          return EFI_ALREADY_STARTED;\r
+        } else {\r
+          //\r
+          // SetVar fail\r
+          //\r
+          return Status;\r
+        }\r
+      } else if (*(UINT8 *)Data == MOR_LOCK_DATA_LOCKED_WITHOUT_KEY) {\r
+        //\r
+        // Lock without key\r
+        //\r
+        Status = SetMorLockVariable (MOR_LOCK_DATA_LOCKED_WITHOUT_KEY);\r
+        if (!EFI_ERROR (Status)) {\r
+          //\r
+          // Lock success\r
+          //\r
+          mMorLockState = MorLockStateLocked;\r
+          //\r
+          // return EFI_ALREADY_STARTED to skip variable set.\r
+          //\r
+          return EFI_ALREADY_STARTED;\r
+        } else {\r
+          //\r
+          // SetVar fail\r
+          //\r
+          return Status;\r
+        }\r
+      } else {\r
+        return EFI_INVALID_PARAMETER;\r
+      }\r
+    } else if (DataSize == MOR_LOCK_V2_KEY_SIZE) {\r
+      //\r
+      // V2 lock and provision the key\r
+      //\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
+        //\r
+        // SetVar fail, do not provision the key\r
+        //\r
+        return Status;\r
+      } else {\r
+        //\r
+        // Lock success, provision the key\r
+        //\r
+        mMorLockKeyEmpty = FALSE;\r
+        CopyMem (mMorLockKey, Data, MOR_LOCK_V2_KEY_SIZE);\r
+        mMorLockState = MorLockStateLocked;\r
+        //\r
+        // return EFI_ALREADY_STARTED to skip variable set.\r
+        //\r
+        return EFI_ALREADY_STARTED;\r
+      }\r
+    } else {\r
+      ASSERT (FALSE);\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+  } else {\r
+    //\r
+    // In Locked State\r
+    //\r
+    if (mMorLockKeyEmpty || (DataSize != MOR_LOCK_V2_KEY_SIZE)) {\r
+      return EFI_ACCESS_DENIED;\r
+    }\r
+    if ((CompareMem (Data, mMorLockKey, MOR_LOCK_V2_KEY_SIZE) == 0)) {\r
+      //\r
+      // Key match - unlock\r
+      //\r
+\r
+      //\r
+      // Need set here because the data value on flash is different\r
+      //\r
+      Status = SetMorLockVariable (MOR_LOCK_DATA_UNLOCKED);\r
+      if (EFI_ERROR (Status)) {\r
+        //\r
+        // SetVar fail\r
+        //\r
+        return Status;\r
+      } else {\r
+        //\r
+        // Unlock Success\r
+        //\r
+        mMorLockState = MorLockStateUnlocked;\r
+        mMorLockKeyEmpty = TRUE;\r
+        ZeroMem (mMorLockKey, sizeof(mMorLockKey));\r
+        //\r
+        // return EFI_ALREADY_STARTED to skip variable set.\r
+        //\r
+        return EFI_ALREADY_STARTED;\r
+      }\r
+    } else {\r
+      //\r
+      // Key mismatch - Prevent Dictionary Attack\r
+      //\r
+      mMorLockState = MorLockStateLocked;\r
+      mMorLockKeyEmpty = TRUE;\r
+      ZeroMem (mMorLockKey, sizeof(mMorLockKey));\r
+      return EFI_ACCESS_DENIED;\r
+    }\r
+  }\r
+}\r
+\r
+/**\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
+  @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
+**/\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
+  )\r
+{\r
+  //\r
+  // do not handle non-MOR variable\r
+  //\r
+  if (!IsAnyMorVariable (VariableName, VendorGuid)) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  //\r
+  // MorLock variable\r
+  //\r
+  if (IsMorLockVariable (VariableName, VendorGuid)) {\r
+    return SetVariableCheckHandlerMorLock (\r
+             VariableName,\r
+             VendorGuid,\r
+             Attributes,\r
+             DataSize,\r
+             Data\r
+             );\r
+  }\r
+\r
+  //\r
+  // Mor Variable\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
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  if (mMorLockState == MorLockStateLocked) {\r
+    //\r
+    // If lock, deny access\r
+    //\r
+    return EFI_ACCESS_DENIED;\r
+  }\r
+  //\r
+  // grant access\r
+  //\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Initialization for MOR Lock Control.\r
+\r
+  @retval EFI_SUCEESS     MorLock initialization success.\r
+  @return Others          Some error occurs.\r
+**/\r
+EFI_STATUS\r
+MorLockInit (\r
+  VOID\r
+  )\r
+{\r
+  //\r
+  // Set variable to report capability to OS\r
+  //\r
+  return SetMorLockVariable (0);\r
+}\r