]> git.proxmox.com Git - mirror_edk2.git/commitdiff
Add SMRAM range check to variable SMM SMI handler.
authorczhang46 <czhang46@6f19259b-4bc3-4df7-8a09-765794883524>
Fri, 13 Jul 2012 05:15:06 +0000 (05:15 +0000)
committerczhang46 <czhang46@6f19259b-4bc3-4df7-8a09-765794883524>
Fri, 13 Jul 2012 05:15:06 +0000 (05:15 +0000)
Signed-off-by: Chao Zhang <chao.b.zhang@intel.com>
Reviewed-by: Fu, Siyuan<siyuan.fu@intel.com>
git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@13530 6f19259b-4bc3-4df7-8a09-765794883524

MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.c
MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf

index 8d949c396513e147c29de21ad75e0cc72e8564f7..d4403a2530daac67fc364faac1b75b99edafa8d0 100644 (file)
@@ -4,11 +4,22 @@
   implements  an SMI handler to communicate with the DXE runtime driver \r
   to provide variable services.\r
 \r
-Copyright (c) 2010 - 2011, 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
+  Caution: This module requires additional review when modified.\r
+  This driver will have external input - variable data and communicate buffer in SMM mode.\r
+  This external input must be validated carefully to avoid security issue like\r
+  buffer overflow, integer overflow.\r
+\r
+  SmmVariableHandler() will receive untrusted input and do basic validation.\r
+\r
+  Each sub function VariableServiceGetVariable(), VariableServiceGetNextVariableName(), \r
+  VariableServiceSetVariable(), VariableServiceQueryVariableInfo(), ReclaimForOS(), \r
+  SmmVariableGetStatistics() should also do validation based on its own knowledge.\r
+\r
+Copyright (c) 2010 - 2012, 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
@@ -17,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/VariableFormat.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
@@ -50,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
@@ -241,12 +285,15 @@ GetFvbCountAndBuffer (
 /**\r
   Get the variable statistics information from the information buffer pointed by gVariableInfo.\r
 \r
-  @param[in, out]  InfoEntry   A pointer to the buffer of variable information entry.\r
-                               On input, point to the variable information returned last time. if \r
-                               InfoEntry->VendorGuid is zero, return the first information.\r
-                               On output, point to the next variable information.\r
-  @param[in, out]  InfoSize    On input, the size of the variable information buffer.\r
-                               On output, the returned variable information size.\r
+  Caution: This function may be invoked at SMM runtime.\r
+  InfoEntry and InfoSize are external input. Care must be taken to make sure not security issue at runtime.\r
+\r
+  @param[in, out]  InfoEntry    A pointer to the buffer of variable information entry.\r
+                                On input, point to the variable information returned last time. if \r
+                                InfoEntry->VendorGuid is zero, return the first information.\r
+                                On output, point to the next variable information.\r
+  @param[in, out]  InfoSize     On input, the size of the variable information buffer.\r
+                                On output, the returned variable information size.\r
 \r
   @retval EFI_SUCCESS          The variable information is found and returned successfully.\r
   @retval EFI_UNSUPPORTED      No variable inoformation exists in variable driver. The \r
@@ -334,6 +381,12 @@ SmmVariableGetStatistics (
 \r
   This SMI handler provides services for the variable wrapper driver.\r
 \r
+  Caution: This function may receive untrusted input.\r
+  This variable data and communicate buffer are external input, so this function will do basic validation.\r
+  Each sub function VariableServiceGetVariable(), VariableServiceGetNextVariableName(), \r
+  VariableServiceSetVariable(), VariableServiceQueryVariableInfo(), ReclaimForOS(), \r
+  SmmVariableGetStatistics() should also do validation based on its own knowledge.\r
+\r
   @param[in]     DispatchHandle  The unique handle assigned to this handler by SmiHandlerRegister().\r
   @param[in]     RegisterContext Points to an optional handler context which was specified when the\r
                                  handler was registered.\r
@@ -366,12 +419,38 @@ SmmVariableHandler (
   VARIABLE_INFO_ENTRY                              *VariableInfo;\r
   UINTN                                            InfoSize;\r
 \r
-  ASSERT (CommBuffer != NULL);\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
   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
@@ -383,6 +462,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
@@ -403,6 +493,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
@@ -424,15 +525,28 @@ 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
+EXIT:\r
+\r
   SmmVariableFunctionHeader->ReturnStatus = Status;\r
 \r
   return EFI_SUCCESS;\r
@@ -532,7 +646,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
@@ -551,6 +667,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 da0a0e9ff83ecdc9c4261244059b83caff09bd82..11009c299cfb7d759d0d47323ade27f0e72ad61c 100644 (file)
@@ -8,14 +8,19 @@
 #  This module should be used with SMM Runtime DXE module together. The 
 #  SMM Runtime DXE module would install variable arch protocol and variable 
 #  write arch protocol based on SMM variable module.
-# Copyright (c) 2010 - 2012, Intel Corporation. All rights reserved.<BR>
 #
-#  This program and the accompanying materials
-#  are licensed and made available under the terms and conditions of the BSD License
-#  which accompanies this distribution. The full text of the license may be found at
-#  http://opensource.org/licenses/bsd-license.php
-#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
-#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#  Caution: This module requires additional review when modified.
+#  This driver will have external input - variable data and communicate buffer in SMM mode.
+#  This external input must be validated carefully to avoid security issue like
+#  buffer overflow, integer overflow.
+#
+# Copyright (c) 2010 - 2012, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 #
 #
 ##
@@ -62,6 +67,7 @@
   gEfiSmmFirmwareVolumeBlockProtocolGuid        ## SOMETIMES_CONSUMES
   gEfiSmmVariableProtocolGuid                   ## ALWAYS_PRODUCES
   gEfiSmmFaultTolerantWriteProtocolGuid         ## SOMETIMES_CONSUMES
+  gEfiSmmAccess2ProtocolGuid                    ## ALWAYS_CONSUMES
 
 [Guids]
   gEfiVariableGuid                              ## PRODUCES ## Configuration Table Guid