MdeModulePkg/PiSmmCore: Implement heap guard feature for SMM mode

This feature makes use of paging mechanism to add a hidden (not present)
page just before and after the allocated memory block. If the code tries
to access memory outside of the allocated part, page fault exception will
be triggered.

This feature is controlled by three PCDs:

    gEfiMdeModulePkgTokenSpaceGuid.PcdHeapGuardPropertyMask
    gEfiMdeModulePkgTokenSpaceGuid.PcdHeapGuardPoolType
    gEfiMdeModulePkgTokenSpaceGuid.PcdHeapGuardPageType

BIT2 and BIT3 of PcdHeapGuardPropertyMask can be used to enable or disable
memory guard for SMM page and pool respectively. PcdHeapGuardPoolType and/or
PcdHeapGuardPageType are used to enable or disable guard for specific type
of memory. For example, we can turn on guard only for EfiRuntimeServicesCode
and EfiRuntimeServicesData by setting the PCD with value 0x60.

Pool memory is not ususally integer multiple of one page, and is more likely
less than a page. There's no way to monitor the overflow at both top and
bottom of pool memory. BIT7 of PcdHeapGuardPropertyMask is used to control
how to position the head of pool memory so that it's easier to catch memory
overflow in memory growing direction or in decreasing direction.

Cc: Eric Dong <eric.dong@intel.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Ruiyu Ni <ruiyu.ni@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: Jiewen Yao <jiewen.yao@intel.com>
Regression-tested-by: Laszlo Ersek <lersek@redhat.com>
This commit is contained in:
Jian J Wang
2017-11-14 10:56:37 +08:00
committed by Star Zeng
parent af4f4b3468
commit 2930ef9809
7 changed files with 2064 additions and 28 deletions

View File

@@ -64,6 +64,8 @@ LIST_ENTRY mFreeMemoryMapEntryList = INITIALIZE_LIST_HEAD_VARIABLE (mFreeMemor
@param[out] Memory A pointer to receive the base allocated memory
address.
@param[in] AddRegion If this memory is new added region.
@param[in] NeedGuard Flag to indicate Guard page is needed
or not
@retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in spec.
@retval EFI_NOT_FOUND Could not allocate pages match the requirement.
@@ -77,7 +79,8 @@ SmmInternalAllocatePagesEx (
IN EFI_MEMORY_TYPE MemoryType,
IN UINTN NumberOfPages,
OUT EFI_PHYSICAL_ADDRESS *Memory,
IN BOOLEAN AddRegion
IN BOOLEAN AddRegion,
IN BOOLEAN NeedGuard
);
/**
@@ -112,7 +115,8 @@ AllocateMemoryMapEntry (
EfiRuntimeServicesData,
EFI_SIZE_TO_PAGES (RUNTIME_PAGE_ALLOCATION_GRANULARITY),
&Mem,
TRUE
TRUE,
FALSE
);
ASSERT_EFI_ERROR (Status);
if(!EFI_ERROR (Status)) {
@@ -688,6 +692,8 @@ InternalAllocAddress (
@param[out] Memory A pointer to receive the base allocated memory
address.
@param[in] AddRegion If this memory is new added region.
@param[in] NeedGuard Flag to indicate Guard page is needed
or not
@retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in spec.
@retval EFI_NOT_FOUND Could not allocate pages match the requirement.
@@ -701,7 +707,8 @@ SmmInternalAllocatePagesEx (
IN EFI_MEMORY_TYPE MemoryType,
IN UINTN NumberOfPages,
OUT EFI_PHYSICAL_ADDRESS *Memory,
IN BOOLEAN AddRegion
IN BOOLEAN AddRegion,
IN BOOLEAN NeedGuard
)
{
UINTN RequestedAddress;
@@ -723,6 +730,21 @@ SmmInternalAllocatePagesEx (
case AllocateAnyPages:
RequestedAddress = (UINTN)(-1);
case AllocateMaxAddress:
if (NeedGuard) {
*Memory = InternalAllocMaxAddressWithGuard (
&mSmmMemoryMap,
NumberOfPages,
RequestedAddress,
MemoryType
);
if (*Memory == (UINTN)-1) {
return EFI_OUT_OF_RESOURCES;
} else {
ASSERT (VerifyMemoryGuard (*Memory, NumberOfPages) == TRUE);
return EFI_SUCCESS;
}
}
*Memory = InternalAllocMaxAddress (
&mSmmMemoryMap,
NumberOfPages,
@@ -766,6 +788,8 @@ SmmInternalAllocatePagesEx (
@param[in] NumberOfPages The number of pages to allocate.
@param[out] Memory A pointer to receive the base allocated memory
address.
@param[in] NeedGuard Flag to indicate Guard page is needed
or not
@retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in spec.
@retval EFI_NOT_FOUND Could not allocate pages match the requirement.
@@ -779,10 +803,12 @@ SmmInternalAllocatePages (
IN EFI_ALLOCATE_TYPE Type,
IN EFI_MEMORY_TYPE MemoryType,
IN UINTN NumberOfPages,
OUT EFI_PHYSICAL_ADDRESS *Memory
OUT EFI_PHYSICAL_ADDRESS *Memory,
IN BOOLEAN NeedGuard
)
{
return SmmInternalAllocatePagesEx (Type, MemoryType, NumberOfPages, Memory, FALSE);
return SmmInternalAllocatePagesEx (Type, MemoryType, NumberOfPages, Memory,
FALSE, NeedGuard);
}
/**
@@ -811,8 +837,11 @@ SmmAllocatePages (
)
{
EFI_STATUS Status;
BOOLEAN NeedGuard;
Status = SmmInternalAllocatePages (Type, MemoryType, NumberOfPages, Memory);
NeedGuard = IsPageTypeToGuard (MemoryType, Type);
Status = SmmInternalAllocatePages (Type, MemoryType, NumberOfPages, Memory,
NeedGuard);
if (!EFI_ERROR (Status)) {
SmmCoreUpdateProfile (
(EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0),
@@ -931,6 +960,7 @@ SmmInternalFreePagesEx (
@param[in] Memory Base address of memory being freed.
@param[in] NumberOfPages The number of pages to free.
@param[in] IsGuarded Is the memory to free guarded or not.
@retval EFI_NOT_FOUND Could not find the entry that covers the range.
@retval EFI_INVALID_PARAMETER Address not aligned, Address is zero or NumberOfPages is zero.
@@ -941,9 +971,13 @@ EFI_STATUS
EFIAPI
SmmInternalFreePages (
IN EFI_PHYSICAL_ADDRESS Memory,
IN UINTN NumberOfPages
IN UINTN NumberOfPages,
IN BOOLEAN IsGuarded
)
{
if (IsGuarded) {
return SmmInternalFreePagesExWithGuard (Memory, NumberOfPages, FALSE);
}
return SmmInternalFreePagesEx (Memory, NumberOfPages, FALSE);
}
@@ -966,8 +1000,10 @@ SmmFreePages (
)
{
EFI_STATUS Status;
BOOLEAN IsGuarded;
Status = SmmInternalFreePages (Memory, NumberOfPages);
IsGuarded = IsHeapGuardEnabled () && IsMemoryGuarded (Memory);
Status = SmmInternalFreePages (Memory, NumberOfPages, IsGuarded);
if (!EFI_ERROR (Status)) {
SmmCoreUpdateProfile (
(EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0),