]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmm.c
Use SmmMemLib to check communication buffer.
[mirror_edk2.git] / MdeModulePkg / Universal / FaultTolerantWriteDxe / FaultTolerantWriteSmm.c
index 4179d594dd6bddaf01a565d2879ad63d10fcf81f..c96469f18949dcb1020e9f0e41d2abe899490aba 100644 (file)
   If one of them is not satisfied, FtwWrite may fail.\r
   Usually, Spare area only takes one block. That's SpareAreaLength = BlockSize, NumberOfSpareBlock = 1.\r
 \r
-Copyright (c) 2010 - 2011, Intel Corporation. All rights reserved.<BR>\r
+  Caution: This module requires additional review when modified.\r
+  This driver need to make sure the CommBuffer is not in the SMRAM range. \r
+\r
+Copyright (c) 2010 - 2015, 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
@@ -53,13 +56,21 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 \r
 #include <PiSmm.h>\r
 #include <Library/SmmServicesTableLib.h>\r
+#include <Library/SmmMemLib.h>\r
 #include <Protocol/SmmSwapAddressRange.h>\r
 #include "FaultTolerantWrite.h"\r
 #include "FaultTolerantWriteSmmCommon.h"\r
+#include <Protocol/SmmAccess2.h>\r
+#include <Protocol/SmmEndOfDxe.h>\r
 \r
 EFI_EVENT                                 mFvbRegistration = NULL;\r
 EFI_FTW_DEVICE                            *mFtwDevice      = NULL;\r
 \r
+///\r
+/// The flag to indicate whether the platform has left the DXE phase of execution.\r
+///\r
+BOOLEAN                                   mEndOfDxe = FALSE;\r
+\r
 /**\r
   Retrive the SMM FVB protocol interface by HANDLE.\r
 \r
@@ -174,6 +185,8 @@ GetFvbCountAndBuffer (
   *NumberHandles = BufferSize / sizeof(EFI_HANDLE);\r
   if (EFI_ERROR(Status)) {\r
     *NumberHandles = 0;\r
+    FreePool (*Buffer);\r
+    *Buffer = NULL;\r
   }\r
 \r
   return Status;\r
@@ -206,6 +219,8 @@ GetFvbByAddressAndAttribute (
   EFI_FVB_ATTRIBUTES_2                FvbAttributes;\r
   EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  *Fvb;\r
 \r
+  HandleBuffer = NULL;\r
+\r
   //\r
   // Locate all handles of SMM Fvb protocol.\r
   //\r
@@ -261,6 +276,11 @@ GetFvbByAddressAndAttribute (
 \r
   This SMI handler provides services for the fault tolerant write wrapper driver.\r
 \r
+  Caution: This function requires additional review when modified.\r
+  This driver need to make sure the CommBuffer is not in the SMRAM range. \r
+  Also in FTW_FUNCTION_GET_LAST_WRITE case, check SmmFtwGetLastWriteHeader->Data + \r
+  SmmFtwGetLastWriteHeader->PrivateDataSize within communication buffer.\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
@@ -295,14 +315,51 @@ SmmFaultTolerantWriteHandler (
   SMM_FTW_GET_LAST_WRITE_HEADER                    *SmmFtwGetLastWriteHeader;\r
   VOID                                             *PrivateData;\r
   EFI_HANDLE                                       SmmFvbHandle;\r
+  UINTN                                            InfoSize;\r
+  UINTN                                            CommBufferPayloadSize;\r
+  UINTN                                            PrivateDataSize;\r
+  UINTN                                            Length;\r
+  UINTN                                            TempCommBufferSize;\r
+\r
+  //\r
+  // If input is invalid, stop processing this SMI\r
+  //\r
+  if (CommBuffer == NULL || CommBufferSize == NULL) {\r
+    return EFI_SUCCESS;\r
+  }\r
 \r
-  ASSERT (CommBuffer != NULL);\r
-  ASSERT (CommBufferSize != NULL);\r
+  TempCommBufferSize = *CommBufferSize;\r
+\r
+  if (TempCommBufferSize < SMM_FTW_COMMUNICATE_HEADER_SIZE) {\r
+    DEBUG ((EFI_D_ERROR, "SmmFtwHandler: SMM communication buffer size invalid!\n"));\r
+    return EFI_SUCCESS;\r
+  }\r
+  CommBufferPayloadSize = TempCommBufferSize - SMM_FTW_COMMUNICATE_HEADER_SIZE;\r
+\r
+  if (!SmmIsBufferOutsideSmmValid ((UINTN)CommBuffer, TempCommBufferSize)) {\r
+    DEBUG ((EFI_D_ERROR, "SmmFtwHandler: SMM communication buffer in SMRAM or overflow!\n"));\r
+    return EFI_SUCCESS;\r
+  }\r
 \r
   SmmFtwFunctionHeader = (SMM_FTW_COMMUNICATE_FUNCTION_HEADER *)CommBuffer;\r
+\r
+  if (mEndOfDxe) {\r
+    //\r
+    // It will be not safe to expose the operations after End Of Dxe.\r
+    //\r
+    DEBUG ((EFI_D_ERROR, "SmmFtwHandler: Not safe to do the operation: %x after End Of Dxe, so access denied!\n", SmmFtwFunctionHeader->Function));\r
+    SmmFtwFunctionHeader->ReturnStatus = EFI_ACCESS_DENIED;\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
   switch (SmmFtwFunctionHeader->Function) {\r
     case FTW_FUNCTION_GET_MAX_BLOCK_SIZE:\r
-      SmmGetMaxBlockSizeHeader = (SMM_FTW_GET_MAX_BLOCK_SIZE_HEADER *) SmmFtwFunctionHeader->Data;     \r
+      if (CommBufferPayloadSize < sizeof (SMM_FTW_GET_MAX_BLOCK_SIZE_HEADER)) {\r
+        DEBUG ((EFI_D_ERROR, "GetMaxBlockSize: SMM communication buffer size invalid!\n"));\r
+        return EFI_SUCCESS;\r
+      }\r
+      SmmGetMaxBlockSizeHeader = (SMM_FTW_GET_MAX_BLOCK_SIZE_HEADER *) SmmFtwFunctionHeader->Data;\r
+\r
       Status = FtwGetMaxBlockSize (\r
                  &mFtwDevice->FtwInstance,\r
                  &SmmGetMaxBlockSizeHeader->BlockSize\r
@@ -310,6 +367,10 @@ SmmFaultTolerantWriteHandler (
       break;\r
       \r
     case FTW_FUNCTION_ALLOCATE:\r
+      if (CommBufferPayloadSize < sizeof (SMM_FTW_ALLOCATE_HEADER)) {\r
+        DEBUG ((EFI_D_ERROR, "Allocate: SMM communication buffer size invalid!\n"));\r
+        return EFI_SUCCESS;\r
+      }\r
       SmmFtwAllocateHeader = (SMM_FTW_ALLOCATE_HEADER *) SmmFtwFunctionHeader->Data;\r
       Status = FtwAllocate (\r
                  &mFtwDevice->FtwInstance,\r
@@ -320,11 +381,36 @@ SmmFaultTolerantWriteHandler (
       break;\r
       \r
     case FTW_FUNCTION_WRITE:\r
+      if (CommBufferPayloadSize < OFFSET_OF (SMM_FTW_WRITE_HEADER, Data)) {\r
+        DEBUG ((EFI_D_ERROR, "Write: SMM communication buffer size invalid!\n"));\r
+        return EFI_SUCCESS;\r
+      }\r
       SmmFtwWriteHeader = (SMM_FTW_WRITE_HEADER *) SmmFtwFunctionHeader->Data;\r
-      if (SmmFtwWriteHeader->PrivateDataSize == 0) {\r
+      Length = SmmFtwWriteHeader->Length;\r
+      PrivateDataSize = SmmFtwWriteHeader->PrivateDataSize;\r
+      if (((UINTN)(~0) - Length < OFFSET_OF (SMM_FTW_WRITE_HEADER, Data)) ||\r
+        ((UINTN)(~0) - PrivateDataSize < OFFSET_OF (SMM_FTW_WRITE_HEADER, Data) + Length)) {\r
+        //\r
+        // Prevent InfoSize overflow\r
+        //\r
+        Status = EFI_ACCESS_DENIED;\r
+        break;\r
+      }\r
+      InfoSize = OFFSET_OF (SMM_FTW_WRITE_HEADER, Data) + Length + PrivateDataSize;\r
+\r
+      //\r
+      // SMRAM range check already covered before\r
+      //\r
+      if (InfoSize > CommBufferPayloadSize) {\r
+        DEBUG ((EFI_D_ERROR, "Write: Data size exceed communication buffer size limit!\n"));\r
+        Status = EFI_ACCESS_DENIED;\r
+        break;\r
+      }\r
+\r
+      if (PrivateDataSize == 0) {\r
         PrivateData = NULL;\r
       } else {\r
-        PrivateData = (VOID *)&SmmFtwWriteHeader->Data[SmmFtwWriteHeader->Length];\r
+        PrivateData = (VOID *)&SmmFtwWriteHeader->Data[Length];\r
       }\r
       Status = GetFvbByAddressAndAttribute (\r
                  SmmFtwWriteHeader->FvbBaseAddress, \r
@@ -336,7 +422,7 @@ SmmFaultTolerantWriteHandler (
                    &mFtwDevice->FtwInstance,\r
                    SmmFtwWriteHeader->Lba,\r
                    SmmFtwWriteHeader->Offset,\r
-                   SmmFtwWriteHeader->Length,\r
+                   Length,\r
                    PrivateData,\r
                    SmmFvbHandle,\r
                    SmmFtwWriteHeader->Data\r
@@ -345,6 +431,10 @@ SmmFaultTolerantWriteHandler (
       break;\r
       \r
     case FTW_FUNCTION_RESTART:\r
+      if (CommBufferPayloadSize < sizeof (SMM_FTW_RESTART_HEADER)) {\r
+        DEBUG ((EFI_D_ERROR, "Restart: SMM communication buffer size invalid!\n"));\r
+        return EFI_SUCCESS;\r
+      }\r
       SmmFtwRestartHeader = (SMM_FTW_RESTART_HEADER *) SmmFtwFunctionHeader->Data;\r
       Status = GetFvbByAddressAndAttribute (\r
                  SmmFtwRestartHeader->FvbBaseAddress, \r
@@ -361,21 +451,44 @@ SmmFaultTolerantWriteHandler (
       break;\r
       \r
     case FTW_FUNCTION_GET_LAST_WRITE:\r
+      if (CommBufferPayloadSize < OFFSET_OF (SMM_FTW_GET_LAST_WRITE_HEADER, Data)) {\r
+        DEBUG ((EFI_D_ERROR, "GetLastWrite: SMM communication buffer size invalid!\n"));\r
+        return EFI_SUCCESS;\r
+      }\r
       SmmFtwGetLastWriteHeader = (SMM_FTW_GET_LAST_WRITE_HEADER *) SmmFtwFunctionHeader->Data;\r
+      PrivateDataSize = SmmFtwGetLastWriteHeader->PrivateDataSize;\r
+      if ((UINTN)(~0) - PrivateDataSize < OFFSET_OF (SMM_FTW_GET_LAST_WRITE_HEADER, Data)){\r
+        //\r
+        // Prevent InfoSize overflow\r
+        //\r
+        Status = EFI_ACCESS_DENIED;\r
+        break;\r
+      }\r
+      InfoSize = OFFSET_OF (SMM_FTW_GET_LAST_WRITE_HEADER, Data) + PrivateDataSize;\r
+\r
+      //\r
+      // SMRAM range check already covered before\r
+      //\r
+      if (InfoSize > CommBufferPayloadSize) {\r
+        DEBUG ((EFI_D_ERROR, "Data size exceed communication buffer size limit!\n"));\r
+        Status = EFI_ACCESS_DENIED;\r
+        break;\r
+      }\r
+\r
       Status = FtwGetLastWrite (\r
                  &mFtwDevice->FtwInstance,\r
                  &SmmFtwGetLastWriteHeader->CallerId,\r
                  &SmmFtwGetLastWriteHeader->Lba,\r
                  &SmmFtwGetLastWriteHeader->Offset,\r
                  &SmmFtwGetLastWriteHeader->Length,\r
-                 &SmmFtwGetLastWriteHeader->PrivateDataSize,\r
+                 &PrivateDataSize,\r
                  (VOID *)SmmFtwGetLastWriteHeader->Data,\r
                  &SmmFtwGetLastWriteHeader->Complete\r
                  );\r
+      SmmFtwGetLastWriteHeader->PrivateDataSize = PrivateDataSize;\r
       break;\r
 \r
     default:\r
-      ASSERT (FALSE);\r
       Status = EFI_UNSUPPORTED;\r
   }\r
 \r
@@ -406,6 +519,7 @@ FvbNotificationEvent (
   EFI_STATUS                              Status;\r
   EFI_SMM_FAULT_TOLERANT_WRITE_PROTOCOL   *FtwProtocol;\r
   EFI_HANDLE                              SmmFtwHandle;\r
+  EFI_HANDLE                              FtwHandle;\r
   \r
   //\r
   // Just return to avoid install SMM FaultTolerantWriteProtocol again\r
@@ -427,7 +541,7 @@ FvbNotificationEvent (
   if (EFI_ERROR(Status)) {\r
     return Status;\r
   }\r
-  \r
+\r
   //\r
   // Install protocol interface\r
   //\r
@@ -439,12 +553,18 @@ FvbNotificationEvent (
                     );\r
   ASSERT_EFI_ERROR (Status); \r
 \r
+  ///\r
+  /// Register SMM FTW SMI handler\r
+  ///\r
+  Status = gSmst->SmiHandlerRegister (SmmFaultTolerantWriteHandler, &gEfiSmmFaultTolerantWriteProtocolGuid, &SmmFtwHandle);\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
   //\r
   // Notify the Ftw wrapper driver SMM Ftw is ready\r
   //\r
-  SmmFtwHandle = NULL;\r
+  FtwHandle = NULL;\r
   Status = gBS->InstallProtocolInterface (\r
-                  &SmmFtwHandle,\r
+                  &FtwHandle,\r
                   &gEfiSmmFaultTolerantWriteProtocolGuid,\r
                   EFI_NATIVE_INTERFACE,\r
                   NULL\r
@@ -454,6 +574,27 @@ FvbNotificationEvent (
   return EFI_SUCCESS;\r
 }\r
 \r
+/**\r
+  SMM END_OF_DXE protocol notification event handler.\r
\r
+  @param  Protocol   Points to the protocol's unique identifier\r
+  @param  Interface  Points to the interface instance\r
+  @param  Handle     The handle on which the interface was installed\r
+\r
+  @retval EFI_SUCCESS   SmmEndOfDxeCallback runs successfully\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmEndOfDxeCallback (\r
+  IN CONST EFI_GUID                       *Protocol,\r
+  IN VOID                                 *Interface,\r
+  IN EFI_HANDLE                           Handle\r
+  )\r
+{\r
+  mEndOfDxe = TRUE;\r
+  return EFI_SUCCESS;\r
+}\r
 \r
 /**\r
   This function is the entry point of the Fault Tolerant Write driver.\r
@@ -474,8 +615,8 @@ SmmFaultTolerantWriteInitialize (
   )\r
 {\r
   EFI_STATUS                              Status;\r
-  EFI_HANDLE                              FtwHandle;\r
-  \r
+  VOID                                    *SmmEndOfDxeRegistration;\r
+\r
   //\r
   // Allocate private data structure for SMM FTW protocol and do some initialization\r
   //\r
@@ -483,7 +624,17 @@ SmmFaultTolerantWriteInitialize (
   if (EFI_ERROR(Status)) {\r
     return Status;\r
   }\r
-  \r
+\r
+  //\r
+  // Register EFI_SMM_END_OF_DXE_PROTOCOL_GUID notify function.\r
+  //\r
+  Status = gSmst->SmmRegisterProtocolNotify (\r
+                    &gEfiSmmEndOfDxeProtocolGuid,\r
+                    SmmEndOfDxeCallback,\r
+                    &SmmEndOfDxeRegistration\r
+                    );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
   //\r
   // Register FvbNotificationEvent () notify function.\r
   // \r
@@ -495,12 +646,6 @@ SmmFaultTolerantWriteInitialize (
   ASSERT_EFI_ERROR (Status);\r
 \r
   FvbNotificationEvent (NULL, NULL, NULL);\r
-\r
-  ///\r
-  /// Register SMM FTW SMI handler\r
-  ///\r
-  Status = gSmst->SmiHandlerRegister (SmmFaultTolerantWriteHandler, &gEfiSmmFaultTolerantWriteProtocolGuid, &FtwHandle);\r
-  ASSERT_EFI_ERROR (Status);\r
   \r
   return EFI_SUCCESS;\r
 }\r