]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmm.c
1. Fix TOCTOU issue in VariableSmm, FtwSmm, FpdtSmm, SmmCorePerformance SMM handler...
[mirror_edk2.git] / MdeModulePkg / Universal / FaultTolerantWriteDxe / FaultTolerantWriteSmm.c
index 13c709658f255f5bb5ec61218065d6372f67bc67..2580d478a38c1fb493699e83a0e10a5acaffa67b 100644 (file)
@@ -99,6 +99,32 @@ InternalIsAddressInSmram (
   return FALSE;\r
 }\r
 \r
+/**\r
+  This function check if the address refered by Buffer and Length is valid.\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 valid.\r
+  @retval FALSE this address is NOT valid.\r
+**/\r
+BOOLEAN\r
+InternalIsAddressValid (\r
+  IN UINTN                 Buffer,\r
+  IN UINTN                 Length\r
+  )\r
+{\r
+  if (Buffer > (MAX_ADDRESS - Length)) {\r
+    //\r
+    // Overflow happen\r
+    //\r
+    return FALSE;\r
+  }\r
+  if (InternalIsAddressInSmram ((EFI_PHYSICAL_ADDRESS)Buffer, (UINT64)Length)) {\r
+    return FALSE;\r
+  }\r
+  return TRUE;\r
+}\r
 \r
 /**\r
   Retrive the SMM FVB protocol interface by HANDLE.\r
@@ -343,6 +369,9 @@ SmmFaultTolerantWriteHandler (
   VOID                                             *PrivateData;\r
   EFI_HANDLE                                       SmmFvbHandle;\r
   UINTN                                            InfoSize;\r
+  UINTN                                            CommBufferPayloadSize;\r
+  UINTN                                            PrivateDataSize;\r
+  UINTN                                            Length;\r
 \r
 \r
   //\r
@@ -353,11 +382,13 @@ SmmFaultTolerantWriteHandler (
   }\r
 \r
   if (*CommBufferSize < SMM_FTW_COMMUNICATE_HEADER_SIZE) {\r
+    DEBUG ((EFI_D_ERROR, "SmmFtwHandler: SMM communication buffer size invalid!\n"));\r
     return EFI_SUCCESS;\r
   }\r
+  CommBufferPayloadSize = *CommBufferSize - SMM_FTW_COMMUNICATE_HEADER_SIZE;\r
 \r
-  if (InternalIsAddressInSmram ((EFI_PHYSICAL_ADDRESS)(UINTN)CommBuffer, *CommBufferSize)) {\r
-    DEBUG ((EFI_D_ERROR, "SMM communication buffer size is in SMRAM!\n"));\r
+  if (!InternalIsAddressValid ((UINTN)CommBuffer, *CommBufferSize)) {\r
+    DEBUG ((EFI_D_ERROR, "SmmFtwHandler: SMM communication buffer in SMRAM or overflow!\n"));\r
     return EFI_SUCCESS;\r
   }\r
 \r
@@ -374,17 +405,11 @@ SmmFaultTolerantWriteHandler (
 \r
   switch (SmmFtwFunctionHeader->Function) {\r
     case FTW_FUNCTION_GET_MAX_BLOCK_SIZE:\r
-      SmmGetMaxBlockSizeHeader = (SMM_FTW_GET_MAX_BLOCK_SIZE_HEADER *) SmmFtwFunctionHeader->Data;\r
-      InfoSize = sizeof (SMM_FTW_GET_MAX_BLOCK_SIZE_HEADER);\r
-\r
-      //\r
-      // SMRAM range check already covered before\r
-      //\r
-      if (InfoSize > *CommBufferSize - SMM_FTW_COMMUNICATE_HEADER_SIZE) {\r
-        DEBUG ((EFI_D_ERROR, "Data size exceed communication buffer size limit!\n"));\r
-        Status = EFI_ACCESS_DENIED;\r
-        break;\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
@@ -393,6 +418,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
@@ -403,11 +432,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
@@ -419,7 +473,7 @@ SmmFaultTolerantWriteHandler (
                    &mFtwDevice->FtwInstance,\r
                    SmmFtwWriteHeader->Lba,\r
                    SmmFtwWriteHeader->Offset,\r
-                   SmmFtwWriteHeader->Length,\r
+                   Length,\r
                    PrivateData,\r
                    SmmFvbHandle,\r
                    SmmFtwWriteHeader->Data\r
@@ -428,6 +482,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
@@ -444,20 +502,25 @@ 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
-      if ((UINTN)(~0) - SmmFtwGetLastWriteHeader->PrivateDataSize < OFFSET_OF (SMM_FTW_GET_LAST_WRITE_HEADER, 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) + SmmFtwGetLastWriteHeader->PrivateDataSize;\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 > *CommBufferSize - SMM_FTW_COMMUNICATE_HEADER_SIZE) {\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
@@ -469,10 +532,11 @@ SmmFaultTolerantWriteHandler (
                  &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
@@ -506,6 +570,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
@@ -527,7 +592,7 @@ FvbNotificationEvent (
   if (EFI_ERROR(Status)) {\r
     return Status;\r
   }\r
-  \r
+\r
   //\r
   // Install protocol interface\r
   //\r
@@ -539,12 +604,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
@@ -595,7 +666,6 @@ SmmFaultTolerantWriteInitialize (
   )\r
 {\r
   EFI_STATUS                              Status;\r
-  EFI_HANDLE                              FtwHandle;\r
   EFI_SMM_ACCESS2_PROTOCOL                *SmmAccess;\r
   UINTN                                   Size;\r
   VOID                                    *SmmEndOfDxeRegistration;\r
@@ -651,12 +721,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