]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Core/Dxe/Mem/Page.c
MdeModulePkg/DxeCore: Implement heap guard feature for UEFI
[mirror_edk2.git] / MdeModulePkg / Core / Dxe / Mem / Page.c
index c9219cc068b392c14052d77f0548715a86399146..f1e4a37f2af644ca0b673d60f65e824671d90c8a 100644 (file)
@@ -14,6 +14,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 \r
 #include "DxeMain.h"\r
 #include "Imem.h"\r
+#include "HeapGuard.h"
 \r
 //\r
 // Entry for tracking the memory regions for each memory type to coalesce similar memory types\r
@@ -287,9 +288,12 @@ AllocateMemoryMapEntry (
     //\r
     // The list is empty, to allocate one page to refuel the list\r
     //\r
-    FreeDescriptorEntries = CoreAllocatePoolPages (EfiBootServicesData,\r
+    FreeDescriptorEntries = CoreAllocatePoolPages (
+                              EfiBootServicesData,
                               EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION_GRANULARITY),\r
-                              DEFAULT_PAGE_ALLOCATION_GRANULARITY);\r
+                              DEFAULT_PAGE_ALLOCATION_GRANULARITY,
+                              FALSE
+                              );
     if (FreeDescriptorEntries != NULL) {\r
       //\r
       // Enque the free memmory map entries into the list\r
@@ -896,17 +900,41 @@ CoreConvertPagesEx (
     //\r
     CoreAddRange (MemType, Start, RangeEnd, Attribute);\r
     if (ChangingType && (MemType == EfiConventionalMemory)) {\r
-      //\r
-      // Avoid calling DEBUG_CLEAR_MEMORY() for an address of 0 because this\r
-      // macro will ASSERT() if address is 0.  Instead, CoreAddRange() guarantees\r
-      // that the page starting at address 0 is always filled with zeros.\r
-      //\r
       if (Start == 0) {\r
+        //
+        // Avoid calling DEBUG_CLEAR_MEMORY() for an address of 0 because this
+        // macro will ASSERT() if address is 0.  Instead, CoreAddRange()
+        // guarantees that the page starting at address 0 is always filled
+        // with zeros.
+        //
         if (RangeEnd > EFI_PAGE_SIZE) {\r
           DEBUG_CLEAR_MEMORY ((VOID *)(UINTN) EFI_PAGE_SIZE, (UINTN) (RangeEnd - EFI_PAGE_SIZE + 1));\r
         }\r
       } else {\r
-        DEBUG_CLEAR_MEMORY ((VOID *)(UINTN) Start, (UINTN) (RangeEnd - Start + 1));\r
+        //
+        // If Heap Guard is enabled, the page at the top and/or bottom of
+        // this memory block to free might be inaccessible. Skipping them
+        // to avoid page fault exception.
+        //
+        UINT64  StartToClear;
+        UINT64  EndToClear;
+
+        StartToClear = Start;
+        EndToClear   = RangeEnd;
+        if (PcdGet8 (PcdHeapGuardPropertyMask) & (BIT1|BIT0)) {
+          if (IsGuardPage(StartToClear)) {
+            StartToClear += EFI_PAGE_SIZE;
+          }
+          if (IsGuardPage (EndToClear)) {
+            EndToClear -= EFI_PAGE_SIZE;
+          }
+          ASSERT (EndToClear > StartToClear);
+        }
+
+        DEBUG_CLEAR_MEMORY(
+          (VOID *)(UINTN)StartToClear,
+          (UINTN)(EndToClear - StartToClear + 1)
+          );
       }\r
     }\r
 \r
@@ -993,6 +1021,7 @@ CoreUpdateMemoryAttributes (
   @param  NewType                The type of memory the range is going to be\r
                                  turned into\r
   @param  Alignment              Bits to align with\r
+  @param  NeedGuard              Flag to indicate Guard page is needed or not
 \r
   @return The base address of the range, or 0 if the range was not found\r
 \r
@@ -1003,7 +1032,8 @@ CoreFindFreePagesI (
   IN UINT64           MinAddress,\r
   IN UINT64           NumberOfPages,\r
   IN EFI_MEMORY_TYPE  NewType,\r
-  IN UINTN            Alignment\r
+  IN UINTN            Alignment,
+  IN BOOLEAN          NeedGuard
   )\r
 {\r
   UINT64          NumberOfBytes;\r
@@ -1095,6 +1125,17 @@ CoreFindFreePagesI (
       // If this is the best match so far remember it\r
       //\r
       if (DescEnd > Target) {\r
+        if (NeedGuard) {
+          DescEnd = AdjustMemoryS (
+                      DescEnd + 1 - DescNumberOfBytes,
+                      DescNumberOfBytes,
+                      NumberOfBytes
+                      );
+          if (DescEnd == 0) {
+            continue;
+          }
+        }
+
         Target = DescEnd;\r
       }\r
     }\r
@@ -1125,6 +1166,7 @@ CoreFindFreePagesI (
   @param  NewType                The type of memory the range is going to be\r
                                  turned into\r
   @param  Alignment              Bits to align with\r
+  @param  NeedGuard              Flag to indicate Guard page is needed or not
 \r
   @return The base address of the range, or 0 if the range was not found.\r
 \r
@@ -1134,7 +1176,8 @@ FindFreePages (
     IN UINT64           MaxAddress,\r
     IN UINT64           NoPages,\r
     IN EFI_MEMORY_TYPE  NewType,\r
-    IN UINTN            Alignment\r
+    IN UINTN            Alignment,
+    IN BOOLEAN          NeedGuard
     )\r
 {\r
   UINT64   Start;\r
@@ -1148,7 +1191,8 @@ FindFreePages (
               mMemoryTypeStatistics[NewType].BaseAddress, \r
               NoPages, \r
               NewType, \r
-              Alignment\r
+              Alignment,
+              NeedGuard
               );\r
     if (Start != 0) {\r
       return Start;\r
@@ -1159,7 +1203,8 @@ FindFreePages (
   // Attempt to find free pages in the default allocation bin\r
   //\r
   if (MaxAddress >= mDefaultMaximumAddress) {\r
-    Start = CoreFindFreePagesI (mDefaultMaximumAddress, 0, NoPages, NewType, Alignment);\r
+    Start = CoreFindFreePagesI (mDefaultMaximumAddress, 0, NoPages, NewType,
+                                Alignment, NeedGuard);
     if (Start != 0) {\r
       if (Start < mDefaultBaseAddress) {\r
         mDefaultBaseAddress = Start;\r
@@ -1174,7 +1219,8 @@ FindFreePages (
   // address range.  If this allocation fails, then there are not enough \r
   // resources anywhere to satisfy the request.\r
   //\r
-  Start = CoreFindFreePagesI (MaxAddress, 0, NoPages, NewType, Alignment);\r
+  Start = CoreFindFreePagesI (MaxAddress, 0, NoPages, NewType, Alignment,
+                              NeedGuard);
   if (Start != 0) {\r
     return Start;\r
   }\r
@@ -1189,7 +1235,7 @@ FindFreePages (
   //\r
   // If any memory resources were promoted, then re-attempt the allocation\r
   //\r
-  return FindFreePages (MaxAddress, NoPages, NewType, Alignment);\r
+  return FindFreePages (MaxAddress, NoPages, NewType, Alignment, NeedGuard);
 }\r
 \r
 \r
@@ -1202,6 +1248,7 @@ FindFreePages (
   @param  NumberOfPages          The number of pages to allocate\r
   @param  Memory                 A pointer to receive the base allocated memory\r
                                  address\r
+  @param  NeedGuard              Flag to indicate Guard page is needed or not
 \r
   @return Status. On success, Memory is filled in with the base address allocated\r
   @retval EFI_INVALID_PARAMETER  Parameters violate checking rules defined in\r
@@ -1217,7 +1264,8 @@ CoreInternalAllocatePages (
   IN EFI_ALLOCATE_TYPE      Type,\r
   IN EFI_MEMORY_TYPE        MemoryType,\r
   IN UINTN                  NumberOfPages,\r
-  IN OUT EFI_PHYSICAL_ADDRESS  *Memory\r
+  IN OUT EFI_PHYSICAL_ADDRESS  *Memory,
+  IN BOOLEAN                NeedGuard
   )\r
 {\r
   EFI_STATUS      Status;\r
@@ -1303,7 +1351,8 @@ CoreInternalAllocatePages (
   // If not a specific address, then find an address to allocate\r
   //\r
   if (Type != AllocateAddress) {\r
-    Start = FindFreePages (MaxAddress, NumberOfPages, MemoryType, Alignment);\r
+    Start = FindFreePages (MaxAddress, NumberOfPages, MemoryType, Alignment,
+                           NeedGuard);
     if (Start == 0) {\r
       Status = EFI_OUT_OF_RESOURCES;\r
       goto Done;\r
@@ -1313,12 +1362,19 @@ CoreInternalAllocatePages (
   //\r
   // Convert pages from FreeMemory to the requested type\r
   //\r
-  Status = CoreConvertPages (Start, NumberOfPages, MemoryType);\r
+  if (NeedGuard) {
+    Status = CoreConvertPagesWithGuard(Start, NumberOfPages, MemoryType);
+  } else {
+    Status = CoreConvertPages(Start, NumberOfPages, MemoryType);
+  }
 \r
 Done:\r
   CoreReleaseMemoryLock ();\r
 \r
   if (!EFI_ERROR (Status)) {\r
+    if (NeedGuard) {
+      SetGuardForMemory (Start, NumberOfPages);
+    }
     *Memory = Start;\r
   }\r
 \r
@@ -1353,8 +1409,11 @@ CoreAllocatePages (
   )\r
 {\r
   EFI_STATUS  Status;\r
+  BOOLEAN     NeedGuard;
 \r
-  Status = CoreInternalAllocatePages (Type, MemoryType, NumberOfPages, Memory);\r
+  NeedGuard = IsPageTypeToGuard (MemoryType, Type) && !mOnGuarding;
+  Status = CoreInternalAllocatePages (Type, MemoryType, NumberOfPages, Memory,
+                                      NeedGuard);
   if (!EFI_ERROR (Status)) {\r
     CoreUpdateProfile (\r
       (EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0),\r
@@ -1395,6 +1454,7 @@ CoreInternalFreePages (
   LIST_ENTRY      *Link;\r
   MEMORY_MAP      *Entry;\r
   UINTN           Alignment;\r
+  BOOLEAN         IsGuarded;
 \r
   //\r
   // Free the range\r
@@ -1404,6 +1464,7 @@ CoreInternalFreePages (
   //\r
   // Find the entry that the covers the range\r
   //\r
+  IsGuarded = FALSE;
   Entry = NULL;\r
   for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {\r
     Entry = CR(Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);\r
@@ -1440,14 +1501,20 @@ CoreInternalFreePages (
     *MemoryType = Entry->Type;\r
   }\r
 \r
-  Status = CoreConvertPages (Memory, NumberOfPages, EfiConventionalMemory);\r
-\r
-  if (EFI_ERROR (Status)) {\r
-    goto Done;\r
+  IsGuarded = IsPageTypeToGuard (Entry->Type, AllocateAnyPages) &&
+              IsMemoryGuarded (Memory);
+  if (IsGuarded) {
+    Status = CoreConvertPagesWithGuard (Memory, NumberOfPages,
+                                        EfiConventionalMemory);
+  } else {
+    Status = CoreConvertPages (Memory, NumberOfPages, EfiConventionalMemory);
   }\r
 \r
 Done:\r
   CoreReleaseMemoryLock ();\r
+  if (IsGuarded) {
+    UnsetGuardForMemory(Memory, NumberOfPages);
+  }
   return Status;\r
 }\r
 \r
@@ -1845,6 +1912,12 @@ Done:
 \r
   *MemoryMapSize = BufferSize;\r
 \r
+  DEBUG_CODE (
+    if (PcdGet8 (PcdHeapGuardPropertyMask) & (BIT1|BIT0)) {
+      DumpGuardedMemoryBitmap ();
+    }
+  );
+
   return Status;\r
 }\r
 \r
@@ -1856,6 +1929,7 @@ Done:
   @param  PoolType               The type of memory for the new pool pages\r
   @param  NumberOfPages          No of pages to allocate\r
   @param  Alignment              Bits to align.\r
+  @param  NeedGuard              Flag to indicate Guard page is needed or not
 \r
   @return The allocated memory, or NULL\r
 \r
@@ -1864,7 +1938,8 @@ VOID *
 CoreAllocatePoolPages (\r
   IN EFI_MEMORY_TYPE    PoolType,\r
   IN UINTN              NumberOfPages,\r
-  IN UINTN              Alignment\r
+  IN UINTN              Alignment,
+  IN BOOLEAN            NeedGuard
   )\r
 {\r
   UINT64            Start;\r
@@ -1872,7 +1947,8 @@ CoreAllocatePoolPages (
   //\r
   // Find the pages to convert\r
   //\r
-  Start = FindFreePages (MAX_ADDRESS, NumberOfPages, PoolType, Alignment);\r
+  Start = FindFreePages (MAX_ADDRESS, NumberOfPages, PoolType, Alignment,
+                         NeedGuard);
 \r
   //\r
   // Convert it to boot services data\r
@@ -1880,7 +1956,11 @@ CoreAllocatePoolPages (
   if (Start == 0) {\r
     DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "AllocatePoolPages: failed to allocate %d pages\n", (UINT32)NumberOfPages));\r
   } else {\r
-    CoreConvertPages (Start, NumberOfPages, PoolType);\r
+    if (NeedGuard) {
+      CoreConvertPagesWithGuard (Start, NumberOfPages, PoolType);
+    } else {
+      CoreConvertPages (Start, NumberOfPages, PoolType);
+    }
   }\r
 \r
   return (VOID *)(UINTN) Start;\r