From af4f4b3468aa239c61418ff899bfd239eae57b2d Mon Sep 17 00:00:00 2001 From: Jian J Wang Date: Tue, 14 Nov 2017 10:56:14 +0800 Subject: [PATCH] UefiCpuPkg/PiSmmCpuDxeSmm: Add SmmMemoryAttribute protocol Heap guard makes use of paging mechanism to implement its functionality. But there's no protocol or library available to change page attribute in SMM mode. A new protocol gEdkiiSmmMemoryAttributeProtocolGuid is introduced to make it happen. This protocol provide three interfaces struct _EDKII_SMM_MEMORY_ATTRIBUTE_PROTOCOL { EDKII_SMM_GET_MEMORY_ATTRIBUTES GetMemoryAttributes; EDKII_SMM_SET_MEMORY_ATTRIBUTES SetMemoryAttributes; EDKII_SMM_CLEAR_MEMORY_ATTRIBUTES ClearMemoryAttributes; }; Since heap guard feature need to update page attributes. The page table should not set to be read-only if heap guard feature is enabled for SMM mode. Otherwise this feature cannot work. Cc: Eric Dong Cc: Jiewen Yao Cc: Laszlo Ersek Cc: Ruiyu Ni Suggested-by: Ayellet Wolman Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Jian J Wang Reviewed-by: Jiewen Yao Regression-tested-by: Laszlo Ersek --- UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/PageTbl.c | 10 ++ UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.c | 20 +++ UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h | 98 +++++++++++ UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf | 2 + .../PiSmmCpuDxeSmm/SmmCpuMemoryManagement.c | 163 ++++++++++++++++++ UefiCpuPkg/PiSmmCpuDxeSmm/X64/PageTbl.c | 15 +- 6 files changed, 307 insertions(+), 1 deletion(-) diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/PageTbl.c b/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/PageTbl.c index 641a1d69a2..9447a31ef5 100644 --- a/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/PageTbl.c +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/PageTbl.c @@ -196,6 +196,16 @@ SetPageTableAttributes ( BOOLEAN IsSplitted; BOOLEAN PageTableSplitted; + // + // Don't mark page table as read-only if heap guard is enabled. + // + // BIT2: SMM page guard enabled + // BIT3: SMM pool guard enabled + // + if ((PcdGet8 (PcdHeapGuardPropertyMask) & (BIT3 | BIT2)) != 0) { + return ; + } + DEBUG ((DEBUG_INFO, "SetPageTableAttributes\n")); // diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.c b/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.c index 282d2e6981..6c6d742c95 100755 --- a/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.c +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.c @@ -76,6 +76,15 @@ EFI_SMM_CPU_PROTOCOL mSmmCpu = { SmmWriteSaveState }; +/// +/// SMM Memory Attribute Protocol instance +/// +EDKII_SMM_MEMORY_ATTRIBUTE_PROTOCOL mSmmMemoryAttribute = { + EdkiiSmmGetMemoryAttributes, + EdkiiSmmSetMemoryAttributes, + EdkiiSmmClearMemoryAttributes +}; + EFI_CPU_INTERRUPT_HANDLER mExternalVectorTable[EXCEPTION_VECTOR_NUMBER]; // @@ -893,6 +902,17 @@ PiCpuSmmEntry ( ); ASSERT_EFI_ERROR (Status); + // + // Install the SMM Memory Attribute Protocol into SMM protocol database + // + Status = gSmst->SmmInstallProtocolInterface ( + &mSmmCpuHandle, + &gEdkiiSmmMemoryAttributeProtocolGuid, + EFI_NATIVE_INTERFACE, + &mSmmMemoryAttribute + ); + ASSERT_EFI_ERROR (Status); + // // Expose address of CPU Hot Plug Data structure if CPU hot plug is supported. // diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h b/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h index 1cf85c1481..a2d5f55045 100644 --- a/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h @@ -25,6 +25,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include #include #include +#include #include #include @@ -1068,4 +1069,101 @@ TransferApToSafeState ( IN UINTN NumberToFinishAddress ); +/** + This function set given attributes of the memory region specified by + BaseAddress and Length. + + @param This The EDKII_SMM_MEMORY_ATTRIBUTE_PROTOCOL instance. + @param BaseAddress The physical address that is the start address of + a memory region. + @param Length The size in bytes of the memory region. + @param Attributes The bit mask of attributes to set for the memory + region. + + @retval EFI_SUCCESS The attributes were set for the memory region. + @retval EFI_INVALID_PARAMETER Length is zero. + Attributes specified an illegal combination of + attributes that cannot be set together. + @retval EFI_UNSUPPORTED The processor does not support one or more + bytes of the memory resource range specified + by BaseAddress and Length. + The bit mask of attributes is not support for + the memory resource range specified by + BaseAddress and Length. + +**/ +EFI_STATUS +EFIAPI +EdkiiSmmSetMemoryAttributes ( + IN EDKII_SMM_MEMORY_ATTRIBUTE_PROTOCOL *This, + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length, + IN UINT64 Attributes + ); + +/** + This function clears given attributes of the memory region specified by + BaseAddress and Length. + + @param This The EDKII_SMM_MEMORY_ATTRIBUTE_PROTOCOL instance. + @param BaseAddress The physical address that is the start address of + a memory region. + @param Length The size in bytes of the memory region. + @param Attributes The bit mask of attributes to set for the memory + region. + + @retval EFI_SUCCESS The attributes were set for the memory region. + @retval EFI_INVALID_PARAMETER Length is zero. + Attributes specified an illegal combination of + attributes that cannot be set together. + @retval EFI_UNSUPPORTED The processor does not support one or more + bytes of the memory resource range specified + by BaseAddress and Length. + The bit mask of attributes is not support for + the memory resource range specified by + BaseAddress and Length. + +**/ +EFI_STATUS +EFIAPI +EdkiiSmmClearMemoryAttributes ( + IN EDKII_SMM_MEMORY_ATTRIBUTE_PROTOCOL *This, + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length, + IN UINT64 Attributes + ); + +/** + This function retrieve the attributes of the memory region specified by + BaseAddress and Length. If different attributes are got from different part + of the memory region, EFI_NO_MAPPING will be returned. + + @param This The EDKII_SMM_MEMORY_ATTRIBUTE_PROTOCOL instance. + @param BaseAddress The physical address that is the start address of + a memory region. + @param Length The size in bytes of the memory region. + @param Attributes Pointer to attributes returned. + + @retval EFI_SUCCESS The attributes got for the memory region. + @retval EFI_INVALID_PARAMETER Length is zero. + Attributes is NULL. + @retval EFI_NO_MAPPING Attributes are not consistent cross the memory + region. + @retval EFI_UNSUPPORTED The processor does not support one or more + bytes of the memory resource range specified + by BaseAddress and Length. + The bit mask of attributes is not support for + the memory resource range specified by + BaseAddress and Length. + +**/ +EFI_STATUS +EFIAPI +EdkiiSmmGetMemoryAttributes ( + IN EDKII_SMM_MEMORY_ATTRIBUTE_PROTOCOL *This, + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length, + IN UINT64 *Attributes + ); + #endif diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf b/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf index 31cb215342..9edd162feb 100644 --- a/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf @@ -129,6 +129,7 @@ gEfiSmmCpuProtocolGuid ## PRODUCES gEfiSmmReadyToLockProtocolGuid ## NOTIFY gEfiSmmCpuServiceProtocolGuid ## PRODUCES + gEdkiiSmmMemoryAttributeProtocolGuid ## PRODUCES [Guids] gEfiAcpiVariableGuid ## SOMETIMES_CONSUMES ## HOB # it is used for S3 boot. @@ -160,6 +161,7 @@ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiS3Enable ## CONSUMES gEfiMdeModulePkgTokenSpaceGuid.PcdPteMemoryEncryptionAddressOrMask ## CONSUMES gEfiMdeModulePkgTokenSpaceGuid.PcdNullPointerDetectionPropertyMask ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdHeapGuardPropertyMask ## CONSUMES [Depex] gEfiMpServiceProtocolGuid diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/SmmCpuMemoryManagement.c b/UefiCpuPkg/PiSmmCpuDxeSmm/SmmCpuMemoryManagement.c index 3ad5256f1e..55c04c7aa7 100644 --- a/UefiCpuPkg/PiSmmCpuDxeSmm/SmmCpuMemoryManagement.c +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/SmmCpuMemoryManagement.c @@ -1120,3 +1120,166 @@ IsSmmCommBufferForbiddenAddress ( } return FALSE; } + +/** + This function set given attributes of the memory region specified by + BaseAddress and Length. + + @param This The EDKII_SMM_MEMORY_ATTRIBUTE_PROTOCOL instance. + @param BaseAddress The physical address that is the start address of + a memory region. + @param Length The size in bytes of the memory region. + @param Attributes The bit mask of attributes to set for the memory + region. + + @retval EFI_SUCCESS The attributes were set for the memory region. + @retval EFI_INVALID_PARAMETER Length is zero. + Attributes specified an illegal combination of + attributes that cannot be set together. + @retval EFI_UNSUPPORTED The processor does not support one or more + bytes of the memory resource range specified + by BaseAddress and Length. + The bit mask of attributes is not support for + the memory resource range specified by + BaseAddress and Length. + +**/ +EFI_STATUS +EFIAPI +EdkiiSmmSetMemoryAttributes ( + IN EDKII_SMM_MEMORY_ATTRIBUTE_PROTOCOL *This, + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length, + IN UINT64 Attributes + ) +{ + return SmmSetMemoryAttributes (BaseAddress, Length, Attributes); +} + +/** + This function clears given attributes of the memory region specified by + BaseAddress and Length. + + @param This The EDKII_SMM_MEMORY_ATTRIBUTE_PROTOCOL instance. + @param BaseAddress The physical address that is the start address of + a memory region. + @param Length The size in bytes of the memory region. + @param Attributes The bit mask of attributes to set for the memory + region. + + @retval EFI_SUCCESS The attributes were set for the memory region. + @retval EFI_INVALID_PARAMETER Length is zero. + Attributes specified an illegal combination of + attributes that cannot be set together. + @retval EFI_UNSUPPORTED The processor does not support one or more + bytes of the memory resource range specified + by BaseAddress and Length. + The bit mask of attributes is not support for + the memory resource range specified by + BaseAddress and Length. + +**/ +EFI_STATUS +EFIAPI +EdkiiSmmClearMemoryAttributes ( + IN EDKII_SMM_MEMORY_ATTRIBUTE_PROTOCOL *This, + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length, + IN UINT64 Attributes + ) +{ + return SmmClearMemoryAttributes (BaseAddress, Length, Attributes); +} + +/** + This function retrieve the attributes of the memory region specified by + BaseAddress and Length. If different attributes are got from different part + of the memory region, EFI_NO_MAPPING will be returned. + + @param This The EDKII_SMM_MEMORY_ATTRIBUTE_PROTOCOL instance. + @param BaseAddress The physical address that is the start address of + a memory region. + @param Length The size in bytes of the memory region. + @param Attributes Pointer to attributes returned. + + @retval EFI_SUCCESS The attributes got for the memory region. + @retval EFI_INVALID_PARAMETER Length is zero. + Attributes is NULL. + @retval EFI_NO_MAPPING Attributes are not consistent cross the memory + region. + @retval EFI_UNSUPPORTED The processor does not support one or more + bytes of the memory resource range specified + by BaseAddress and Length. + The bit mask of attributes is not support for + the memory resource range specified by + BaseAddress and Length. + +**/ +EFI_STATUS +EFIAPI +EdkiiSmmGetMemoryAttributes ( + IN EDKII_SMM_MEMORY_ATTRIBUTE_PROTOCOL *This, + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length, + OUT UINT64 *Attributes + ) +{ + EFI_PHYSICAL_ADDRESS Address; + UINT64 *PageEntry; + UINT64 MemAttr; + PAGE_ATTRIBUTE PageAttr; + INT64 Size; + + if (Length < SIZE_4KB || Attributes == NULL) { + return EFI_INVALID_PARAMETER; + } + + Size = (INT64)Length; + MemAttr = (UINT64)-1; + + do { + + PageEntry = GetPageTableEntry (BaseAddress, &PageAttr); + if (PageEntry == NULL || PageAttr == PageNone) { + return EFI_UNSUPPORTED; + } + + // + // If the memory range is cross page table boundary, make sure they + // share the same attribute. Return EFI_NO_MAPPING if not. + // + *Attributes = GetAttributesFromPageEntry (PageEntry); + if (MemAttr != (UINT64)-1 && *Attributes != MemAttr) { + return EFI_NO_MAPPING; + } + + switch (PageAttr) { + case Page4K: + Address = *PageEntry & ~mAddressEncMask & PAGING_4K_ADDRESS_MASK_64; + Size -= (SIZE_4KB - (BaseAddress - Address)); + BaseAddress += (SIZE_4KB - (BaseAddress - Address)); + break; + + case Page2M: + Address = *PageEntry & ~mAddressEncMask & PAGING_2M_ADDRESS_MASK_64; + Size -= SIZE_2MB - (BaseAddress - Address); + BaseAddress += SIZE_2MB - (BaseAddress - Address); + break; + + case Page1G: + Address = *PageEntry & ~mAddressEncMask & PAGING_1G_ADDRESS_MASK_64; + Size -= SIZE_1GB - (BaseAddress - Address); + BaseAddress += SIZE_1GB - (BaseAddress - Address); + break; + + default: + return EFI_UNSUPPORTED; + } + + MemAttr = *Attributes; + + } while (Size > 0); + + return EFI_SUCCESS; +} + diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/X64/PageTbl.c b/UefiCpuPkg/PiSmmCpuDxeSmm/X64/PageTbl.c index f3791ce897..1da4b5506c 100644 --- a/UefiCpuPkg/PiSmmCpuDxeSmm/X64/PageTbl.c +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/X64/PageTbl.c @@ -914,7 +914,20 @@ SetPageTableAttributes ( BOOLEAN IsSplitted; BOOLEAN PageTableSplitted; - if (!mCpuSmmStaticPageTable) { + // + // Don't do this if + // - no static page table; or + // - SMM heap guard feature enabled + // BIT2: SMM page guard enabled + // BIT3: SMM pool guard enabled + // + if (!mCpuSmmStaticPageTable || + (PcdGet8 (PcdHeapGuardPropertyMask) & (BIT3 | BIT2)) != 0) { + // + // Static paging and heap guard should not be enabled at the same time. + // + ASSERT (!(mCpuSmmStaticPageTable && + (PcdGet8 (PcdHeapGuardPropertyMask) & (BIT3 | BIT2)) != 0)); return ; } -- 2.39.2