]> git.proxmox.com Git - mirror_edk2.git/blobdiff - UefiCpuPkg/PiSmmCpuDxeSmm/SmmProfile.c
UefiCpuPkg/PiSmmCpuDxeSmm: [CVE-2017-5753] Fix bounds check bypass
[mirror_edk2.git] / UefiCpuPkg / PiSmmCpuDxeSmm / SmmProfile.c
index 1b84e2c5f3d0db1037886a83d383db90cdc15203..91b8e7ddb991d1948e66d903cfe21aea7896637f 100644 (file)
@@ -1,7 +1,7 @@
 /** @file\r
 Enable SMM profile.\r
 \r
-Copyright (c) 2012 - 2016, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2012 - 2018, Intel Corporation. All rights reserved.<BR>\r
 Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>\r
 \r
 This program and the accompanying materials\r
@@ -31,6 +31,11 @@ UINTN                     mSmmProfileSize;
 //\r
 UINTN                     mMsrDsAreaSize   = SMM_PROFILE_DTS_SIZE;\r
 \r
+//\r
+// The flag indicates if execute-disable is supported by processor.\r
+//\r
+BOOLEAN                   mXdSupported     = TRUE;\r
+\r
 //\r
 // The flag indicates if execute-disable is enabled on processor.\r
 //\r
@@ -46,6 +51,11 @@ BOOLEAN                   mBtsSupported     = TRUE;
 //\r
 BOOLEAN                   mSmmProfileStart = FALSE;\r
 \r
+//\r
+// The flag indicates if #DB will be setup in #PF handler.\r
+//\r
+BOOLEAN                   mSetupDebugTrap = FALSE;\r
+\r
 //\r
 // Record the page fault exception count for one instruction execution.\r
 //\r
@@ -82,6 +92,12 @@ MEMORY_PROTECTION_RANGE mProtectionMemRangeTemplate[] = {
   //\r
   {{0x00000000, 0x00000000},TRUE,TRUE},\r
 \r
+  //\r
+  // SMRAM ranges not covered by mCpuHotPlugData.SmrrBase/mCpuHotPlugData.SmrrSiz (to be fixed in runtime).\r
+  // It is always present and instruction fetches are allowed.\r
+  // {{0x00000000, 0x00000000},TRUE,FALSE},\r
+  //\r
+\r
   //\r
   // Future extended range could be added here.\r
   //\r
@@ -218,7 +234,9 @@ DebugExceptionHandler (
   UINTN  CpuIndex;\r
   UINTN  PFEntry;\r
 \r
-  if (!mSmmProfileStart) {\r
+  if (!mSmmProfileStart &&\r
+      !HEAP_GUARD_NONSTOP_MODE &&\r
+      !NULL_DETECTION_NONSTOP_MODE) {\r
     return;\r
   }\r
   CpuIndex = GetCpuIndex ();\r
@@ -246,6 +264,33 @@ DebugExceptionHandler (
   ClearTrapFlag (SystemContext);\r
 }\r
 \r
+/**\r
+  Check if the input address is in SMM ranges.\r
+\r
+  @param[in]  Address       The input address.\r
+\r
+  @retval TRUE     The input address is in SMM.\r
+  @retval FALSE    The input address is not in SMM.\r
+**/\r
+BOOLEAN\r
+IsInSmmRanges (\r
+  IN EFI_PHYSICAL_ADDRESS   Address\r
+  )\r
+{\r
+  UINTN  Index;\r
+\r
+  if ((Address >= mCpuHotPlugData.SmrrBase) && (Address < mCpuHotPlugData.SmrrBase + mCpuHotPlugData.SmrrSize)) {\r
+    return TRUE;\r
+  }\r
+  for (Index = 0; Index < mSmmCpuSmramRangeCount; Index++) {\r
+    if (Address >= mSmmCpuSmramRanges[Index].CpuStart &&\r
+        Address < mSmmCpuSmramRanges[Index].CpuStart + mSmmCpuSmramRanges[Index].PhysicalSize) {\r
+      return TRUE;\r
+    }\r
+  }\r
+  return FALSE;\r
+}\r
+\r
 /**\r
   Check if the memory address will be mapped by 4KB-page.\r
 \r
@@ -261,7 +306,6 @@ IsAddressValid (
 {\r
   UINTN  Index;\r
 \r
-  *Nx = FALSE;\r
   if (FeaturePcdGet (PcdCpuSmmProfileEnable)) {\r
     //\r
     // Check configuration\r
@@ -276,9 +320,9 @@ IsAddressValid (
     return FALSE;\r
 \r
   } else {\r
-    if ((Address < mCpuHotPlugData.SmrrBase) ||\r
-        (Address >= mCpuHotPlugData.SmrrBase + mCpuHotPlugData.SmrrSize)) {\r
-      *Nx = TRUE;\r
+    *Nx = TRUE;\r
+    if (IsInSmmRanges (Address)) {\r
+      *Nx = FALSE;\r
     }\r
     return TRUE;\r
   }\r
@@ -334,7 +378,7 @@ InitProtectedMemRange (
 {\r
   UINTN                            Index;\r
   UINTN                            NumberOfDescriptors;\r
-  UINTN                            NumberOfMmioDescriptors;\r
+  UINTN                            NumberOfAddedDescriptors;\r
   UINTN                            NumberOfProtectRange;\r
   UINTN                            NumberOfSpliteRange;\r
   EFI_GCD_MEMORY_SPACE_DESCRIPTOR  *MemorySpaceMap;\r
@@ -347,7 +391,7 @@ InitProtectedMemRange (
   UINT64                           Low4KBPageSize;\r
 \r
   NumberOfDescriptors      = 0;\r
-  NumberOfMmioDescriptors  = 0;\r
+  NumberOfAddedDescriptors = mSmmCpuSmramRangeCount;\r
   NumberOfSpliteRange      = 0;\r
   MemorySpaceMap           = NULL;\r
 \r
@@ -360,12 +404,12 @@ InitProtectedMemRange (
        );\r
   for (Index = 0; Index < NumberOfDescriptors; Index++) {\r
     if (MemorySpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) {\r
-      NumberOfMmioDescriptors++;\r
+      NumberOfAddedDescriptors++;\r
     }\r
   }\r
 \r
-  if (NumberOfMmioDescriptors != 0) {\r
-    TotalSize = NumberOfMmioDescriptors * sizeof (MEMORY_PROTECTION_RANGE) + sizeof (mProtectionMemRangeTemplate);\r
+  if (NumberOfAddedDescriptors != 0) {\r
+    TotalSize = NumberOfAddedDescriptors * sizeof (MEMORY_PROTECTION_RANGE) + sizeof (mProtectionMemRangeTemplate);\r
     mProtectionMemRange = (MEMORY_PROTECTION_RANGE *) AllocateZeroPool (TotalSize);\r
     ASSERT (mProtectionMemRange != NULL);\r
     mProtectionMemRangeCount = TotalSize / sizeof (MEMORY_PROTECTION_RANGE);\r
@@ -382,10 +426,28 @@ InitProtectedMemRange (
     mSplitMemRange = (MEMORY_RANGE *) AllocateZeroPool (TotalSize);\r
     ASSERT (mSplitMemRange != NULL);\r
 \r
+    //\r
+    // Create SMM ranges which are set to present and execution-enable.\r
+    //\r
+    NumberOfProtectRange = sizeof (mProtectionMemRangeTemplate) / sizeof (MEMORY_PROTECTION_RANGE);\r
+    for (Index = 0; Index < mSmmCpuSmramRangeCount; Index++) {\r
+      if (mSmmCpuSmramRanges[Index].CpuStart >= mProtectionMemRange[0].Range.Base &&\r
+          mSmmCpuSmramRanges[Index].CpuStart + mSmmCpuSmramRanges[Index].PhysicalSize < mProtectionMemRange[0].Range.Top) {\r
+        //\r
+        // If the address have been already covered by mCpuHotPlugData.SmrrBase/mCpuHotPlugData.SmrrSiz\r
+        //\r
+        break;\r
+      }\r
+      mProtectionMemRange[NumberOfProtectRange].Range.Base = mSmmCpuSmramRanges[Index].CpuStart;\r
+      mProtectionMemRange[NumberOfProtectRange].Range.Top  = mSmmCpuSmramRanges[Index].CpuStart + mSmmCpuSmramRanges[Index].PhysicalSize;\r
+      mProtectionMemRange[NumberOfProtectRange].Present    = TRUE;\r
+      mProtectionMemRange[NumberOfProtectRange].Nx         = FALSE;\r
+      NumberOfProtectRange++;\r
+    }\r
+\r
     //\r
     // Create MMIO ranges which are set to present and execution-disable.\r
     //\r
-    NumberOfProtectRange    = sizeof (mProtectionMemRangeTemplate) / sizeof (MEMORY_PROTECTION_RANGE);\r
     for (Index = 0; Index < NumberOfDescriptors; Index++) {\r
       if (MemorySpaceMap[Index].GcdMemoryType != EfiGcdMemoryTypeMemoryMappedIo) {\r
         continue;\r
@@ -396,6 +458,12 @@ InitProtectedMemRange (
       mProtectionMemRange[NumberOfProtectRange].Nx         = TRUE;\r
       NumberOfProtectRange++;\r
     }\r
+\r
+    //\r
+    // Check and updated actual protected memory ranges count\r
+    //\r
+    ASSERT (NumberOfProtectRange <= mProtectionMemRangeCount);\r
+    mProtectionMemRangeCount = NumberOfProtectRange;\r
   }\r
 \r
   //\r
@@ -657,84 +725,6 @@ InitPaging (
   return ;\r
 }\r
 \r
-/**\r
-  To find FADT in ACPI tables.\r
-\r
-  @param AcpiTableGuid   The GUID used to find ACPI table in UEFI ConfigurationTable.\r
-\r
-  @return  FADT table pointer.\r
-**/\r
-EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE  *\r
-FindAcpiFadtTableByAcpiGuid (\r
-  IN EFI_GUID  *AcpiTableGuid\r
-  )\r
-{\r
-  EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER  *Rsdp;\r
-  EFI_ACPI_DESCRIPTION_HEADER                   *Rsdt;\r
-  EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE     *Fadt;\r
-  UINTN                                         Index;\r
-  UINT32                                        Data32;\r
-  Rsdp  = NULL;\r
-  Rsdt  = NULL;\r
-  Fadt  = NULL;\r
-  //\r
-  // found ACPI table RSD_PTR from system table\r
-  //\r
-  for (Index = 0; Index < gST->NumberOfTableEntries; Index++) {\r
-    if (CompareGuid (&(gST->ConfigurationTable[Index].VendorGuid), AcpiTableGuid)) {\r
-      //\r
-      // A match was found.\r
-      //\r
-      Rsdp = gST->ConfigurationTable[Index].VendorTable;\r
-      break;\r
-    }\r
-  }\r
-\r
-  if (Rsdp == NULL) {\r
-    return NULL;\r
-  }\r
-\r
-  Rsdt = (EFI_ACPI_DESCRIPTION_HEADER *)(UINTN) Rsdp->RsdtAddress;\r
-  if (Rsdt == NULL || Rsdt->Signature != EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_TABLE_SIGNATURE) {\r
-    return NULL;\r
-  }\r
-\r
-  for (Index = sizeof (EFI_ACPI_DESCRIPTION_HEADER); Index < Rsdt->Length; Index = Index + sizeof (UINT32)) {\r
-\r
-    Data32  = *(UINT32 *) ((UINT8 *) Rsdt + Index);\r
-    Fadt    = (EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE *) (UINT32 *) (UINTN) Data32;\r
-    if (Fadt->Header.Signature == EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE) {\r
-      break;\r
-    }\r
-  }\r
-\r
-  if (Fadt == NULL || Fadt->Header.Signature != EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE) {\r
-    return NULL;\r
-  }\r
-\r
-  return Fadt;\r
-}\r
-\r
-/**\r
-  To find FADT in ACPI tables.\r
-\r
-  @return  FADT table pointer.\r
-**/\r
-EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE  *\r
-FindAcpiFadtTable (\r
-  VOID\r
-  )\r
-{\r
-  EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE *Fadt;\r
-\r
-  Fadt = FindAcpiFadtTableByAcpiGuid (&gEfiAcpi20TableGuid);\r
-  if (Fadt != NULL) {\r
-    return Fadt;\r
-  }\r
-\r
-  return FindAcpiFadtTableByAcpiGuid (&gEfiAcpi10TableGuid);\r
-}\r
-\r
 /**\r
   To get system port address of the SMI Command Port in FADT table.\r
 \r
@@ -746,7 +736,9 @@ GetSmiCommandPort (
 {\r
   EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE *Fadt;\r
 \r
-  Fadt = FindAcpiFadtTable ();\r
+  Fadt = (EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE *) EfiLocateFirstAcpiTable (\r
+                                                         EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE\r
+                                                         );\r
   ASSERT (Fadt != NULL);\r
 \r
   mSmiCommandPort = Fadt->SmiCmd;\r
@@ -954,6 +946,7 @@ CheckFeatureSupported (
       // Extended CPUID functions are not supported on this processor.\r
       //\r
       mXdSupported = FALSE;\r
+      PatchInstructionX86 (gPatchXdSupported, mXdSupported, 1);\r
     }\r
 \r
     AsmCpuid (CPUID_EXTENDED_CPU_SIG, NULL, NULL, NULL, &RegEdx);\r
@@ -962,6 +955,7 @@ CheckFeatureSupported (
       // Execute Disable Bit feature is not supported on this processor.\r
       //\r
       mXdSupported = FALSE;\r
+      PatchInstructionX86 (gPatchXdSupported, mXdSupported, 1);\r
     }\r
   }\r
 \r
@@ -1111,7 +1105,9 @@ InitSmmProfile (
   //\r
   // Skip SMM profile initialization if feature is disabled\r
   //\r
-  if (!FeaturePcdGet (PcdCpuSmmProfileEnable)) {\r
+  if (!FeaturePcdGet (PcdCpuSmmProfileEnable) &&\r
+      !HEAP_GUARD_NONSTOP_MODE &&\r
+      !NULL_DETECTION_NONSTOP_MODE) {\r
     return;\r
   }\r
 \r
@@ -1124,6 +1120,11 @@ InitSmmProfile (
   // Initialize profile IDT.\r
   //\r
   InitIdtr ();\r
+\r
+  //\r
+  // Tell #PF handler to prepare a #DB subsequently.\r
+  //\r
+  mSetupDebugTrap = TRUE;\r
 }\r
 \r
 /**\r
@@ -1231,6 +1232,46 @@ RestorePageTableBelow4G (
   }\r
 }\r
 \r
+/**\r
+  Handler for Page Fault triggered by Guard page.\r
+\r
+  @param  ErrorCode  The Error code of exception.\r
+\r
+**/\r
+VOID\r
+GuardPagePFHandler (\r
+  UINTN ErrorCode\r
+  )\r
+{\r
+  UINT64                *PageTable;\r
+  UINT64                PFAddress;\r
+  UINT64                RestoreAddress;\r
+  UINTN                 RestorePageNumber;\r
+  UINTN                 CpuIndex;\r
+\r
+  PageTable         = (UINT64 *)AsmReadCr3 ();\r
+  PFAddress         = AsmReadCr2 ();\r
+  CpuIndex          = GetCpuIndex ();\r
+\r
+  //\r
+  // Memory operation cross pages, like "rep mov" instruction, will cause\r
+  // infinite loop between this and Debug Trap handler. We have to make sure\r
+  // that current page and the page followed are both in PRESENT state.\r
+  //\r
+  RestorePageNumber = 2;\r
+  RestoreAddress = PFAddress;\r
+  while (RestorePageNumber > 0) {\r
+    RestorePageTableBelow4G (PageTable, RestoreAddress, CpuIndex, ErrorCode);\r
+    RestoreAddress += EFI_PAGE_SIZE;\r
+    RestorePageNumber--;\r
+  }\r
+\r
+  //\r
+  // Flush TLB\r
+  //\r
+  CpuFlushTlb ();\r
+}\r
+\r
 /**\r
   The Page fault handler to save SMM profile data.\r
 \r
@@ -1246,6 +1287,8 @@ SmmProfilePFHandler (
 {\r
   UINT64                *PageTable;\r
   UINT64                PFAddress;\r
+  UINT64                RestoreAddress;\r
+  UINTN                 RestorePageNumber;\r
   UINTN                 CpuIndex;\r
   UINTN                 Index;\r
   UINT64                InstructionAddress;\r
@@ -1275,10 +1318,21 @@ SmmProfilePFHandler (
   PFAddress         = AsmReadCr2 ();\r
   CpuIndex          = GetCpuIndex ();\r
 \r
-  if (PFAddress <= 0xFFFFFFFF) {\r
-    RestorePageTableBelow4G (PageTable, PFAddress, CpuIndex, ErrorCode);\r
-  } else {\r
-    RestorePageTableAbove4G (PageTable, PFAddress, CpuIndex, ErrorCode, &IsValidPFAddress);\r
+  //\r
+  // Memory operation cross pages, like "rep mov" instruction, will cause\r
+  // infinite loop between this and Debug Trap handler. We have to make sure\r
+  // that current page and the page followed are both in PRESENT state.\r
+  //\r
+  RestorePageNumber = 2;\r
+  RestoreAddress = PFAddress;\r
+  while (RestorePageNumber > 0) {\r
+    if (RestoreAddress <= 0xFFFFFFFF) {\r
+      RestorePageTableBelow4G (PageTable, RestoreAddress, CpuIndex, ErrorCode);\r
+    } else {\r
+      RestorePageTableAbove4G (PageTable, RestoreAddress, CpuIndex, ErrorCode, &IsValidPFAddress);\r
+    }\r
+    RestoreAddress += EFI_PAGE_SIZE;\r
+    RestorePageNumber--;\r
   }\r
 \r
   if (!IsValidPFAddress) {\r