X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=MdeModulePkg%2FCore%2FDxe%2FMem%2FHeapGuard.c;h=9377f620c5a5f39b7298a9754e761a300ba1c326;hb=7ef91af84c04b1e5a17631bd1811c9bc1945dfdc;hp=30a73fc04d15ffbfc64a4395a622845c524d4fb6;hpb=e63da9f033274843163908ccefa95c892d7944e5;p=mirror_edk2.git
diff --git a/MdeModulePkg/Core/Dxe/Mem/HeapGuard.c b/MdeModulePkg/Core/Dxe/Mem/HeapGuard.c
index 30a73fc04d..9377f620c5 100644
--- a/MdeModulePkg/Core/Dxe/Mem/HeapGuard.c
+++ b/MdeModulePkg/Core/Dxe/Mem/HeapGuard.c
@@ -1,14 +1,8 @@
/** @file
UEFI Heap Guard functions.
-Copyright (c) 2017, Intel Corporation. All rights reserved.
-This program and the accompanying materials
-are licensed and made available under the terms and conditions of the BSD License
-which accompanies this distribution. The full text of the license may be found at
-http://opensource.org/licenses/bsd-license.php
-
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+Copyright (c) 2017-2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent
**/
@@ -20,29 +14,34 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
// Global to avoid infinite reentrance of memory allocation when updating
// page table attributes, which may need allocate pages for new PDE/PTE.
//
-GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN mOnGuarding = FALSE;
+GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN mOnGuarding = FALSE;
//
// Pointer to table tracking the Guarded memory with bitmap, in which '1'
// is used to indicate memory guarded. '0' might be free memory or Guard
// page itself, depending on status of memory adjacent to it.
//
-GLOBAL_REMOVE_IF_UNREFERENCED UINT64 mGuardedMemoryMap = 0;
+GLOBAL_REMOVE_IF_UNREFERENCED UINT64 mGuardedMemoryMap = 0;
//
// Current depth level of map table pointed by mGuardedMemoryMap.
// mMapLevel must be initialized at least by 1. It will be automatically
// updated according to the address of memory just tracked.
//
-GLOBAL_REMOVE_IF_UNREFERENCED UINTN mMapLevel = 1;
+GLOBAL_REMOVE_IF_UNREFERENCED UINTN mMapLevel = 1;
//
// Shift and mask for each level of map table
//
-GLOBAL_REMOVE_IF_UNREFERENCED UINTN mLevelShift[GUARDED_HEAP_MAP_TABLE_DEPTH]
- = GUARDED_HEAP_MAP_TABLE_DEPTH_SHIFTS;
-GLOBAL_REMOVE_IF_UNREFERENCED UINTN mLevelMask[GUARDED_HEAP_MAP_TABLE_DEPTH]
- = GUARDED_HEAP_MAP_TABLE_DEPTH_MASKS;
+GLOBAL_REMOVE_IF_UNREFERENCED UINTN mLevelShift[GUARDED_HEAP_MAP_TABLE_DEPTH]
+ = GUARDED_HEAP_MAP_TABLE_DEPTH_SHIFTS;
+GLOBAL_REMOVE_IF_UNREFERENCED UINTN mLevelMask[GUARDED_HEAP_MAP_TABLE_DEPTH]
+ = GUARDED_HEAP_MAP_TABLE_DEPTH_MASKS;
+
+//
+// Used for promoting freed but not used pages.
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_PHYSICAL_ADDRESS mLastPromotedPage = BASE_4GB;
/**
Set corresponding bits in bitmap table to 1 according to the address.
@@ -56,29 +55,29 @@ GLOBAL_REMOVE_IF_UNREFERENCED UINTN mLevelMask[GUARDED_HEAP_MAP_TABLE_DEPTH]
STATIC
VOID
SetBits (
- IN EFI_PHYSICAL_ADDRESS Address,
- IN UINTN BitNumber,
- IN UINT64 *BitMap
+ IN EFI_PHYSICAL_ADDRESS Address,
+ IN UINTN BitNumber,
+ IN UINT64 *BitMap
)
{
- UINTN Lsbs;
- UINTN Qwords;
- UINTN Msbs;
- UINTN StartBit;
- UINTN EndBit;
-
- StartBit = (UINTN)GUARDED_HEAP_MAP_ENTRY_BIT_INDEX (Address);
- EndBit = (StartBit + BitNumber - 1) % GUARDED_HEAP_MAP_ENTRY_BITS;
-
- if ((StartBit + BitNumber) > GUARDED_HEAP_MAP_ENTRY_BITS) {
- Msbs = (GUARDED_HEAP_MAP_ENTRY_BITS - StartBit) %
- GUARDED_HEAP_MAP_ENTRY_BITS;
- Lsbs = (EndBit + 1) % GUARDED_HEAP_MAP_ENTRY_BITS;
- Qwords = (BitNumber - Msbs) / GUARDED_HEAP_MAP_ENTRY_BITS;
+ UINTN Lsbs;
+ UINTN Qwords;
+ UINTN Msbs;
+ UINTN StartBit;
+ UINTN EndBit;
+
+ StartBit = (UINTN)GUARDED_HEAP_MAP_ENTRY_BIT_INDEX (Address);
+ EndBit = (StartBit + BitNumber - 1) % GUARDED_HEAP_MAP_ENTRY_BITS;
+
+ if ((StartBit + BitNumber) >= GUARDED_HEAP_MAP_ENTRY_BITS) {
+ Msbs = (GUARDED_HEAP_MAP_ENTRY_BITS - StartBit) %
+ GUARDED_HEAP_MAP_ENTRY_BITS;
+ Lsbs = (EndBit + 1) % GUARDED_HEAP_MAP_ENTRY_BITS;
+ Qwords = (BitNumber - Msbs) / GUARDED_HEAP_MAP_ENTRY_BITS;
} else {
- Msbs = BitNumber;
- Lsbs = 0;
- Qwords = 0;
+ Msbs = BitNumber;
+ Lsbs = 0;
+ Qwords = 0;
}
if (Msbs > 0) {
@@ -87,8 +86,11 @@ SetBits (
}
if (Qwords > 0) {
- SetMem64 ((VOID *)BitMap, Qwords * GUARDED_HEAP_MAP_ENTRY_BYTES,
- (UINT64)-1);
+ SetMem64 (
+ (VOID *)BitMap,
+ Qwords * GUARDED_HEAP_MAP_ENTRY_BYTES,
+ (UINT64)-1
+ );
BitMap += Qwords;
}
@@ -109,29 +111,29 @@ SetBits (
STATIC
VOID
ClearBits (
- IN EFI_PHYSICAL_ADDRESS Address,
- IN UINTN BitNumber,
- IN UINT64 *BitMap
+ IN EFI_PHYSICAL_ADDRESS Address,
+ IN UINTN BitNumber,
+ IN UINT64 *BitMap
)
{
- UINTN Lsbs;
- UINTN Qwords;
- UINTN Msbs;
- UINTN StartBit;
- UINTN EndBit;
-
- StartBit = (UINTN)GUARDED_HEAP_MAP_ENTRY_BIT_INDEX (Address);
- EndBit = (StartBit + BitNumber - 1) % GUARDED_HEAP_MAP_ENTRY_BITS;
-
- if ((StartBit + BitNumber) > GUARDED_HEAP_MAP_ENTRY_BITS) {
- Msbs = (GUARDED_HEAP_MAP_ENTRY_BITS - StartBit) %
- GUARDED_HEAP_MAP_ENTRY_BITS;
- Lsbs = (EndBit + 1) % GUARDED_HEAP_MAP_ENTRY_BITS;
- Qwords = (BitNumber - Msbs) / GUARDED_HEAP_MAP_ENTRY_BITS;
+ UINTN Lsbs;
+ UINTN Qwords;
+ UINTN Msbs;
+ UINTN StartBit;
+ UINTN EndBit;
+
+ StartBit = (UINTN)GUARDED_HEAP_MAP_ENTRY_BIT_INDEX (Address);
+ EndBit = (StartBit + BitNumber - 1) % GUARDED_HEAP_MAP_ENTRY_BITS;
+
+ if ((StartBit + BitNumber) >= GUARDED_HEAP_MAP_ENTRY_BITS) {
+ Msbs = (GUARDED_HEAP_MAP_ENTRY_BITS - StartBit) %
+ GUARDED_HEAP_MAP_ENTRY_BITS;
+ Lsbs = (EndBit + 1) % GUARDED_HEAP_MAP_ENTRY_BITS;
+ Qwords = (BitNumber - Msbs) / GUARDED_HEAP_MAP_ENTRY_BITS;
} else {
- Msbs = BitNumber;
- Lsbs = 0;
- Qwords = 0;
+ Msbs = BitNumber;
+ Lsbs = 0;
+ Qwords = 0;
}
if (Msbs > 0) {
@@ -164,21 +166,21 @@ ClearBits (
STATIC
UINT64
GetBits (
- IN EFI_PHYSICAL_ADDRESS Address,
- IN UINTN BitNumber,
- IN UINT64 *BitMap
+ IN EFI_PHYSICAL_ADDRESS Address,
+ IN UINTN BitNumber,
+ IN UINT64 *BitMap
)
{
- UINTN StartBit;
- UINTN EndBit;
- UINTN Lsbs;
- UINTN Msbs;
- UINT64 Result;
+ UINTN StartBit;
+ UINTN EndBit;
+ UINTN Lsbs;
+ UINTN Msbs;
+ UINT64 Result;
ASSERT (BitNumber <= GUARDED_HEAP_MAP_ENTRY_BITS);
- StartBit = (UINTN)GUARDED_HEAP_MAP_ENTRY_BIT_INDEX (Address);
- EndBit = (StartBit + BitNumber - 1) % GUARDED_HEAP_MAP_ENTRY_BITS;
+ StartBit = (UINTN)GUARDED_HEAP_MAP_ENTRY_BIT_INDEX (Address);
+ EndBit = (StartBit + BitNumber - 1) % GUARDED_HEAP_MAP_ENTRY_BITS;
if ((StartBit + BitNumber) > GUARDED_HEAP_MAP_ENTRY_BITS) {
Msbs = GUARDED_HEAP_MAP_ENTRY_BITS - StartBit;
@@ -188,10 +190,14 @@ GetBits (
Lsbs = 0;
}
- Result = RShiftU64 ((*BitMap), StartBit) & (LShiftU64 (1, Msbs) - 1);
- if (Lsbs > 0) {
- BitMap += 1;
- Result |= LShiftU64 ((*BitMap) & (LShiftU64 (1, Lsbs) - 1), Msbs);
+ if ((StartBit == 0) && (BitNumber == GUARDED_HEAP_MAP_ENTRY_BITS)) {
+ Result = *BitMap;
+ } else {
+ Result = RShiftU64 ((*BitMap), StartBit) & (LShiftU64 (1, Msbs) - 1);
+ if (Lsbs > 0) {
+ BitMap += 1;
+ Result |= LShiftU64 ((*BitMap) & (LShiftU64 (1, Lsbs) - 1), Msbs);
+ }
}
return Result;
@@ -209,71 +215,72 @@ GetBits (
**/
UINTN
FindGuardedMemoryMap (
- IN EFI_PHYSICAL_ADDRESS Address,
- IN BOOLEAN AllocMapUnit,
- OUT UINT64 **BitMap
+ IN EFI_PHYSICAL_ADDRESS Address,
+ IN BOOLEAN AllocMapUnit,
+ OUT UINT64 **BitMap
)
{
- UINTN Level;
- UINT64 *GuardMap;
- UINT64 MapMemory;
- UINTN Index;
- UINTN Size;
- UINTN BitsToUnitEnd;
- EFI_STATUS Status;
+ UINTN Level;
+ UINT64 *GuardMap;
+ UINT64 MapMemory;
+ UINTN Index;
+ UINTN Size;
+ UINTN BitsToUnitEnd;
+ EFI_STATUS Status;
+
+ MapMemory = 0;
//
// Adjust current map table depth according to the address to access
//
- while (mMapLevel < GUARDED_HEAP_MAP_TABLE_DEPTH
- &&
+ while (AllocMapUnit &&
+ mMapLevel < GUARDED_HEAP_MAP_TABLE_DEPTH &&
RShiftU64 (
Address,
mLevelShift[GUARDED_HEAP_MAP_TABLE_DEPTH - mMapLevel - 1]
- ) != 0) {
-
+ ) != 0)
+ {
if (mGuardedMemoryMap != 0) {
Size = (mLevelMask[GUARDED_HEAP_MAP_TABLE_DEPTH - mMapLevel - 1] + 1)
* GUARDED_HEAP_MAP_ENTRY_BYTES;
Status = CoreInternalAllocatePages (
- AllocateAnyPages,
- EfiBootServicesData,
- EFI_SIZE_TO_PAGES (Size),
- &MapMemory,
- FALSE
- );
+ AllocateAnyPages,
+ EfiBootServicesData,
+ EFI_SIZE_TO_PAGES (Size),
+ &MapMemory,
+ FALSE
+ );
ASSERT_EFI_ERROR (Status);
ASSERT (MapMemory != 0);
SetMem ((VOID *)(UINTN)MapMemory, Size, 0);
*(UINT64 *)(UINTN)MapMemory = mGuardedMemoryMap;
- mGuardedMemoryMap = MapMemory;
+ mGuardedMemoryMap = MapMemory;
}
mMapLevel++;
-
}
GuardMap = &mGuardedMemoryMap;
for (Level = GUARDED_HEAP_MAP_TABLE_DEPTH - mMapLevel;
Level < GUARDED_HEAP_MAP_TABLE_DEPTH;
- ++Level) {
-
+ ++Level)
+ {
if (*GuardMap == 0) {
if (!AllocMapUnit) {
GuardMap = NULL;
break;
}
- Size = (mLevelMask[Level] + 1) * GUARDED_HEAP_MAP_ENTRY_BYTES;
+ Size = (mLevelMask[Level] + 1) * GUARDED_HEAP_MAP_ENTRY_BYTES;
Status = CoreInternalAllocatePages (
- AllocateAnyPages,
- EfiBootServicesData,
- EFI_SIZE_TO_PAGES (Size),
- &MapMemory,
- FALSE
- );
+ AllocateAnyPages,
+ EfiBootServicesData,
+ EFI_SIZE_TO_PAGES (Size),
+ &MapMemory,
+ FALSE
+ );
ASSERT_EFI_ERROR (Status);
ASSERT (MapMemory != 0);
@@ -281,10 +288,9 @@ FindGuardedMemoryMap (
*GuardMap = MapMemory;
}
- Index = (UINTN)RShiftU64 (Address, mLevelShift[Level]);
- Index &= mLevelMask[Level];
- GuardMap = (UINT64 *)(UINTN)((*GuardMap) + Index * sizeof (UINT64));
-
+ Index = (UINTN)RShiftU64 (Address, mLevelShift[Level]);
+ Index &= mLevelMask[Level];
+ GuardMap = (UINT64 *)(UINTN)((*GuardMap) + Index * sizeof (UINT64));
}
BitsToUnitEnd = GUARDED_HEAP_MAP_BITS - GUARDED_HEAP_MAP_BIT_INDEX (Address);
@@ -304,13 +310,13 @@ FindGuardedMemoryMap (
VOID
EFIAPI
SetGuardedMemoryBits (
- IN EFI_PHYSICAL_ADDRESS Address,
- IN UINTN NumberOfPages
+ IN EFI_PHYSICAL_ADDRESS Address,
+ IN UINTN NumberOfPages
)
{
- UINT64 *BitMap;
- UINTN Bits;
- UINTN BitsToUnitEnd;
+ UINT64 *BitMap;
+ UINTN Bits;
+ UINTN BitsToUnitEnd;
while (NumberOfPages > 0) {
BitsToUnitEnd = FindGuardedMemoryMap (Address, TRUE, &BitMap);
@@ -320,7 +326,7 @@ SetGuardedMemoryBits (
// Cross map unit
Bits = BitsToUnitEnd;
} else {
- Bits = NumberOfPages;
+ Bits = NumberOfPages;
}
SetBits (Address, Bits, BitMap);
@@ -341,13 +347,13 @@ SetGuardedMemoryBits (
VOID
EFIAPI
ClearGuardedMemoryBits (
- IN EFI_PHYSICAL_ADDRESS Address,
- IN UINTN NumberOfPages
+ IN EFI_PHYSICAL_ADDRESS Address,
+ IN UINTN NumberOfPages
)
{
- UINT64 *BitMap;
- UINTN Bits;
- UINTN BitsToUnitEnd;
+ UINT64 *BitMap;
+ UINTN Bits;
+ UINTN BitsToUnitEnd;
while (NumberOfPages > 0) {
BitsToUnitEnd = FindGuardedMemoryMap (Address, TRUE, &BitMap);
@@ -357,7 +363,7 @@ ClearGuardedMemoryBits (
// Cross map unit
Bits = BitsToUnitEnd;
} else {
- Bits = NumberOfPages;
+ Bits = NumberOfPages;
}
ClearBits (Address, Bits, BitMap);
@@ -375,17 +381,17 @@ ClearGuardedMemoryBits (
@return An integer containing the guarded memory bitmap.
**/
-UINTN
+UINT64
GetGuardedMemoryBits (
- IN EFI_PHYSICAL_ADDRESS Address,
- IN UINTN NumberOfPages
+ IN EFI_PHYSICAL_ADDRESS Address,
+ IN UINTN NumberOfPages
)
{
- UINT64 *BitMap;
- UINTN Bits;
- UINTN Result;
- UINTN Shift;
- UINTN BitsToUnitEnd;
+ UINT64 *BitMap;
+ UINTN Bits;
+ UINT64 Result;
+ UINTN Shift;
+ UINTN BitsToUnitEnd;
ASSERT (NumberOfPages <= GUARDED_HEAP_MAP_ENTRY_BITS);
@@ -396,9 +402,9 @@ GetGuardedMemoryBits (
if (NumberOfPages > BitsToUnitEnd) {
// Cross map unit
- Bits = BitsToUnitEnd;
+ Bits = BitsToUnitEnd;
} else {
- Bits = NumberOfPages;
+ Bits = NumberOfPages;
}
if (BitMap != NULL) {
@@ -423,15 +429,18 @@ GetGuardedMemoryBits (
UINTN
EFIAPI
GetGuardMapBit (
- IN EFI_PHYSICAL_ADDRESS Address
+ IN EFI_PHYSICAL_ADDRESS Address
)
{
- UINT64 *GuardMap;
+ UINT64 *GuardMap;
FindGuardedMemoryMap (Address, FALSE, &GuardMap);
if (GuardMap != NULL) {
- if (RShiftU64 (*GuardMap,
- GUARDED_HEAP_MAP_ENTRY_BIT_INDEX (Address)) & 1) {
+ if (RShiftU64 (
+ *GuardMap,
+ GUARDED_HEAP_MAP_ENTRY_BIT_INDEX (Address)
+ ) & 1)
+ {
return 1;
}
}
@@ -439,52 +448,6 @@ GetGuardMapBit (
return 0;
}
-/**
- Set the bit in bitmap table for the given address.
-
- @param[in] Address The address to set for.
-
- @return VOID.
-**/
-VOID
-EFIAPI
-SetGuardMapBit (
- IN EFI_PHYSICAL_ADDRESS Address
- )
-{
- UINT64 *GuardMap;
- UINT64 BitMask;
-
- FindGuardedMemoryMap (Address, TRUE, &GuardMap);
- if (GuardMap != NULL) {
- BitMask = LShiftU64 (1, GUARDED_HEAP_MAP_ENTRY_BIT_INDEX (Address));
- *GuardMap |= BitMask;
- }
-}
-
-/**
- Clear the bit in bitmap table for the given address.
-
- @param[in] Address The address to clear for.
-
- @return VOID.
-**/
-VOID
-EFIAPI
-ClearGuardMapBit (
- IN EFI_PHYSICAL_ADDRESS Address
- )
-{
- UINT64 *GuardMap;
- UINT64 BitMask;
-
- FindGuardedMemoryMap (Address, TRUE, &GuardMap);
- if (GuardMap != NULL) {
- BitMask = LShiftU64 (1, GUARDED_HEAP_MAP_ENTRY_BIT_INDEX (Address));
- *GuardMap &= ~BitMask;
- }
-}
-
/**
Check to see if the page at the given address is a Guard page or not.
@@ -496,10 +459,10 @@ ClearGuardMapBit (
BOOLEAN
EFIAPI
IsGuardPage (
- IN EFI_PHYSICAL_ADDRESS Address
+ IN EFI_PHYSICAL_ADDRESS Address
)
{
- UINTN BitMap;
+ UINT64 BitMap;
//
// There must be at least one guarded page before and/or after given
@@ -510,40 +473,6 @@ IsGuardPage (
return ((BitMap == BIT0) || (BitMap == BIT2) || (BitMap == (BIT2 | BIT0)));
}
-/**
- Check to see if the page at the given address is a head Guard page or not.
-
- @param[in] Address The address to check for
-
- @return TRUE The page at Address is a head Guard page
- @return FALSE The page at Address is not a head Guard page
-**/
-BOOLEAN
-EFIAPI
-IsHeadGuard (
- IN EFI_PHYSICAL_ADDRESS Address
- )
-{
- return (GetGuardedMemoryBits (Address, 2) == BIT1);
-}
-
-/**
- Check to see if the page at the given address is a tail Guard page or not.
-
- @param[in] Address The address to check for.
-
- @return TRUE The page at Address is a tail Guard page.
- @return FALSE The page at Address is not a tail Guard page.
-**/
-BOOLEAN
-EFIAPI
-IsTailGuard (
- IN EFI_PHYSICAL_ADDRESS Address
- )
-{
- return (GetGuardedMemoryBits (Address - EFI_PAGE_SIZE, 2) == BIT0);
-}
-
/**
Check to see if the page at the given address is guarded or not.
@@ -555,7 +484,7 @@ IsTailGuard (
BOOLEAN
EFIAPI
IsMemoryGuarded (
- IN EFI_PHYSICAL_ADDRESS Address
+ IN EFI_PHYSICAL_ADDRESS Address
)
{
return (GetGuardMapBit (Address) == 1);
@@ -573,9 +502,15 @@ IsMemoryGuarded (
VOID
EFIAPI
SetGuardPage (
- IN EFI_PHYSICAL_ADDRESS BaseAddress
+ IN EFI_PHYSICAL_ADDRESS BaseAddress
)
{
+ EFI_STATUS Status;
+
+ if (gCpu == NULL) {
+ return;
+ }
+
//
// Set flag to make sure allocating memory without GUARD for page table
// operation; otherwise infinite loops could be caused.
@@ -583,10 +518,10 @@ SetGuardPage (
mOnGuarding = TRUE;
//
// Note: This might overwrite other attributes needed by other features,
- // such as memory protection (NX). Please make sure they are not enabled
- // at the same time.
+ // such as NX memory protection.
//
- gCpu->SetMemoryAttributes (gCpu, BaseAddress, EFI_PAGE_SIZE, EFI_MEMORY_RP);
+ Status = gCpu->SetMemoryAttributes (gCpu, BaseAddress, EFI_PAGE_SIZE, EFI_MEMORY_RP);
+ ASSERT_EFI_ERROR (Status);
mOnGuarding = FALSE;
}
@@ -602,9 +537,26 @@ SetGuardPage (
VOID
EFIAPI
UnsetGuardPage (
- IN EFI_PHYSICAL_ADDRESS BaseAddress
+ IN EFI_PHYSICAL_ADDRESS BaseAddress
)
{
+ UINT64 Attributes;
+ EFI_STATUS Status;
+
+ 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
+ // memory.
+ //
+ Attributes = 0;
+ if ((PcdGet64 (PcdDxeNxMemoryProtectionPolicy) & (1 << EfiConventionalMemory)) != 0) {
+ Attributes |= EFI_MEMORY_XP;
+ }
+
//
// Set flag to make sure allocating memory without GUARD for page table
// operation; otherwise infinite loops could be caused.
@@ -615,7 +567,8 @@ UnsetGuardPage (
// such as memory protection (NX). Please make sure they are not enabled
// at the same time.
//
- gCpu->SetMemoryAttributes (gCpu, BaseAddress, EFI_PAGE_SIZE, 0);
+ Status = gCpu->SetMemoryAttributes (gCpu, BaseAddress, EFI_PAGE_SIZE, Attributes);
+ ASSERT_EFI_ERROR (Status);
mOnGuarding = FALSE;
}
@@ -632,25 +585,15 @@ UnsetGuardPage (
**/
BOOLEAN
IsMemoryTypeToGuard (
- IN EFI_MEMORY_TYPE MemoryType,
- IN EFI_ALLOCATE_TYPE AllocateType,
- IN UINT8 PageOrPool
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN EFI_ALLOCATE_TYPE AllocateType,
+ IN UINT8 PageOrPool
)
{
- UINT64 TestBit;
- UINT64 ConfigBit;
- BOOLEAN InSmm;
-
- if (gCpu == NULL || AllocateType == AllocateAddress) {
- return FALSE;
- }
-
- InSmm = FALSE;
- if (gSmmBase2 != NULL) {
- gSmmBase2->InSmm (gSmmBase2, &InSmm);
- }
+ UINT64 TestBit;
+ UINT64 ConfigBit;
- if (InSmm) {
+ if (AllocateType == AllocateAddress) {
return FALSE;
}
@@ -668,7 +611,7 @@ IsMemoryTypeToGuard (
if ((UINT32)MemoryType >= MEMORY_TYPE_OS_RESERVED_MIN) {
TestBit = BIT63;
- } else if ((UINT32) MemoryType >= MEMORY_TYPE_OEM_RESERVED_MIN) {
+ } else if ((UINT32)MemoryType >= MEMORY_TYPE_OEM_RESERVED_MIN) {
TestBit = BIT62;
} else if (MemoryType < EfiMaxMemoryType) {
TestBit = LShiftU64 (1, MemoryType);
@@ -692,11 +635,14 @@ IsMemoryTypeToGuard (
**/
BOOLEAN
IsPoolTypeToGuard (
- IN EFI_MEMORY_TYPE MemoryType
+ IN EFI_MEMORY_TYPE MemoryType
)
{
- return IsMemoryTypeToGuard (MemoryType, AllocateAnyPages,
- GUARD_HEAP_TYPE_POOL);
+ return IsMemoryTypeToGuard (
+ MemoryType,
+ AllocateAnyPages,
+ GUARD_HEAP_TYPE_POOL
+ );
}
/**
@@ -710,13 +656,28 @@ IsPoolTypeToGuard (
**/
BOOLEAN
IsPageTypeToGuard (
- IN EFI_MEMORY_TYPE MemoryType,
- IN EFI_ALLOCATE_TYPE AllocateType
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN EFI_ALLOCATE_TYPE AllocateType
)
{
return IsMemoryTypeToGuard (MemoryType, AllocateType, GUARD_HEAP_TYPE_PAGE);
}
+/**
+ Check to see if the heap guard is enabled for page and/or pool allocation.
+
+ @param[in] GuardType Specify the sub-type(s) of Heap Guard.
+
+ @return TRUE/FALSE.
+**/
+BOOLEAN
+IsHeapGuardEnabled (
+ UINT8 GuardType
+ )
+{
+ return IsMemoryTypeToGuard (EfiMaxMemoryType, AllocateAnyPages, GuardType);
+}
+
/**
Set head Guard and tail Guard for the given memory range.
@@ -727,11 +688,11 @@ IsPageTypeToGuard (
**/
VOID
SetGuardForMemory (
- IN EFI_PHYSICAL_ADDRESS Memory,
- IN UINTN NumberOfPages
+ IN EFI_PHYSICAL_ADDRESS Memory,
+ IN UINTN NumberOfPages
)
{
- EFI_PHYSICAL_ADDRESS GuardPage;
+ EFI_PHYSICAL_ADDRESS GuardPage;
//
// Set tail Guard
@@ -763,11 +724,12 @@ SetGuardForMemory (
**/
VOID
UnsetGuardForMemory (
- IN EFI_PHYSICAL_ADDRESS Memory,
- IN UINTN NumberOfPages
+ IN EFI_PHYSICAL_ADDRESS Memory,
+ IN UINTN NumberOfPages
)
{
EFI_PHYSICAL_ADDRESS GuardPage;
+ UINT64 GuardBitmap;
if (NumberOfPages == 0) {
return;
@@ -776,16 +738,29 @@ UnsetGuardForMemory (
//
// Head Guard must be one page before, if any.
//
- GuardPage = Memory - EFI_PAGES_TO_SIZE (1);
- if (IsHeadGuard (GuardPage)) {
- if (!IsMemoryGuarded (GuardPage - EFI_PAGES_TO_SIZE (1))) {
+ // MSB-> 1 0 <-LSB
+ // -------------------
+ // Head Guard -> 0 1 -> Don't free Head Guard (shared Guard)
+ // Head Guard -> 0 0 -> Free Head Guard either (not shared Guard)
+ // 1 X -> Don't free first page (need a new Guard)
+ // (it'll be turned into a Guard page later)
+ // -------------------
+ // Start -> -1 -2
+ //
+ GuardPage = Memory - EFI_PAGES_TO_SIZE (1);
+ GuardBitmap = GetGuardedMemoryBits (Memory - EFI_PAGES_TO_SIZE (2), 2);
+ if ((GuardBitmap & BIT1) == 0) {
+ //
+ // Head Guard exists.
+ //
+ if ((GuardBitmap & BIT0) == 0) {
//
// If the head Guard is not a tail Guard of adjacent memory block,
// unset it.
//
UnsetGuardPage (GuardPage);
}
- } else if (IsMemoryGuarded (GuardPage)) {
+ } else {
//
// Pages before memory to free are still in Guard. It's a partial free
// case. Turn first page of memory block to free into a new Guard.
@@ -796,16 +771,29 @@ UnsetGuardForMemory (
//
// Tail Guard must be the page after this memory block to free, if any.
//
- GuardPage = Memory + EFI_PAGES_TO_SIZE (NumberOfPages);
- if (IsTailGuard (GuardPage)) {
- if (!IsMemoryGuarded (GuardPage + EFI_PAGES_TO_SIZE (1))) {
+ // MSB-> 1 0 <-LSB
+ // --------------------
+ // 1 0 <- Tail Guard -> Don't free Tail Guard (shared Guard)
+ // 0 0 <- Tail Guard -> Free Tail Guard either (not shared Guard)
+ // X 1 -> Don't free last page (need a new Guard)
+ // (it'll be turned into a Guard page later)
+ // --------------------
+ // +1 +0 <- End
+ //
+ GuardPage = Memory + EFI_PAGES_TO_SIZE (NumberOfPages);
+ GuardBitmap = GetGuardedMemoryBits (GuardPage, 2);
+ if ((GuardBitmap & BIT0) == 0) {
+ //
+ // Tail Guard exists.
+ //
+ if ((GuardBitmap & BIT1) == 0) {
//
// If the tail Guard is not a head Guard of adjacent memory block,
// free it; otherwise, keep it.
//
UnsetGuardPage (GuardPage);
}
- } else if (IsMemoryGuarded (GuardPage)) {
+ } else {
//
// Pages after memory to free are still in Guard. It's a partial free
// case. We need to keep one page to be a head Guard.
@@ -816,7 +804,7 @@ UnsetGuardForMemory (
//
// No matter what, we just clear the mark of the Guarded memory.
//
- ClearGuardedMemoryBits(Memory, NumberOfPages);
+ ClearGuardedMemoryBits (Memory, NumberOfPages);
}
/**
@@ -835,19 +823,25 @@ UnsetGuardForMemory (
**/
UINT64
AdjustMemoryS (
- IN UINT64 Start,
- IN UINT64 Size,
- IN UINT64 SizeRequested
+ IN UINT64 Start,
+ IN UINT64 Size,
+ IN UINT64 SizeRequested
)
{
UINT64 Target;
- Target = Start + Size - SizeRequested;
-
//
- // At least one more page needed for Guard page.
+ // UEFI spec requires that allocated pool must be 8-byte aligned. If it's
+ // indicated to put the pool near the Tail Guard, we need extra bytes to
+ // make sure alignment of the returned pool address.
//
- if (Size < (SizeRequested + EFI_PAGES_TO_SIZE (1))) {
+ if ((PcdGet8 (PcdHeapGuardPropertyMask) & BIT7) == 0) {
+ SizeRequested = ALIGN_VALUE (SizeRequested, 8);
+ }
+
+ Target = Start + Size - SizeRequested;
+ ASSERT (Target >= Start);
+ if (Target == 0) {
return 0;
}
@@ -888,27 +882,41 @@ AdjustMemoryS (
**/
VOID
AdjustMemoryF (
- IN OUT EFI_PHYSICAL_ADDRESS *Memory,
- IN OUT UINTN *NumberOfPages
+ IN OUT EFI_PHYSICAL_ADDRESS *Memory,
+ IN OUT UINTN *NumberOfPages
)
{
EFI_PHYSICAL_ADDRESS Start;
EFI_PHYSICAL_ADDRESS MemoryToTest;
UINTN PagesToFree;
+ UINT64 GuardBitmap;
- if (Memory == NULL || NumberOfPages == NULL || *NumberOfPages == 0) {
+ if ((Memory == NULL) || (NumberOfPages == NULL) || (*NumberOfPages == 0)) {
return;
}
- Start = *Memory;
+ Start = *Memory;
PagesToFree = *NumberOfPages;
//
// Head Guard must be one page before, if any.
//
- MemoryToTest = Start - EFI_PAGES_TO_SIZE (1);
- if (IsHeadGuard (MemoryToTest)) {
- if (!IsMemoryGuarded (MemoryToTest - EFI_PAGES_TO_SIZE (1))) {
+ // MSB-> 1 0 <-LSB
+ // -------------------
+ // Head Guard -> 0 1 -> Don't free Head Guard (shared Guard)
+ // Head Guard -> 0 0 -> Free Head Guard either (not shared Guard)
+ // 1 X -> Don't free first page (need a new Guard)
+ // (it'll be turned into a Guard page later)
+ // -------------------
+ // Start -> -1 -2
+ //
+ MemoryToTest = Start - EFI_PAGES_TO_SIZE (2);
+ GuardBitmap = GetGuardedMemoryBits (MemoryToTest, 2);
+ if ((GuardBitmap & BIT1) == 0) {
+ //
+ // Head Guard exists.
+ //
+ if ((GuardBitmap & BIT0) == 0) {
//
// If the head Guard is not a tail Guard of adjacent memory block,
// free it; otherwise, keep it.
@@ -916,10 +924,10 @@ AdjustMemoryF (
Start -= EFI_PAGES_TO_SIZE (1);
PagesToFree += 1;
}
- } else if (IsMemoryGuarded (MemoryToTest)) {
+ } else {
//
- // Pages before memory to free are still in Guard. It's a partial free
- // case. We need to keep one page to be a tail Guard.
+ // No Head Guard, and pages before memory to free are still in Guard. It's a
+ // partial free case. We need to keep one page to be a tail Guard.
//
Start += EFI_PAGES_TO_SIZE (1);
PagesToFree -= 1;
@@ -928,25 +936,38 @@ AdjustMemoryF (
//
// Tail Guard must be the page after this memory block to free, if any.
//
+ // MSB-> 1 0 <-LSB
+ // --------------------
+ // 1 0 <- Tail Guard -> Don't free Tail Guard (shared Guard)
+ // 0 0 <- Tail Guard -> Free Tail Guard either (not shared Guard)
+ // X 1 -> Don't free last page (need a new Guard)
+ // (it'll be turned into a Guard page later)
+ // --------------------
+ // +1 +0 <- End
+ //
MemoryToTest = Start + EFI_PAGES_TO_SIZE (PagesToFree);
- if (IsTailGuard (MemoryToTest)) {
- if (!IsMemoryGuarded (MemoryToTest + EFI_PAGES_TO_SIZE (1))) {
+ GuardBitmap = GetGuardedMemoryBits (MemoryToTest, 2);
+ if ((GuardBitmap & BIT0) == 0) {
+ //
+ // Tail Guard exists.
+ //
+ if ((GuardBitmap & BIT1) == 0) {
//
// If the tail Guard is not a head Guard of adjacent memory block,
// free it; otherwise, keep it.
//
PagesToFree += 1;
}
- } else if (IsMemoryGuarded (MemoryToTest)) {
+ } else if (PagesToFree > 0) {
//
- // Pages after memory to free are still in Guard. It's a partial free
- // case. We need to keep one page to be a head Guard.
+ // No Tail Guard, and pages after memory to free are still in Guard. It's a
+ // partial free case. We need to keep one page to be a head Guard.
//
PagesToFree -= 1;
}
- *Memory = Start;
- *NumberOfPages = PagesToFree;
+ *Memory = Start;
+ *NumberOfPages = PagesToFree;
}
/**
@@ -959,8 +980,8 @@ AdjustMemoryF (
**/
VOID
AdjustMemoryA (
- IN OUT EFI_PHYSICAL_ADDRESS *Memory,
- IN OUT UINTN *NumberOfPages
+ IN OUT EFI_PHYSICAL_ADDRESS *Memory,
+ IN OUT UINTN *NumberOfPages
)
{
//
@@ -993,12 +1014,12 @@ AdjustMemoryA (
**/
VOID *
AdjustPoolHeadA (
- IN EFI_PHYSICAL_ADDRESS Memory,
- IN UINTN NoPages,
- IN UINTN Size
+ IN EFI_PHYSICAL_ADDRESS Memory,
+ IN UINTN NoPages,
+ IN UINTN Size
)
{
- if ((PcdGet8 (PcdHeapGuardPropertyMask) & BIT7) != 0) {
+ if ((Memory == 0) || ((PcdGet8 (PcdHeapGuardPropertyMask) & BIT7) != 0)) {
//
// Pool head is put near the head Guard
//
@@ -1008,6 +1029,7 @@ AdjustPoolHeadA (
//
// Pool head is put near the tail Guard
//
+ Size = ALIGN_VALUE (Size, 8);
return (VOID *)(UINTN)(Memory + EFI_PAGES_TO_SIZE (NoPages) - Size);
}
@@ -1020,10 +1042,10 @@ AdjustPoolHeadA (
**/
VOID *
AdjustPoolHeadF (
- IN EFI_PHYSICAL_ADDRESS Memory
+ IN EFI_PHYSICAL_ADDRESS Memory
)
{
- if ((PcdGet8 (PcdHeapGuardPropertyMask) & BIT7) != 0) {
+ if ((Memory == 0) || ((PcdGet8 (PcdHeapGuardPropertyMask) & BIT7) != 0)) {
//
// Pool head is put near the head Guard
//
@@ -1052,13 +1074,540 @@ CoreConvertPagesWithGuard (
IN EFI_MEMORY_TYPE NewType
)
{
+ UINT64 OldStart;
+ UINTN OldPages;
+
if (NewType == EfiConventionalMemory) {
+ OldStart = Start;
+ OldPages = NumberOfPages;
+
AdjustMemoryF (&Start, &NumberOfPages);
+ //
+ // It's safe to unset Guard page inside memory lock because there should
+ // be no memory allocation occurred in updating memory page attribute at
+ // this point. And unsetting Guard page before free will prevent Guard
+ // page just freed back to pool from being allocated right away before
+ // marking it usable (from non-present to present).
+ //
+ UnsetGuardForMemory (OldStart, OldPages);
+ if (NumberOfPages == 0) {
+ return EFI_SUCCESS;
+ }
} else {
AdjustMemoryA (&Start, &NumberOfPages);
}
- return CoreConvertPages(Start, NumberOfPages, NewType);
+ 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]);
+ }
+}
+
+/**
+ Find the address of top-most guarded free page.
+
+ @param[out] Address Start address of top-most guarded free page.
+
+ @return VOID.
+**/
+VOID
+GetLastGuardedFreePageAddress (
+ OUT EFI_PHYSICAL_ADDRESS *Address
+ )
+{
+ EFI_PHYSICAL_ADDRESS AddressGranularity;
+ EFI_PHYSICAL_ADDRESS BaseAddress;
+ UINTN Level;
+ UINT64 Map;
+ INTN Index;
+
+ ASSERT (mMapLevel >= 1);
+
+ BaseAddress = 0;
+ Map = mGuardedMemoryMap;
+ for (Level = GUARDED_HEAP_MAP_TABLE_DEPTH - mMapLevel;
+ Level < GUARDED_HEAP_MAP_TABLE_DEPTH;
+ ++Level)
+ {
+ AddressGranularity = LShiftU64 (1, mLevelShift[Level]);
+
+ //
+ // Find the non-NULL entry at largest index.
+ //
+ for (Index = (INTN)mLevelMask[Level]; Index >= 0; --Index) {
+ if (((UINT64 *)(UINTN)Map)[Index] != 0) {
+ BaseAddress += MultU64x32 (AddressGranularity, (UINT32)Index);
+ Map = ((UINT64 *)(UINTN)Map)[Index];
+ break;
+ }
+ }
+ }
+
+ //
+ // Find the non-zero MSB then get the page address.
+ //
+ while (Map != 0) {
+ Map = RShiftU64 (Map, 1);
+ BaseAddress += EFI_PAGES_TO_SIZE (1);
+ }
+
+ *Address = BaseAddress;
+}
+
+/**
+ Record freed pages.
+
+ @param[in] BaseAddress Base address of just freed pages.
+ @param[in] Pages Number of freed pages.
+
+ @return VOID.
+**/
+VOID
+MarkFreedPages (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINTN Pages
+ )
+{
+ SetGuardedMemoryBits (BaseAddress, Pages);
+}
+
+/**
+ Record freed pages as well as mark them as not-present.
+
+ @param[in] BaseAddress Base address of just freed pages.
+ @param[in] Pages Number of freed pages.
+
+ @return VOID.
+**/
+VOID
+EFIAPI
+GuardFreedPages (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINTN Pages
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Legacy memory lower than 1MB might be accessed with no allocation. Leave
+ // them alone.
+ //
+ if (BaseAddress < BASE_1MB) {
+ return;
+ }
+
+ MarkFreedPages (BaseAddress, Pages);
+ if (gCpu != NULL) {
+ //
+ // Set flag to make sure allocating memory without GUARD for page table
+ // operation; otherwise infinite loops could be caused.
+ //
+ mOnGuarding = TRUE;
+ //
+ // Note: This might overwrite other attributes needed by other features,
+ // such as NX memory protection.
+ //
+ Status = gCpu->SetMemoryAttributes (
+ gCpu,
+ BaseAddress,
+ EFI_PAGES_TO_SIZE (Pages),
+ EFI_MEMORY_RP
+ );
+ //
+ // Normally we should ASSERT the returned Status. But there might be memory
+ // alloc/free involved in SetMemoryAttributes(), which might fail this
+ // calling. It's rare case so it's OK to let a few tiny holes be not-guarded.
+ //
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_WARN, "Failed to guard freed pages: %p (%lu)\n", BaseAddress, (UINT64)Pages));
+ }
+
+ mOnGuarding = FALSE;
+ }
+}
+
+/**
+ Record freed pages as well as mark them as not-present, if enabled.
+
+ @param[in] BaseAddress Base address of just freed pages.
+ @param[in] Pages Number of freed pages.
+
+ @return VOID.
+**/
+VOID
+EFIAPI
+GuardFreedPagesChecked (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINTN Pages
+ )
+{
+ if (IsHeapGuardEnabled (GUARD_HEAP_TYPE_FREED)) {
+ GuardFreedPages (BaseAddress, Pages);
+ }
+}
+
+/**
+ Mark all pages freed before CPU Arch Protocol as not-present.
+
+**/
+VOID
+GuardAllFreedPages (
+ 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;
+ UINT64 BitIndex;
+ UINTN GuardPageNumber;
+
+ 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;
+ GuardPage = (UINT64)-1;
+ GuardPageNumber = 0;
+
+ while (TRUE) {
+ if (Indices[Level] > Entries[Level]) {
+ Tables[Level] = 0;
+ Level -= 1;
+ } else {
+ TableEntry = ((UINT64 *)(UINTN)(Tables[Level]))[Indices[Level]];
+ Address = Addresses[Level];
+
+ if (Level < GUARDED_HEAP_MAP_TABLE_DEPTH - 1) {
+ Level += 1;
+ Tables[Level] = TableEntry;
+ Addresses[Level] = Address;
+ Indices[Level] = 0;
+
+ continue;
+ } else {
+ BitIndex = 1;
+ while (BitIndex != 0) {
+ if ((TableEntry & BitIndex) != 0) {
+ if (GuardPage == (UINT64)-1) {
+ GuardPage = Address;
+ }
+
+ ++GuardPageNumber;
+ } else if (GuardPageNumber > 0) {
+ GuardFreedPages (GuardPage, GuardPageNumber);
+ GuardPageNumber = 0;
+ GuardPage = (UINT64)-1;
+ }
+
+ if (TableEntry == 0) {
+ break;
+ }
+
+ Address += EFI_PAGES_TO_SIZE (1);
+ BitIndex = LShiftU64 (BitIndex, 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]);
+ }
+
+ //
+ // Update the maximum address of freed page which can be used for memory
+ // promotion upon out-of-memory-space.
+ //
+ GetLastGuardedFreePageAddress (&Address);
+ if (Address != 0) {
+ mLastPromotedPage = Address;
+ }
+}
+
+/**
+ This function checks to see if the given memory map descriptor in a memory map
+ can be merged with any guarded free pages.
+
+ @param MemoryMapEntry A pointer to a descriptor in MemoryMap.
+ @param MaxAddress Maximum address to stop the merge.
+
+ @return VOID
+
+**/
+VOID
+MergeGuardPages (
+ IN EFI_MEMORY_DESCRIPTOR *MemoryMapEntry,
+ IN EFI_PHYSICAL_ADDRESS MaxAddress
+ )
+{
+ EFI_PHYSICAL_ADDRESS EndAddress;
+ UINT64 Bitmap;
+ INTN Pages;
+
+ if (!IsHeapGuardEnabled (GUARD_HEAP_TYPE_FREED) ||
+ (MemoryMapEntry->Type >= EfiMemoryMappedIO))
+ {
+ return;
+ }
+
+ Bitmap = 0;
+ Pages = EFI_SIZE_TO_PAGES ((UINTN)(MaxAddress - MemoryMapEntry->PhysicalStart));
+ Pages -= (INTN)MemoryMapEntry->NumberOfPages;
+ while (Pages > 0) {
+ if (Bitmap == 0) {
+ EndAddress = MemoryMapEntry->PhysicalStart +
+ EFI_PAGES_TO_SIZE ((UINTN)MemoryMapEntry->NumberOfPages);
+ Bitmap = GetGuardedMemoryBits (EndAddress, GUARDED_HEAP_MAP_ENTRY_BITS);
+ }
+
+ if ((Bitmap & 1) == 0) {
+ break;
+ }
+
+ Pages--;
+ MemoryMapEntry->NumberOfPages++;
+ Bitmap = RShiftU64 (Bitmap, 1);
+ }
+}
+
+/**
+ Put part (at most 64 pages a time) guarded free pages back to free page pool.
+
+ Freed memory guard is used to detect Use-After-Free (UAF) memory issue, which
+ makes use of 'Used then throw away' way to detect any illegal access to freed
+ memory. The thrown-away memory will be marked as not-present so that any access
+ to those memory (after free) will be caught by page-fault exception.
+
+ The problem is that this will consume lots of memory space. Once no memory
+ left in pool to allocate, we have to restore part of the freed pages to their
+ normal function. Otherwise the whole system will stop functioning.
+
+ @param StartAddress Start address of promoted memory.
+ @param EndAddress End address of promoted memory.
+
+ @return TRUE Succeeded to promote memory.
+ @return FALSE No free memory found.
+
+**/
+BOOLEAN
+PromoteGuardedFreePages (
+ OUT EFI_PHYSICAL_ADDRESS *StartAddress,
+ OUT EFI_PHYSICAL_ADDRESS *EndAddress
+ )
+{
+ EFI_STATUS Status;
+ UINTN AvailablePages;
+ UINT64 Bitmap;
+ EFI_PHYSICAL_ADDRESS Start;
+
+ if (!IsHeapGuardEnabled (GUARD_HEAP_TYPE_FREED)) {
+ return FALSE;
+ }
+
+ //
+ // Similar to memory allocation service, always search the freed pages in
+ // descending direction.
+ //
+ Start = mLastPromotedPage;
+ AvailablePages = 0;
+ while (AvailablePages == 0) {
+ Start -= EFI_PAGES_TO_SIZE (GUARDED_HEAP_MAP_ENTRY_BITS);
+ //
+ // If the address wraps around, try the really freed pages at top.
+ //
+ if (Start > mLastPromotedPage) {
+ GetLastGuardedFreePageAddress (&Start);
+ ASSERT (Start != 0);
+ Start -= EFI_PAGES_TO_SIZE (GUARDED_HEAP_MAP_ENTRY_BITS);
+ }
+
+ Bitmap = GetGuardedMemoryBits (Start, GUARDED_HEAP_MAP_ENTRY_BITS);
+ while (Bitmap > 0) {
+ if ((Bitmap & 1) != 0) {
+ ++AvailablePages;
+ } else if (AvailablePages == 0) {
+ Start += EFI_PAGES_TO_SIZE (1);
+ } else {
+ break;
+ }
+
+ Bitmap = RShiftU64 (Bitmap, 1);
+ }
+ }
+
+ if (AvailablePages != 0) {
+ DEBUG ((DEBUG_INFO, "Promoted pages: %lX (%lx)\r\n", Start, (UINT64)AvailablePages));
+ ClearGuardedMemoryBits (Start, AvailablePages);
+
+ if (gCpu != NULL) {
+ //
+ // Set flag to make sure allocating memory without GUARD for page table
+ // operation; otherwise infinite loops could be caused.
+ //
+ mOnGuarding = TRUE;
+ Status = gCpu->SetMemoryAttributes (gCpu, Start, EFI_PAGES_TO_SIZE (AvailablePages), 0);
+ ASSERT_EFI_ERROR (Status);
+ mOnGuarding = FALSE;
+ }
+
+ mLastPromotedPage = Start;
+ *StartAddress = Start;
+ *EndAddress = Start + EFI_PAGES_TO_SIZE (AvailablePages) - 1;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ Notify function used to set all Guard pages before CPU Arch Protocol installed.
+**/
+VOID
+HeapGuardCpuArchProtocolNotify (
+ VOID
+ )
+{
+ ASSERT (gCpu != NULL);
+
+ if (IsHeapGuardEnabled (GUARD_HEAP_TYPE_PAGE|GUARD_HEAP_TYPE_POOL) &&
+ IsHeapGuardEnabled (GUARD_HEAP_TYPE_FREED))
+ {
+ DEBUG ((DEBUG_ERROR, "Heap guard and freed memory guard cannot be enabled at the same time.\n"));
+ CpuDeadLoop ();
+ }
+
+ if (IsHeapGuardEnabled (GUARD_HEAP_TYPE_PAGE|GUARD_HEAP_TYPE_POOL)) {
+ SetAllGuardPages ();
+ }
+
+ if (IsHeapGuardEnabled (GUARD_HEAP_TYPE_FREED)) {
+ GuardAllFreedPages ();
+ }
}
/**
@@ -1071,11 +1620,11 @@ CoreConvertPagesWithGuard (
**/
VOID
Uint64ToBinString (
- IN UINT64 Value,
- OUT CHAR8 *BinString
+ IN UINT64 Value,
+ OUT CHAR8 *BinString
)
{
- UINTN Index;
+ UINTN Index;
if (BinString == NULL) {
return;
@@ -1083,8 +1632,9 @@ Uint64ToBinString (
for (Index = 64; Index > 0; --Index) {
BinString[Index - 1] = '0' + (Value & 1);
- Value = RShiftU64 (Value, 1);
+ Value = RShiftU64 (Value, 1);
}
+
BinString[64] = '\0';
}
@@ -1097,38 +1647,48 @@ DumpGuardedMemoryBitmap (
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;
- INTN Level;
- UINTN RepeatZero;
- CHAR8 String[GUARDED_HEAP_MAP_ENTRY_BITS + 1];
- CHAR8 *Ruler1;
- CHAR8 *Ruler2;
-
- if (mGuardedMemoryMap == 0) {
+ 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;
+ INTN Level;
+ UINTN RepeatZero;
+ CHAR8 String[GUARDED_HEAP_MAP_ENTRY_BITS + 1];
+ CHAR8 *Ruler1;
+ CHAR8 *Ruler2;
+
+ if (!IsHeapGuardEnabled (GUARD_HEAP_TYPE_ALL)) {
+ return;
+ }
+
+ if ((mGuardedMemoryMap == 0) ||
+ (mMapLevel == 0) ||
+ (mMapLevel > GUARDED_HEAP_MAP_TABLE_DEPTH))
+ {
return;
}
Ruler1 = " 3 2 1 0";
Ruler2 = "FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210";
- DEBUG ((HEAP_GUARD_DEBUG_LEVEL, "============================="
- " Guarded Memory Bitmap "
- "==============================\r\n"));
+ DEBUG ((
+ HEAP_GUARD_DEBUG_LEVEL,
+ "============================="
+ " Guarded Memory Bitmap "
+ "==============================\r\n"
+ ));
DEBUG ((HEAP_GUARD_DEBUG_LEVEL, " %a\r\n", Ruler1));
DEBUG ((HEAP_GUARD_DEBUG_LEVEL, " %a\r\n", Ruler2));
CopyMem (Entries, mLevelMask, sizeof (Entries));
CopyMem (Shifts, mLevelShift, sizeof (Shifts));
- SetMem (Indices, sizeof(Indices), 0);
- SetMem (Tables, sizeof(Tables), 0);
- SetMem (Addresses, sizeof(Addresses), 0);
+ SetMem (Indices, sizeof (Indices), 0);
+ SetMem (Tables, sizeof (Tables), 0);
+ SetMem (Addresses, sizeof (Addresses), 0);
Level = GUARDED_HEAP_MAP_TABLE_DEPTH - mMapLevel;
Tables[Level] = mGuardedMemoryMap;
@@ -1137,7 +1697,6 @@ DumpGuardedMemoryBitmap (
while (TRUE) {
if (Indices[Level] > Entries[Level]) {
-
Tables[Level] = 0;
Level -= 1;
RepeatZero = 0;
@@ -1147,40 +1706,33 @@ DumpGuardedMemoryBitmap (
"========================================="
"=========================================\r\n"
));
-
} else {
-
- TableEntry = ((UINT64 *)(UINTN)Tables[Level])[Indices[Level]];
- Address = Addresses[Level];
+ TableEntry = ((UINT64 *)(UINTN)Tables[Level])[Indices[Level]];
+ Address = Addresses[Level];
if (TableEntry == 0) {
-
if (Level == GUARDED_HEAP_MAP_TABLE_DEPTH - 1) {
if (RepeatZero == 0) {
- Uint64ToBinString(TableEntry, String);
+ Uint64ToBinString (TableEntry, String);
DEBUG ((HEAP_GUARD_DEBUG_LEVEL, "%016lx: %a\r\n", Address, String));
} else if (RepeatZero == 1) {
DEBUG ((HEAP_GUARD_DEBUG_LEVEL, "... : ...\r\n"));
}
+
RepeatZero += 1;
}
-
} else if (Level < GUARDED_HEAP_MAP_TABLE_DEPTH - 1) {
-
- Level += 1;
- Tables[Level] = TableEntry;
- Addresses[Level] = Address;
- Indices[Level] = 0;
- RepeatZero = 0;
+ Level += 1;
+ Tables[Level] = TableEntry;
+ Addresses[Level] = Address;
+ Indices[Level] = 0;
+ RepeatZero = 0;
continue;
-
} else {
-
RepeatZero = 0;
- Uint64ToBinString(TableEntry, String);
+ Uint64ToBinString (TableEntry, String);
DEBUG ((HEAP_GUARD_DEBUG_LEVEL, "%016lx: %a\r\n", Address, String));
-
}
}
@@ -1188,10 +1740,8 @@ DumpGuardedMemoryBitmap (
break;
}
- Indices[Level] += 1;
- Address = (Level == 0) ? 0 : Addresses[Level - 1];
- Addresses[Level] = Address | LShiftU64(Indices[Level], Shifts[Level]);
-
+ Indices[Level] += 1;
+ Address = (Level == 0) ? 0 : Addresses[Level - 1];
+ Addresses[Level] = Address | LShiftU64 (Indices[Level], Shifts[Level]);
}
}
-