diff --git a/MdeModulePkg/Core/Dxe/Gcd/Gcd.c b/MdeModulePkg/Core/Dxe/Gcd/Gcd.c index 8fbc3d282c..77f4adb4bc 100644 --- a/MdeModulePkg/Core/Dxe/Gcd/Gcd.c +++ b/MdeModulePkg/Core/Dxe/Gcd/Gcd.c @@ -16,6 +16,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include "DxeMain.h" #include "Gcd.h" +#include "Mem/HeapGuard.h" #define MINIMUM_INITIAL_MEMORY_SIZE 0x10000 @@ -391,12 +392,21 @@ CoreAllocateGcdMapEntry ( IN OUT EFI_GCD_MAP_ENTRY **BottomEntry ) { + // + // Set to mOnGuarding to TRUE before memory allocation. This will make sure + // that the entry memory is not "guarded" by HeapGuard. Otherwise it might + // cause problem when it's freed (if HeapGuard is enabled). + // + mOnGuarding = TRUE; *TopEntry = AllocateZeroPool (sizeof (EFI_GCD_MAP_ENTRY)); + mOnGuarding = FALSE; if (*TopEntry == NULL) { return EFI_OUT_OF_RESOURCES; } + mOnGuarding = TRUE; *BottomEntry = AllocateZeroPool (sizeof (EFI_GCD_MAP_ENTRY)); + mOnGuarding = FALSE; if (*BottomEntry == NULL) { CoreFreePool (*TopEntry); return EFI_OUT_OF_RESOURCES; diff --git a/MdeModulePkg/Core/Dxe/Mem/HeapGuard.c b/MdeModulePkg/Core/Dxe/Mem/HeapGuard.c index ac043b5d9b..f6068c459c 100644 --- a/MdeModulePkg/Core/Dxe/Mem/HeapGuard.c +++ b/MdeModulePkg/Core/Dxe/Mem/HeapGuard.c @@ -576,6 +576,10 @@ SetGuardPage ( IN EFI_PHYSICAL_ADDRESS BaseAddress ) { + if (gCpu == NULL) { + return; + } + // // Set flag to make sure allocating memory without GUARD for page table // operation; otherwise infinite loops could be caused. @@ -606,6 +610,10 @@ UnsetGuardPage ( { UINT64 Attributes; + if (gCpu == NULL) { + return; + } + // // Once the Guard page is unset, it will be freed back to memory pool. NX // memory protection must be restored for this page if NX is enabled for free @@ -652,7 +660,7 @@ IsMemoryTypeToGuard ( UINT64 ConfigBit; BOOLEAN InSmm; - if (gCpu == NULL || AllocateType == AllocateAddress) { + if (AllocateType == AllocateAddress) { return FALSE; } @@ -1164,6 +1172,128 @@ CoreConvertPagesWithGuard ( return CoreConvertPages (Start, NumberOfPages, NewType); } +/** + Set all Guard pages which cannot be set before CPU Arch Protocol installed. +**/ +VOID +SetAllGuardPages ( + VOID + ) +{ + UINTN Entries[GUARDED_HEAP_MAP_TABLE_DEPTH]; + UINTN Shifts[GUARDED_HEAP_MAP_TABLE_DEPTH]; + UINTN Indices[GUARDED_HEAP_MAP_TABLE_DEPTH]; + UINT64 Tables[GUARDED_HEAP_MAP_TABLE_DEPTH]; + UINT64 Addresses[GUARDED_HEAP_MAP_TABLE_DEPTH]; + UINT64 TableEntry; + UINT64 Address; + UINT64 GuardPage; + INTN Level; + UINTN Index; + BOOLEAN OnGuarding; + + if (mGuardedMemoryMap == 0 || + mMapLevel == 0 || + mMapLevel > GUARDED_HEAP_MAP_TABLE_DEPTH) { + return; + } + + CopyMem (Entries, mLevelMask, sizeof (Entries)); + CopyMem (Shifts, mLevelShift, sizeof (Shifts)); + + SetMem (Tables, sizeof(Tables), 0); + SetMem (Addresses, sizeof(Addresses), 0); + SetMem (Indices, sizeof(Indices), 0); + + Level = GUARDED_HEAP_MAP_TABLE_DEPTH - mMapLevel; + Tables[Level] = mGuardedMemoryMap; + Address = 0; + OnGuarding = FALSE; + + DEBUG_CODE ( + DumpGuardedMemoryBitmap (); + ); + + while (TRUE) { + if (Indices[Level] > Entries[Level]) { + Tables[Level] = 0; + Level -= 1; + } else { + + TableEntry = ((UINT64 *)(UINTN)(Tables[Level]))[Indices[Level]]; + Address = Addresses[Level]; + + if (TableEntry == 0) { + + OnGuarding = FALSE; + + } else if (Level < GUARDED_HEAP_MAP_TABLE_DEPTH - 1) { + + Level += 1; + Tables[Level] = TableEntry; + Addresses[Level] = Address; + Indices[Level] = 0; + + continue; + + } else { + + Index = 0; + while (Index < GUARDED_HEAP_MAP_ENTRY_BITS) { + if ((TableEntry & 1) == 1) { + if (OnGuarding) { + GuardPage = 0; + } else { + GuardPage = Address - EFI_PAGE_SIZE; + } + OnGuarding = TRUE; + } else { + if (OnGuarding) { + GuardPage = Address; + } else { + GuardPage = 0; + } + OnGuarding = FALSE; + } + + if (GuardPage != 0) { + SetGuardPage (GuardPage); + } + + if (TableEntry == 0) { + break; + } + + TableEntry = RShiftU64 (TableEntry, 1); + Address += EFI_PAGE_SIZE; + Index += 1; + } + } + } + + if (Level < (GUARDED_HEAP_MAP_TABLE_DEPTH - (INTN)mMapLevel)) { + break; + } + + Indices[Level] += 1; + Address = (Level == 0) ? 0 : Addresses[Level - 1]; + Addresses[Level] = Address | LShiftU64(Indices[Level], Shifts[Level]); + + } +} + +/** + Notify function used to set all Guard pages before CPU Arch Protocol installed. +**/ +VOID +HeapGuardCpuArchProtocolNotify ( + VOID + ) +{ + ASSERT (gCpu != NULL); + SetAllGuardPages (); +} + /** Helper function to convert a UINT64 value in binary to a string. diff --git a/MdeModulePkg/Core/Dxe/Mem/HeapGuard.h b/MdeModulePkg/Core/Dxe/Mem/HeapGuard.h index 7208ab1437..8c34692439 100644 --- a/MdeModulePkg/Core/Dxe/Mem/HeapGuard.h +++ b/MdeModulePkg/Core/Dxe/Mem/HeapGuard.h @@ -399,6 +399,14 @@ IsHeapGuardEnabled ( VOID ); +/** + Notify function used to set all Guard pages after CPU Arch Protocol installed. +**/ +VOID +HeapGuardCpuArchProtocolNotify ( + VOID + ); + extern BOOLEAN mOnGuarding; #endif diff --git a/MdeModulePkg/Core/Dxe/Misc/MemoryProtection.c b/MdeModulePkg/Core/Dxe/Misc/MemoryProtection.c index 407aece807..2f7e490af1 100644 --- a/MdeModulePkg/Core/Dxe/Misc/MemoryProtection.c +++ b/MdeModulePkg/Core/Dxe/Misc/MemoryProtection.c @@ -1001,6 +1001,11 @@ MemoryProtectionCpuArchProtocolNotify ( InitializeDxeNxMemoryProtectionPolicy (); } + // + // Call notify function meant for Heap Guard. + // + HeapGuardCpuArchProtocolNotify (); + if (mImageProtectionPolicy == 0) { return; }