]> git.proxmox.com Git - mirror_edk2.git/commitdiff
MdeModulePkg/DxeIpl: Implement NULL pointer detection
authorJian J Wang <jian.j.wang@intel.com>
Mon, 9 Oct 2017 13:56:32 +0000 (21:56 +0800)
committerEric Dong <eric.dong@intel.com>
Wed, 11 Oct 2017 08:39:00 +0000 (16:39 +0800)
NULL pointer detection is done by making use of paging mechanism of CPU.
During page table setup, if enabled, the first 4-K page (0-4095) will be
marked as NOT PRESENT. Any code which unintentionally access memory between
0-4095 will trigger a Page Fault exception which warns users that there's
potential illegal code in BIOS.

This also means that legacy code which has to access memory between 0-4095
should be cautious to temporarily disable this feature before the access
and re-enable it afterwards; or disalbe this feature at all.

Cc: Star Zeng <star.zeng@intel.com>
Cc: Eric Dong <eric.dong@intel.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Michael Kinney <michael.d.kinney@intel.com>
Cc: Ayellet Wolman <ayellet.wolman@intel.com>
Suggested-by: Ayellet Wolman <ayellet.wolman@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
Reviewed-by: Star Zeng <star.zeng@intel.com>
Reviewed-by: Jiewen Yao <jiewen.yao@intel.com>
MdeModulePkg/Core/DxeIplPeim/DxeIpl.h
MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf
MdeModulePkg/Core/DxeIplPeim/DxeLoad.c
MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c
MdeModulePkg/Core/DxeIplPeim/X64/DxeLoadFunc.c
MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c

index 72d2532f50a0c08e7afb87ddb4da74162522b80d..ecf186667a1c03375ab40a1f9a89f704377ef937 100644 (file)
@@ -240,4 +240,29 @@ Decompress (
   OUT       UINTN                   *OutputSize\r
   );\r
 \r
+/**\r
+   Clear legacy memory located at the first 4K-page.\r
+\r
+   This function traverses the whole HOB list to check if memory from 0 to 4095\r
+   exists and has not been allocated, and then clear it if so.\r
+\r
+   @param HoStart         The start of HobList passed to DxeCore.\r
+\r
+**/\r
+VOID\r
+ClearFirst4KPage (\r
+  IN  VOID *HobStart\r
+  );\r
+\r
+/**\r
+   Return configure status of NULL pointer detection feature\r
+\r
+   @return TRUE   NULL pointer detection feature is enabled\r
+   @return FALSE  NULL pointer detection feature is disabled\r
+**/\r
+BOOLEAN\r
+IsNullDetectionEnabled (\r
+  VOID\r
+  );\r
+\r
 #endif\r
index c54afe4aa6adbd64b4627562289ed937d8f255bd..9d0e76a2936fa3036c3bf073e6359765c472ff46 100644 (file)
 [Pcd.IA32,Pcd.X64]\r
   gEfiMdeModulePkgTokenSpaceGuid.PcdUse1GPageTable                      ## SOMETIMES_CONSUMES\r
   gEfiMdeModulePkgTokenSpaceGuid.PcdPteMemoryEncryptionAddressOrMask    ## CONSUMES\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdNullPointerDetectionPropertyMask    ## CONSUMES\r
 \r
 [Pcd.IA32,Pcd.X64,Pcd.ARM,Pcd.AARCH64]\r
   gEfiMdeModulePkgTokenSpaceGuid.PcdSetNxForStack               ## SOMETIMES_CONSUMES\r
index 50b5440d15035ffe3cd121e51301ed2d55db2c10..1f626a9e8658211e07ea49e898cc7a0a5ede0f61 100644 (file)
@@ -825,3 +825,4 @@ UpdateStackHob (
     Hob.Raw = GET_NEXT_HOB (Hob);\r
   }\r
 }\r
+\r
index 1957326caf6247f0cde76d316e34952cb3d5837d..96f57184447061b02831ac09cf755e857fcbb7b8 100644 (file)
@@ -123,7 +123,9 @@ Create4GPageTablesIa32Pae (
     PageDirectoryPointerEntry->Bits.Present = 1;\r
 \r
     for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512; IndexOfPageDirectoryEntries++, PageDirectoryEntry++, PhysicalAddress += SIZE_2MB) {\r
-      if ((PhysicalAddress < StackBase + StackSize) && ((PhysicalAddress + SIZE_2MB) > StackBase)) {\r
+      if ((IsNullDetectionEnabled () && PhysicalAddress == 0)\r
+          || ((PhysicalAddress < StackBase + StackSize)\r
+              && ((PhysicalAddress + SIZE_2MB) > StackBase))) {\r
         //\r
         // Need to split this 2M page that covers stack range.\r
         //\r
@@ -240,6 +242,10 @@ HandOffToDxeCore (
   EFI_PEI_VECTOR_HANDOFF_INFO_PPI *VectorHandoffInfoPpi;\r
   BOOLEAN                   BuildPageTablesIa32Pae;\r
 \r
+  if (IsNullDetectionEnabled ()) {\r
+    ClearFirst4KPage (HobList.Raw);\r
+  }\r
+\r
   Status = PeiServicesAllocatePages (EfiBootServicesData, EFI_SIZE_TO_PAGES (STACK_SIZE), &BaseOfStack);\r
   ASSERT_EFI_ERROR (Status);\r
 \r
@@ -379,10 +385,15 @@ HandOffToDxeCore (
     TopOfStack = (EFI_PHYSICAL_ADDRESS) (UINTN) ALIGN_POINTER (TopOfStack, CPU_STACK_ALIGNMENT);\r
 \r
     PageTables = 0;\r
-    BuildPageTablesIa32Pae = (BOOLEAN) (PcdGetBool (PcdSetNxForStack) && IsIa32PaeSupport () && IsExecuteDisableBitAvailable ());\r
+    BuildPageTablesIa32Pae = (BOOLEAN) (IsIa32PaeSupport () &&\r
+                                        (IsNullDetectionEnabled () ||\r
+                                         (PcdGetBool (PcdSetNxForStack) &&\r
+                                          IsExecuteDisableBitAvailable ())));\r
     if (BuildPageTablesIa32Pae) {\r
       PageTables = Create4GPageTablesIa32Pae (BaseOfStack, STACK_SIZE);\r
-      EnableExecuteDisableBit ();\r
+      if (IsExecuteDisableBitAvailable ()) {\r
+        EnableExecuteDisableBit();\r
+      }\r
     }\r
 \r
     //\r
index 6488880eab9ca3b670d2e75fbea9a40e9e5d96e2..f613221b81dd04cbecc11bc658a68ebb0aa25619 100644 (file)
@@ -42,6 +42,10 @@ HandOffToDxeCore (
   EFI_VECTOR_HANDOFF_INFO         *VectorInfo;\r
   EFI_PEI_VECTOR_HANDOFF_INFO_PPI *VectorHandoffInfoPpi;\r
 \r
+  if (IsNullDetectionEnabled ()) {\r
+    ClearFirst4KPage (HobList.Raw);\r
+  }\r
+\r
   //\r
   // Get Vector Hand-off Info PPI and build Guided HOB\r
   //\r
index 48150be4e1c8bdfa724399c87ab330e8198108a0..a10dea25fd7fd2c65dfa7c6f3bf51426922ac1e1 100644 (file)
@@ -31,6 +31,68 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 #include "DxeIpl.h"\r
 #include "VirtualMemory.h"\r
 \r
+/**\r
+   Clear legacy memory located at the first 4K-page, if available.\r
+\r
+   This function traverses the whole HOB list to check if memory from 0 to 4095\r
+   exists and has not been allocated, and then clear it if so.\r
+\r
+   @param HoStart                   The start of HobList passed to DxeCore.\r
+\r
+**/\r
+VOID\r
+ClearFirst4KPage (\r
+  IN  VOID *HobStart\r
+  )\r
+{\r
+  EFI_PEI_HOB_POINTERS          RscHob;\r
+  EFI_PEI_HOB_POINTERS          MemHob;\r
+  BOOLEAN                       DoClear;\r
+\r
+  RscHob.Raw = HobStart;\r
+  MemHob.Raw = HobStart;\r
+  DoClear = FALSE;\r
+\r
+  //\r
+  // Check if page 0 exists and free\r
+  //\r
+  while ((RscHob.Raw = GetNextHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR,\r
+                                   RscHob.Raw)) != NULL) {\r
+    if (RscHob.ResourceDescriptor->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY &&\r
+        RscHob.ResourceDescriptor->PhysicalStart == 0) {\r
+      DoClear = TRUE;\r
+      //\r
+      // Make sure memory at 0-4095 has not been allocated.\r
+      //\r
+      while ((MemHob.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION,\r
+                                       MemHob.Raw)) != NULL) {\r
+        if (MemHob.MemoryAllocation->AllocDescriptor.MemoryBaseAddress\r
+            < EFI_PAGE_SIZE) {\r
+          DoClear = FALSE;\r
+          break;\r
+        }\r
+        MemHob.Raw = GET_NEXT_HOB (MemHob);\r
+      }\r
+      break;\r
+    }\r
+    RscHob.Raw = GET_NEXT_HOB (RscHob);\r
+  }\r
+\r
+  if (DoClear) {\r
+    DEBUG ((DEBUG_INFO, "Clearing first 4K-page!\r\n"));\r
+    SetMem (NULL, EFI_PAGE_SIZE, 0);\r
+  }\r
+\r
+  return;\r
+}\r
+\r
+BOOLEAN\r
+IsNullDetectionEnabled (\r
+  VOID\r
+  )\r
+{\r
+  return ((PcdGet8 (PcdNullPointerDetectionPropertyMask) & BIT0) != 0);\r
+}\r
 \r
 /**\r
   Enable Execute Disable Bit.\r
@@ -90,8 +152,16 @@ Split2MPageTo4K (
     //\r
     PageTableEntry->Uint64 = (UINT64) PhysicalAddress4K | AddressEncMask;\r
     PageTableEntry->Bits.ReadWrite = 1;\r
-    PageTableEntry->Bits.Present = 1;\r
-    if ((PhysicalAddress4K >= StackBase) && (PhysicalAddress4K < StackBase + StackSize)) {\r
+\r
+    if (IsNullDetectionEnabled () && PhysicalAddress4K == 0) {\r
+      PageTableEntry->Bits.Present = 0;\r
+    } else {\r
+      PageTableEntry->Bits.Present = 1;\r
+    }\r
+\r
+    if (PcdGetBool (PcdSetNxForStack)\r
+        && (PhysicalAddress4K >= StackBase)\r
+        && (PhysicalAddress4K < StackBase + StackSize)) {\r
       //\r
       // Set Nx bit for stack.\r
       //\r
@@ -137,9 +207,12 @@ Split1GPageTo2M (
 \r
   PhysicalAddress2M = PhysicalAddress;\r
   for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512; IndexOfPageDirectoryEntries++, PageDirectoryEntry++, PhysicalAddress2M += SIZE_2MB) {\r
-    if ((PhysicalAddress2M < StackBase + StackSize) && ((PhysicalAddress2M + SIZE_2MB) > StackBase)) {\r
+    if ((IsNullDetectionEnabled () && PhysicalAddress2M == 0)\r
+        || (PcdGetBool (PcdSetNxForStack)\r
+            && (PhysicalAddress2M < StackBase + StackSize)\r
+            && ((PhysicalAddress2M + SIZE_2MB) > StackBase))) {\r
       //\r
-      // Need to split this 2M page that covers stack range.\r
+      // Need to split this 2M page that covers NULL or stack range.\r
       //\r
       Split2MPageTo4K (PhysicalAddress2M, (UINT64 *) PageDirectoryEntry, StackBase, StackSize);\r
     } else {\r
@@ -279,7 +352,10 @@ CreateIdentityMappingPageTables (
       PageDirectory1GEntry = (VOID *) PageDirectoryPointerEntry;\r
     \r
       for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512; IndexOfPageDirectoryEntries++, PageDirectory1GEntry++, PageAddress += SIZE_1GB) {\r
-        if (PcdGetBool (PcdSetNxForStack) && (PageAddress < StackBase + StackSize) && ((PageAddress + SIZE_1GB) > StackBase)) {\r
+        if ((IsNullDetectionEnabled () && PageAddress == 0)\r
+            || (PcdGetBool (PcdSetNxForStack)\r
+                && (PageAddress < StackBase + StackSize)\r
+                && ((PageAddress + SIZE_1GB) > StackBase))) {\r
           Split1GPageTo2M (PageAddress, (UINT64 *) PageDirectory1GEntry, StackBase, StackSize);\r
         } else {\r
           //\r
@@ -308,9 +384,12 @@ CreateIdentityMappingPageTables (
         PageDirectoryPointerEntry->Bits.Present = 1;\r
 \r
         for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512; IndexOfPageDirectoryEntries++, PageDirectoryEntry++, PageAddress += SIZE_2MB) {\r
-          if (PcdGetBool (PcdSetNxForStack) && (PageAddress < StackBase + StackSize) && ((PageAddress + SIZE_2MB) > StackBase)) {\r
+          if ((IsNullDetectionEnabled () && PageAddress == 0)\r
+              || (PcdGetBool (PcdSetNxForStack)\r
+                  && (PageAddress < StackBase + StackSize)\r
+                  && ((PageAddress + SIZE_2MB) > StackBase))) {\r
             //\r
-            // Need to split this 2M page that covers stack range.\r
+            // Need to split this 2M page that covers NULL or stack range.\r
             //\r
             Split2MPageTo4K (PageAddress, (UINT64 *) PageDirectoryEntry, StackBase, StackSize);\r
           } else {\r