]> git.proxmox.com Git - mirror_edk2.git/commitdiff
Add SMRAM range check to variable SMM SMI handler.
authorczhang46 <czhang46@6f19259b-4bc3-4df7-8a09-765794883524>
Mon, 9 Jul 2012 08:26:35 +0000 (08:26 +0000)
committerczhang46 <czhang46@6f19259b-4bc3-4df7-8a09-765794883524>
Mon, 9 Jul 2012 08:26:35 +0000 (08:26 +0000)
git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@13514 6f19259b-4bc3-4df7-8a09-765794883524

SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableSmm.c
SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableSmm.inf

index 37b6f118399825e0ef254f8f39c6af78946679c3..8247836a635123eea0fe8ac5b1f8fdced10107dc 100644 (file)
@@ -28,12 +28,17 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 #include <Protocol/SmmVariable.h>\r
 #include <Protocol/SmmFirmwareVolumeBlock.h>\r
 #include <Protocol/SmmFaultTolerantWrite.h>\r
+#include <Protocol/SmmAccess2.h>\r
+\r
 #include <Library/SmmServicesTableLib.h>\r
 \r
 #include <Guid/AuthenticatedVariableFormat.h>\r
 #include <Guid/SmmVariableCommon.h>\r
 #include "Variable.h"\r
 \r
+EFI_SMRAM_DESCRIPTOR                                 *mSmramRanges;\r
+UINTN                                                mSmramRangeCount;\r
+\r
 extern VARIABLE_INFO_ENTRY                           *gVariableInfo;\r
 EFI_HANDLE                                           mSmmVariableHandle      = NULL;\r
 EFI_HANDLE                                           mVariableHandle         = NULL;\r
@@ -61,6 +66,34 @@ AtRuntime (
   return mAtRuntime;\r
 }\r
 \r
+/**\r
+  This function check if the address is in SMRAM.\r
+\r
+  @param Buffer  the buffer address to be checked.\r
+  @param Length  the buffer length to be checked.\r
+\r
+  @retval TRUE  this address is in SMRAM.\r
+  @retval FALSE this address is NOT in SMRAM.\r
+**/\r
+BOOLEAN\r
+InternalIsAddressInSmram (\r
+  IN EFI_PHYSICAL_ADDRESS  Buffer,\r
+  IN UINT64                Length\r
+  )\r
+{\r
+  UINTN  Index;\r
+\r
+  for (Index = 0; Index < mSmramRangeCount; Index ++) {\r
+    if (((Buffer >= mSmramRanges[Index].CpuStart) && (Buffer < mSmramRanges[Index].CpuStart + mSmramRanges[Index].PhysicalSize)) ||\r
+        ((mSmramRanges[Index].CpuStart >= Buffer) && (mSmramRanges[Index].CpuStart < Buffer + Length))) {\r
+      return TRUE;\r
+    }\r
+  }\r
+\r
+  return FALSE;\r
+}\r
+\r
+\r
 /**\r
   Initializes a basic mutual exclusion lock.\r
 \r
@@ -372,7 +405,6 @@ SmmVariableGetStatistics (
   @retval EFI_WARN_INTERRUPT_SOURCE_PENDING   The interrupt is still pending and other handlers should still \r
                                               be called.\r
   @retval EFI_INTERRUPT_PENDING               The interrupt could not be quiesced.\r
-  @retval EFI_INVALID_PARAMETER               Input parameter is invalid.\r
 \r
 **/\r
 EFI_STATUS\r
@@ -392,14 +424,39 @@ SmmVariableHandler (
   VARIABLE_INFO_ENTRY                              *VariableInfo;\r
   UINTN                                            InfoSize;\r
 \r
-  if (CommBuffer == NULL) {\r
-    return EFI_INVALID_PARAMETER;\r
+  //\r
+  // If input is invalid, stop processing this SMI\r
+  //\r
+  if (CommBuffer == NULL || CommBufferSize == NULL) {\r
+    return EFI_SUCCESS;\r
   }\r
 \r
+  if (*CommBufferSize < sizeof(SMM_VARIABLE_COMMUNICATE_HEADER) - 1) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  if (InternalIsAddressInSmram ((EFI_PHYSICAL_ADDRESS)(UINTN)CommBuffer, *CommBufferSize)) {\r
+    DEBUG ((EFI_D_ERROR, "SMM communication buffer size is in SMRAM!\n"));\r
+    return EFI_SUCCESS;\r
+  }\r
+  \r
   SmmVariableFunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *)CommBuffer;\r
+    \r
   switch (SmmVariableFunctionHeader->Function) {\r
     case SMM_VARIABLE_FUNCTION_GET_VARIABLE:\r
-      SmmVariableHeader = (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *) SmmVariableFunctionHeader->Data;     \r
+      SmmVariableHeader = (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *) SmmVariableFunctionHeader->Data;\r
+      InfoSize = OFFSET_OF(SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) \r
+                 + SmmVariableHeader->DataSize + SmmVariableHeader->NameSize;\r
+\r
+      //\r
+      // SMRAM range check already covered before\r
+      //\r
+      if (InfoSize > *CommBufferSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_HEADER, Data)) {\r
+        DEBUG ((EFI_D_ERROR, "Data size exceed communication buffer size limit!\n"));\r
+        Status = EFI_ACCESS_DENIED;\r
+        goto EXIT;\r
+      }\r
+\r
       Status = VariableServiceGetVariable (\r
                  SmmVariableHeader->Name,\r
                  &SmmVariableHeader->Guid,\r
@@ -411,6 +468,17 @@ SmmVariableHandler (
       \r
     case SMM_VARIABLE_FUNCTION_GET_NEXT_VARIABLE_NAME:\r
       GetNextVariableName = (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME *) SmmVariableFunctionHeader->Data;\r
+      InfoSize = OFFSET_OF(SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name) + GetNextVariableName->NameSize;\r
+\r
+      //\r
+      // SMRAM range check already covered before\r
+      //\r
+      if (InfoSize > *CommBufferSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_HEADER, Data)) {\r
+        DEBUG ((EFI_D_ERROR, "Data size exceed communication buffer size limit!\n"));\r
+        Status = EFI_ACCESS_DENIED;\r
+        goto EXIT;\r
+      }\r
+\r
       Status = VariableServiceGetNextVariableName (\r
                  &GetNextVariableName->NameSize,\r
                  GetNextVariableName->Name,\r
@@ -431,6 +499,17 @@ SmmVariableHandler (
       \r
     case SMM_VARIABLE_FUNCTION_QUERY_VARIABLE_INFO:\r
       QueryVariableInfo = (SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO *) SmmVariableFunctionHeader->Data;\r
+      InfoSize = sizeof(SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO);\r
+\r
+      //\r
+      // SMRAM range check already covered before\r
+      //\r
+      if (InfoSize > *CommBufferSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_HEADER, Data)) {\r
+        DEBUG ((EFI_D_ERROR, "Data size exceed communication buffer size limit!\n"));\r
+        Status = EFI_ACCESS_DENIED;\r
+        goto EXIT;\r
+      }\r
+  \r
       Status = VariableServiceQueryVariableInfo (\r
                  QueryVariableInfo->Attributes,\r
                  &QueryVariableInfo->MaximumVariableStorageSize,\r
@@ -452,17 +531,29 @@ SmmVariableHandler (
     case SMM_VARIABLE_FUNCTION_GET_STATISTICS:\r
       VariableInfo = (VARIABLE_INFO_ENTRY *) SmmVariableFunctionHeader->Data;\r
       InfoSize = *CommBufferSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_HEADER, Data);\r
+\r
+      //\r
+      // Do not need to check SmmVariableFunctionHeader->Data in SMRAM here. \r
+      // It is covered by previous CommBuffer check \r
+      //\r
+     \r
+      if (InternalIsAddressInSmram ((EFI_PHYSICAL_ADDRESS)(UINTN)CommBufferSize, sizeof(UINTN))) {\r
+        DEBUG ((EFI_D_ERROR, "SMM communication buffer size is in SMRAM!\n"));\r
+        Status = EFI_ACCESS_DENIED;\r
+        goto EXIT;\r
+      }  \r
+\r
       Status = SmmVariableGetStatistics (VariableInfo, &InfoSize);\r
       *CommBufferSize = InfoSize + OFFSET_OF (SMM_VARIABLE_COMMUNICATE_HEADER, Data);\r
       break;\r
 \r
     default:\r
-      ASSERT (FALSE);\r
       Status = EFI_UNSUPPORTED;\r
   }\r
 \r
-  SmmVariableFunctionHeader->ReturnStatus = Status;\r
+EXIT:\r
 \r
+  SmmVariableFunctionHeader->ReturnStatus = Status;\r
   return EFI_SUCCESS;\r
 }\r
 \r
@@ -560,7 +651,9 @@ VariableServiceInitialize (
   EFI_STATUS                              Status;\r
   EFI_HANDLE                              VariableHandle;\r
   VOID                                    *SmmFtwRegistration;\r
-  \r
+  EFI_SMM_ACCESS2_PROTOCOL                *SmmAccess;\r
+  UINTN                                   Size;\r
+\r
   //\r
   // Variable initialize.\r
   //\r
@@ -579,6 +672,28 @@ VariableServiceInitialize (
                     );\r
   ASSERT_EFI_ERROR (Status);\r
 \r
+  //\r
+  // Get SMRAM information\r
+  //\r
+  Status = gBS->LocateProtocol (&gEfiSmmAccess2ProtocolGuid, NULL, (VOID **)&SmmAccess);\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  Size = 0;\r
+  Status = SmmAccess->GetCapabilities (SmmAccess, &Size, NULL);\r
+  ASSERT (Status == EFI_BUFFER_TOO_SMALL);\r
+\r
+  Status = gSmst->SmmAllocatePool (\r
+                    EfiRuntimeServicesData,\r
+                    Size,\r
+                    (VOID **)&mSmramRanges\r
+                    );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  Status = SmmAccess->GetCapabilities (SmmAccess, &Size, mSmramRanges);\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  mSmramRangeCount = Size / sizeof (EFI_SMRAM_DESCRIPTOR);\r
+\r
   ///\r
   /// Register SMM variable SMI handler\r
   ///\r
index a6343dbbbdef0f500060fa70e75bf406b809e170..e0aa40ac6d4c569d574efe0ecd45b90b5d428d42 100644 (file)
@@ -72,6 +72,7 @@
   gEfiSmmFirmwareVolumeBlockProtocolGuid        ## SOMETIMES_CONSUMES\r
   gEfiSmmVariableProtocolGuid                   ## ALWAYS_PRODUCES\r
   gEfiSmmFaultTolerantWriteProtocolGuid         ## SOMETIMES_CONSUMES\r
+  gEfiSmmAccess2ProtocolGuid                    ## ALWAYS_CONSUMES\r
 \r
 [Guids]\r
   gEfiAuthenticatedVariableGuid                 ## PRODUCES ## Configuration Table Guid\r