]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Core/Pei/Dispatcher/Dispatcher.c
MdeModulePkg/PeiCore: Enable T-RAM evacuation in PeiCore (CVE-2019-11098)
[mirror_edk2.git] / MdeModulePkg / Core / Pei / Dispatcher / Dispatcher.c
index 4c2eac1384e8e29b2578d3659b55beed3573a8c0..5bc0f8674d601cc79126000db70431c5f6be5e9c 100644 (file)
@@ -952,6 +952,409 @@ PeiCheckAndSwitchStack (
   }\r
 }\r
 \r
+/**\r
+  Migrate a PEIM from temporary RAM to permanent memory.\r
+\r
+  @param PeimFileHandle       Pointer to the FFS file header of the image.\r
+  @param MigratedFileHandle   Pointer to the FFS file header of the migrated image.\r
+\r
+  @retval EFI_SUCCESS         Sucessfully migrated the PEIM to permanent memory.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+MigratePeim (\r
+  IN  EFI_PEI_FILE_HANDLE     FileHandle,\r
+  IN  EFI_PEI_FILE_HANDLE     MigratedFileHandle\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  EFI_FFS_FILE_HEADER       *FileHeader;\r
+  VOID                      *Pe32Data;\r
+  VOID                      *ImageAddress;\r
+  CHAR8                     *AsciiString;\r
+  UINTN                     Index;\r
+\r
+  Status = EFI_SUCCESS;\r
+\r
+  FileHeader = (EFI_FFS_FILE_HEADER *) FileHandle;\r
+  ASSERT (!IS_FFS_FILE2 (FileHeader));\r
+\r
+  ImageAddress = NULL;\r
+  PeiGetPe32Data (MigratedFileHandle, &ImageAddress);\r
+  if (ImageAddress != NULL) {\r
+    DEBUG_CODE_BEGIN ();\r
+    AsciiString = PeCoffLoaderGetPdbPointer (ImageAddress);\r
+    for (Index = 0; AsciiString[Index] != 0; Index++) {\r
+      if (AsciiString[Index] == '\\' || AsciiString[Index] == '/') {\r
+        AsciiString = AsciiString + Index + 1;\r
+        Index = 0;\r
+      } else if (AsciiString[Index] == '.') {\r
+        AsciiString[Index] = 0;\r
+      }\r
+    }\r
+    DEBUG ((DEBUG_INFO, "%a", AsciiString));\r
+    DEBUG_CODE_END ();\r
+\r
+    Pe32Data = (VOID *) ((UINTN) ImageAddress - (UINTN) MigratedFileHandle + (UINTN) FileHandle);\r
+    Status = LoadAndRelocatePeCoffImageInPlace (Pe32Data, ImageAddress);\r
+    ASSERT_EFI_ERROR (Status);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Migrate Status Code Callback function pointers inside an FV from temporary memory to permanent memory.\r
+\r
+  @param OrgFvHandle      Address of FV handle in temporary memory.\r
+  @param FvHandle         Address of FV handle in permanent memory.\r
+  @param FvSize           Size of the FV.\r
+\r
+**/\r
+VOID\r
+ConvertStatusCodeCallbacks (\r
+  IN  UINTN                   OrgFvHandle,\r
+  IN  UINTN                   FvHandle,\r
+  IN  UINTN                   FvSize\r
+  )\r
+{\r
+  EFI_PEI_HOB_POINTERS    Hob;\r
+  UINTN                   *NumberOfEntries;\r
+  UINTN                   *CallbackEntry;\r
+  UINTN                   Index;\r
+\r
+  Hob.Raw  = GetFirstGuidHob (&gStatusCodeCallbackGuid);\r
+  while (Hob.Raw != NULL) {\r
+    NumberOfEntries = GET_GUID_HOB_DATA (Hob);\r
+    CallbackEntry   = NumberOfEntries + 1;\r
+    for (Index = 0; Index < *NumberOfEntries; Index++) {\r
+      if (((VOID *) CallbackEntry[Index]) != NULL) {\r
+        if ((CallbackEntry[Index] >= OrgFvHandle) && (CallbackEntry[Index] < (OrgFvHandle + FvSize))) {\r
+          DEBUG ((\r
+            DEBUG_INFO,\r
+            "Migrating CallbackEntry[%Lu] from 0x%0*Lx to ",\r
+            (UINT64)Index,\r
+            (sizeof CallbackEntry[Index]) * 2,\r
+            (UINT64)CallbackEntry[Index]\r
+            ));\r
+          if (OrgFvHandle > FvHandle) {\r
+            CallbackEntry[Index] = CallbackEntry[Index] - (OrgFvHandle - FvHandle);\r
+          } else {\r
+            CallbackEntry[Index] = CallbackEntry[Index] + (FvHandle - OrgFvHandle);\r
+          }\r
+          DEBUG ((\r
+            DEBUG_INFO,\r
+            "0x%0*Lx\n",\r
+            (sizeof CallbackEntry[Index]) * 2,\r
+            (UINT64)CallbackEntry[Index]\r
+            ));\r
+        }\r
+      }\r
+    }\r
+    Hob.Raw = GET_NEXT_HOB (Hob);\r
+    Hob.Raw = GetNextGuidHob (&gStatusCodeCallbackGuid, Hob.Raw);\r
+  }\r
+}\r
+\r
+/**\r
+  Migrates SEC modules in the given firmware volume.\r
+\r
+  Migrating SECURITY_CORE files requires special treatment since they are not tracked for PEI dispatch.\r
+\r
+  This functioun should be called after the FV has been copied to its post-memory location and the PEI Core FV list has\r
+  been updated.\r
+\r
+  @param Private          Pointer to the PeiCore's private data structure.\r
+  @param FvIndex          The firmware volume index to migrate.\r
+  @param OrgFvHandle      The handle to the firmware volume in temporary memory.\r
+\r
+  @retval   EFI_SUCCESS           SEC modules were migrated successfully\r
+  @retval   EFI_INVALID_PARAMETER The Private pointer is NULL or FvCount is invalid.\r
+  @retval   EFI_NOT_FOUND         Can't find valid FFS header.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+MigrateSecModulesInFv (\r
+  IN PEI_CORE_INSTANCE    *Private,\r
+  IN  UINTN               FvIndex,\r
+  IN  UINTN               OrgFvHandle\r
+  )\r
+{\r
+  EFI_STATUS                  Status;\r
+  EFI_STATUS                  FindFileStatus;\r
+  EFI_PEI_FILE_HANDLE         MigratedFileHandle;\r
+  EFI_PEI_FILE_HANDLE         FileHandle;\r
+  UINT32                      SectionAuthenticationStatus;\r
+  UINT32                      FileSize;\r
+  VOID                        *OrgPe32SectionData;\r
+  VOID                        *Pe32SectionData;\r
+  EFI_FFS_FILE_HEADER         *FfsFileHeader;\r
+  EFI_COMMON_SECTION_HEADER   *Section;\r
+  BOOLEAN                     IsFfs3Fv;\r
+  UINTN                       SectionInstance;\r
+\r
+  if (Private == NULL || FvIndex >= Private->FvCount) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  do {\r
+    FindFileStatus =  PeiFfsFindNextFile (\r
+                        GetPeiServicesTablePointer (),\r
+                        EFI_FV_FILETYPE_SECURITY_CORE,\r
+                        Private->Fv[FvIndex].FvHandle,\r
+                        &MigratedFileHandle\r
+                        );\r
+    if (!EFI_ERROR (FindFileStatus ) && MigratedFileHandle != NULL) {\r
+      FileHandle = (EFI_PEI_FILE_HANDLE) ((UINTN) MigratedFileHandle - (UINTN) Private->Fv[FvIndex].FvHandle + OrgFvHandle);\r
+      FfsFileHeader = (EFI_FFS_FILE_HEADER *) MigratedFileHandle;\r
+\r
+      DEBUG ((DEBUG_VERBOSE, "    Migrating SEC_CORE MigratedFileHandle at 0x%x.\n", (UINTN) MigratedFileHandle));\r
+      DEBUG ((DEBUG_VERBOSE, "                       FileHandle at 0x%x.\n", (UINTN) FileHandle));\r
+\r
+      IsFfs3Fv = CompareGuid (&Private->Fv[FvIndex].FvHeader->FileSystemGuid, &gEfiFirmwareFileSystem3Guid);\r
+      if (IS_FFS_FILE2 (FfsFileHeader)) {\r
+        ASSERT (FFS_FILE2_SIZE (FfsFileHeader) > 0x00FFFFFF);\r
+        if (!IsFfs3Fv) {\r
+          DEBUG ((DEBUG_ERROR, "It is a FFS3 formatted file: %g in a non-FFS3 formatted FV.\n", &FfsFileHeader->Name));\r
+          return EFI_NOT_FOUND;\r
+        }\r
+        Section = (EFI_COMMON_SECTION_HEADER *) ((UINT8 *) FfsFileHeader + sizeof (EFI_FFS_FILE_HEADER2));\r
+        FileSize = FFS_FILE2_SIZE (FfsFileHeader) - sizeof (EFI_FFS_FILE_HEADER2);\r
+      } else {\r
+        Section = (EFI_COMMON_SECTION_HEADER *) ((UINT8 *) FfsFileHeader + sizeof (EFI_FFS_FILE_HEADER));\r
+        FileSize = FFS_FILE_SIZE (FfsFileHeader) - sizeof (EFI_FFS_FILE_HEADER);\r
+      }\r
+\r
+      SectionInstance = 1;\r
+      SectionAuthenticationStatus = 0;\r
+      Status = ProcessSection (\r
+                GetPeiServicesTablePointer (),\r
+                EFI_SECTION_PE32,\r
+                &SectionInstance,\r
+                Section,\r
+                FileSize,\r
+                &Pe32SectionData,\r
+                &SectionAuthenticationStatus,\r
+                IsFfs3Fv\r
+                );\r
+\r
+      if (!EFI_ERROR (Status)) {\r
+        OrgPe32SectionData = (VOID *) ((UINTN) Pe32SectionData - (UINTN) MigratedFileHandle + (UINTN) FileHandle);\r
+        DEBUG ((DEBUG_VERBOSE, "      PE32 section in migrated file at 0x%x.\n", (UINTN) Pe32SectionData));\r
+        DEBUG ((DEBUG_VERBOSE, "      PE32 section in original file at 0x%x.\n", (UINTN) OrgPe32SectionData));\r
+        Status = LoadAndRelocatePeCoffImageInPlace (OrgPe32SectionData, Pe32SectionData);\r
+        ASSERT_EFI_ERROR (Status);\r
+      }\r
+    }\r
+  } while (!EFI_ERROR (FindFileStatus));\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Migrates PEIMs in the given firmware volume.\r
+\r
+  @param Private          Pointer to the PeiCore's private data structure.\r
+  @param FvIndex          The firmware volume index to migrate.\r
+  @param OrgFvHandle      The handle to the firmware volume in temporary memory.\r
+  @param FvHandle         The handle to the firmware volume in permanent memory.\r
+\r
+  @retval   EFI_SUCCESS           The PEIMs in the FV were migrated successfully\r
+  @retval   EFI_INVALID_PARAMETER The Private pointer is NULL or FvCount is invalid.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+MigratePeimsInFv (\r
+  IN PEI_CORE_INSTANCE    *Private,\r
+  IN  UINTN               FvIndex,\r
+  IN  UINTN               OrgFvHandle,\r
+  IN  UINTN               FvHandle\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  volatile UINTN          FileIndex;\r
+  EFI_PEI_FILE_HANDLE     MigratedFileHandle;\r
+  EFI_PEI_FILE_HANDLE     FileHandle;\r
+\r
+  if (Private == NULL || FvIndex >= Private->FvCount) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (Private->Fv[FvIndex].ScanFv) {\r
+    for (FileIndex = 0; FileIndex < Private->Fv[FvIndex].PeimCount; FileIndex++) {\r
+      if (Private->Fv[FvIndex].FvFileHandles[FileIndex] != NULL) {\r
+        FileHandle = Private->Fv[FvIndex].FvFileHandles[FileIndex];\r
+\r
+        MigratedFileHandle = (EFI_PEI_FILE_HANDLE) ((UINTN) FileHandle - OrgFvHandle + FvHandle);\r
+\r
+        DEBUG ((DEBUG_VERBOSE, "    Migrating FileHandle %2d ", FileIndex));\r
+        Status = MigratePeim (FileHandle, MigratedFileHandle);\r
+        DEBUG ((DEBUG_VERBOSE, "\n"));\r
+        ASSERT_EFI_ERROR (Status);\r
+\r
+        if (!EFI_ERROR (Status)) {\r
+          Private->Fv[FvIndex].FvFileHandles[FileIndex] = MigratedFileHandle;\r
+          if (FvIndex == Private->CurrentPeimFvCount) {\r
+            Private->CurrentFvFileHandles[FileIndex] = MigratedFileHandle;\r
+          }\r
+        }\r
+      }\r
+    }\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Migrate FVs out of temporary RAM before the cache is flushed.\r
+\r
+  @param Private         PeiCore's private data structure\r
+  @param SecCoreData     Points to a data structure containing information about the PEI core's operating\r
+                         environment, such as the size and location of temporary RAM, the stack location and\r
+                         the BFV location.\r
+\r
+  @retval EFI_SUCCESS           Succesfully migrated installed FVs from temporary RAM to permanent memory.\r
+  @retval EFI_OUT_OF_RESOURCES  Insufficient memory exists to allocate needed pages.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EvacuateTempRam (\r
+  IN PEI_CORE_INSTANCE            *Private,\r
+  IN CONST EFI_SEC_PEI_HAND_OFF   *SecCoreData\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+  volatile UINTN                FvIndex;\r
+  volatile UINTN                FvChildIndex;\r
+  UINTN                         ChildFvOffset;\r
+  EFI_FIRMWARE_VOLUME_HEADER    *FvHeader;\r
+  EFI_FIRMWARE_VOLUME_HEADER    *ChildFvHeader;\r
+  EFI_FIRMWARE_VOLUME_HEADER    *MigratedFvHeader;\r
+  EFI_FIRMWARE_VOLUME_HEADER    *MigratedChildFvHeader;\r
+\r
+  PEI_CORE_FV_HANDLE            PeiCoreFvHandle;\r
+  EFI_PEI_CORE_FV_LOCATION_PPI  *PeiCoreFvLocationPpi;\r
+\r
+  ASSERT (Private->PeiMemoryInstalled);\r
+\r
+  DEBUG ((DEBUG_VERBOSE, "Beginning evacuation of content in temporary RAM.\n"));\r
+\r
+  //\r
+  // Migrate PPI Pointers of PEI_CORE from temporary memory to newly loaded PEI_CORE in permanent memory.\r
+  //\r
+  Status = PeiLocatePpi ((CONST EFI_PEI_SERVICES **) &Private->Ps, &gEfiPeiCoreFvLocationPpiGuid, 0, NULL, (VOID **) &PeiCoreFvLocationPpi);\r
+  if (!EFI_ERROR (Status) && (PeiCoreFvLocationPpi->PeiCoreFvLocation != NULL)) {\r
+    PeiCoreFvHandle.FvHandle = (EFI_PEI_FV_HANDLE) PeiCoreFvLocationPpi->PeiCoreFvLocation;\r
+  } else {\r
+    PeiCoreFvHandle.FvHandle = (EFI_PEI_FV_HANDLE) SecCoreData->BootFirmwareVolumeBase;\r
+  }\r
+  for (FvIndex = 0; FvIndex < Private->FvCount; FvIndex++) {\r
+    if (Private->Fv[FvIndex].FvHandle == PeiCoreFvHandle.FvHandle) {\r
+      PeiCoreFvHandle = Private->Fv[FvIndex];\r
+      break;\r
+    }\r
+  }\r
+  Status = EFI_SUCCESS;\r
+\r
+  ConvertPeiCorePpiPointers (Private, PeiCoreFvHandle);\r
+\r
+  for (FvIndex = 0; FvIndex < Private->FvCount; FvIndex++) {\r
+    FvHeader = Private->Fv[FvIndex].FvHeader;\r
+    ASSERT (FvHeader != NULL);\r
+    ASSERT (FvIndex < Private->FvCount);\r
+\r
+    DEBUG ((DEBUG_VERBOSE, "FV[%02d] at 0x%x.\n", FvIndex, (UINTN) FvHeader));\r
+    if (\r
+      !(\r
+        ((EFI_PHYSICAL_ADDRESS)(UINTN) FvHeader >= Private->PhysicalMemoryBegin) &&\r
+        (((EFI_PHYSICAL_ADDRESS)(UINTN) FvHeader + (FvHeader->FvLength - 1)) < Private->FreePhysicalMemoryTop)\r
+        )\r
+      ) {\r
+      Status =  PeiServicesAllocatePages (\r
+                  EfiBootServicesCode,\r
+                  EFI_SIZE_TO_PAGES ((UINTN) FvHeader->FvLength),\r
+                  (EFI_PHYSICAL_ADDRESS *) &MigratedFvHeader\r
+                  );\r
+      ASSERT_EFI_ERROR (Status);\r
+\r
+      DEBUG ((\r
+        DEBUG_VERBOSE,\r
+        "  Migrating FV[%d] from 0x%08X to 0x%08X\n",\r
+        FvIndex,\r
+        (UINTN) FvHeader,\r
+        (UINTN) MigratedFvHeader\r
+        ));\r
+\r
+      CopyMem (MigratedFvHeader, FvHeader, (UINTN) FvHeader->FvLength);\r
+\r
+      //\r
+      // Migrate any children for this FV now\r
+      //\r
+      for (FvChildIndex = FvIndex; FvChildIndex < Private->FvCount; FvChildIndex++) {\r
+        ChildFvHeader = Private->Fv[FvChildIndex].FvHeader;\r
+        if (\r
+          ((UINTN) ChildFvHeader > (UINTN) FvHeader) &&\r
+          (((UINTN) ChildFvHeader + ChildFvHeader->FvLength) < ((UINTN) FvHeader) + FvHeader->FvLength)\r
+          ) {\r
+          DEBUG ((DEBUG_VERBOSE, "    Child FV[%02d] is being migrated.\n", FvChildIndex));\r
+          ChildFvOffset = (UINTN) ChildFvHeader - (UINTN) FvHeader;\r
+          DEBUG ((DEBUG_VERBOSE, "    Child FV offset = 0x%x.\n", ChildFvOffset));\r
+          MigratedChildFvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) MigratedFvHeader + ChildFvOffset);\r
+          Private->Fv[FvChildIndex].FvHeader = MigratedChildFvHeader;\r
+          Private->Fv[FvChildIndex].FvHandle = (EFI_PEI_FV_HANDLE) MigratedChildFvHeader;\r
+          DEBUG ((DEBUG_VERBOSE, "    Child migrated FV header at 0x%x.\n", (UINTN) MigratedChildFvHeader));\r
+\r
+          Status =  MigratePeimsInFv (Private, FvChildIndex, (UINTN) ChildFvHeader, (UINTN) MigratedChildFvHeader);\r
+          ASSERT_EFI_ERROR (Status);\r
+\r
+          ConvertPpiPointersFv (\r
+            Private,\r
+            (UINTN) ChildFvHeader,\r
+            (UINTN) MigratedChildFvHeader,\r
+            (UINTN) ChildFvHeader->FvLength - 1\r
+            );\r
+\r
+          ConvertStatusCodeCallbacks (\r
+            (UINTN) ChildFvHeader,\r
+            (UINTN) MigratedChildFvHeader,\r
+            (UINTN) ChildFvHeader->FvLength - 1\r
+            );\r
+\r
+          ConvertFvHob (Private, (UINTN) ChildFvHeader, (UINTN) MigratedChildFvHeader);\r
+        }\r
+      }\r
+      Private->Fv[FvIndex].FvHeader = MigratedFvHeader;\r
+      Private->Fv[FvIndex].FvHandle = (EFI_PEI_FV_HANDLE) MigratedFvHeader;\r
+\r
+      Status = MigratePeimsInFv (Private, FvIndex, (UINTN) FvHeader, (UINTN) MigratedFvHeader);\r
+      ASSERT_EFI_ERROR (Status);\r
+\r
+      ConvertPpiPointersFv (\r
+        Private,\r
+        (UINTN) FvHeader,\r
+        (UINTN) MigratedFvHeader,\r
+        (UINTN) FvHeader->FvLength - 1\r
+        );\r
+\r
+      ConvertStatusCodeCallbacks (\r
+        (UINTN) FvHeader,\r
+        (UINTN) MigratedFvHeader,\r
+        (UINTN) FvHeader->FvLength - 1\r
+        );\r
+\r
+      ConvertFvHob (Private, (UINTN) FvHeader, (UINTN) MigratedFvHeader);\r
+    }\r
+  }\r
+\r
+  RemoveFvHobsInTemporaryMemory (Private);\r
+\r
+  return Status;\r
+}\r
+\r
 /**\r
   Conduct PEIM dispatch.\r
 \r
@@ -988,7 +1391,11 @@ PeiDispatcher (
   PeimFileHandle = NULL;\r
   EntryPoint     = 0;\r
 \r
-  if ((Private->PeiMemoryInstalled) && (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME || PcdGetBool (PcdShadowPeimOnS3Boot))) {\r
+  if ((Private->PeiMemoryInstalled) &&\r
+      (PcdGetBool (PcdMigrateTemporaryRamFirmwareVolumes) ||\r
+       (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME) ||\r
+       PcdGetBool (PcdShadowPeimOnS3Boot))\r
+    ) {\r
     //\r
     // Once real memory is available, shadow the RegisterForShadow modules. And meanwhile\r
     // update the modules' status from PEIM_STATE_REGISTER_FOR_SHADOW to PEIM_STATE_DONE.\r
@@ -1187,13 +1594,17 @@ PeiDispatcher (
             PeiCheckAndSwitchStack (SecCoreData, Private);\r
 \r
             if ((Private->PeiMemoryInstalled) && (Private->Fv[FvCount].PeimState[PeimCount] == PEIM_STATE_REGISTER_FOR_SHADOW) &&   \\r
-                (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME || PcdGetBool (PcdShadowPeimOnS3Boot))) {\r
+                (PcdGetBool (PcdMigrateTemporaryRamFirmwareVolumes) ||\r
+                 (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME) ||\r
+                 PcdGetBool (PcdShadowPeimOnS3Boot))\r
+              ) {\r
               //\r
               // If memory is available we shadow images by default for performance reasons.\r
               // We call the entry point a 2nd time so the module knows it's shadowed.\r
               //\r
               //PERF_START (PeiServices, L"PEIM", PeimFileHandle, 0);\r
-              if ((Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME) && !PcdGetBool (PcdShadowPeimOnBoot)) {\r
+              if ((Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME) && !PcdGetBool (PcdShadowPeimOnBoot) &&\r
+                  !PcdGetBool (PcdMigrateTemporaryRamFirmwareVolumes)) {\r
                 //\r
                 // Load PEIM into Memory for Register for shadow PEIM.\r
                 //\r