summaryrefslogtreecommitdiffstats
path: root/UefiCpuPkg/PiSmmCpuDxeSmm
diff options
context:
space:
mode:
authorSheng, W <w.sheng@intel.com>2021-11-12 09:40:28 +0800
committermergify[bot] <37929162+mergify[bot]@users.noreply.github.com>2021-11-12 12:50:19 +0000
commit455b0347a7c55d3842e87b20259659a22f7e62a5 (patch)
tree6fdc4bbd12ba2f5943bd5a4ff27e9c91bfe5ead0 /UefiCpuPkg/PiSmmCpuDxeSmm
parent466ebdd2e0919c1538d03cd59833704bd5e1c028 (diff)
downloadedk2-455b0347a7c55d3842e87b20259659a22f7e62a5.tar.gz
edk2-455b0347a7c55d3842e87b20259659a22f7e62a5.tar.bz2
edk2-455b0347a7c55d3842e87b20259659a22f7e62a5.zip
UefiCpuPkg/PiSmmCpuDxeSmm: Use SMM Interrupt Shadow Stack
When CET shadow stack feature is enabled, it needs to use IST for the exceptions, and uses interrupt shadow stack for the stack switch. Shadow stack should be 32 bytes aligned. Check IST field, when clear shadow stack token busy bit when using retf. REF: https://bugzilla.tianocore.org/show_bug.cgi?id=3728 Signed-off-by: Sheng Wei <w.sheng@intel.com> Cc: Eric Dong <eric.dong@intel.com> Cc: Ray Ni <ray.ni@intel.com> Cc: Rahul Kumar <rahul1.kumar@intel.com> Reviewed-by: Ray Ni <ray.ni@intel.com>
Diffstat (limited to 'UefiCpuPkg/PiSmmCpuDxeSmm')
-rw-r--r--UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.c61
-rw-r--r--UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h14
-rw-r--r--UefiCpuPkg/PiSmmCpuDxeSmm/X64/PageTbl.c12
-rw-r--r--UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmmFuncsArch.c81
4 files changed, 111 insertions, 57 deletions
diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.c b/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.c
index 67ad9a4c07..2b2e1a5390 100644
--- a/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.c
+++ b/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.c
@@ -861,35 +861,58 @@ PiCpuSmmEntry (
mSmmStackSize = EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (PcdGet32 (PcdCpuSmmStackSize)));
if (FeaturePcdGet (PcdCpuSmmStackGuard)) {
//
- // 2 more pages is allocated for each processor.
- // one is guard page and the other is known good stack.
+ // SMM Stack Guard Enabled
+ // 2 more pages is allocated for each processor, one is guard page and the other is known good stack.
//
- // +-------------------------------------------+-----+-------------------------------------------+
- // | Known Good Stack | Guard Page | SMM Stack | ... | Known Good Stack | Guard Page | SMM Stack |
- // +-------------------------------------------+-----+-------------------------------------------+
- // | | | |
- // |<-------------- Processor 0 -------------->| |<-------------- Processor n -------------->|
+ // +--------------------------------------------------+-----+--------------------------------------------------+
+ // | Known Good Stack | Guard Page | SMM Stack | ... | Known Good Stack | Guard Page | SMM Stack |
+ // +--------------------------------------------------+-----+--------------------------------------------------+
+ // | 4K | 4K PcdCpuSmmStackSize| | 4K | 4K PcdCpuSmmStackSize|
+ // |<---------------- mSmmStackSize ----------------->| |<---------------- mSmmStackSize ----------------->|
+ // | | | |
+ // |<------------------ Processor 0 ----------------->| |<------------------ Processor n ----------------->|
//
mSmmStackSize += EFI_PAGES_TO_SIZE (2);
}
mSmmShadowStackSize = 0;
if ((PcdGet32 (PcdControlFlowEnforcementPropertyMask) != 0) && mCetSupported) {
- //
- // Append Shadow Stack after normal stack
- //
- // |= Stacks
- // +--------------------------------------------------+---------------------------------------------------------------+
- // | Known Good Stack | Guard Page | SMM Stack | Known Good Shadow Stack | Guard Page | SMM Shadow Stack |
- // +--------------------------------------------------+---------------------------------------------------------------+
- // | |PcdCpuSmmStackSize| |PcdCpuSmmShadowStackSize|
- // |<---------------- mSmmStackSize ----------------->|<--------------------- mSmmShadowStackSize ------------------->|
- // | |
- // |<-------------------------------------------- Processor N ------------------------------------------------------->|
- //
mSmmShadowStackSize = EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (PcdGet32 (PcdCpuSmmShadowStackSize)));
+
if (FeaturePcdGet (PcdCpuSmmStackGuard)) {
+ //
+ // SMM Stack Guard Enabled
+ // Append Shadow Stack after normal stack
+ // 2 more pages is allocated for each processor, one is guard page and the other is known good shadow stack.
+ //
+ // |= Stacks
+ // +--------------------------------------------------+---------------------------------------------------------------+
+ // | Known Good Stack | Guard Page | SMM Stack | Known Good Shadow Stack | Guard Page | SMM Shadow Stack |
+ // +--------------------------------------------------+---------------------------------------------------------------+
+ // | 4K | 4K |PcdCpuSmmStackSize| 4K | 4K |PcdCpuSmmShadowStackSize|
+ // |<---------------- mSmmStackSize ----------------->|<--------------------- mSmmShadowStackSize ------------------->|
+ // | |
+ // |<-------------------------------------------- Processor N ------------------------------------------------------->|
+ //
mSmmShadowStackSize += EFI_PAGES_TO_SIZE (2);
+ } else {
+ //
+ // SMM Stack Guard Disabled (Known Good Stack is still required for potential stack switch.)
+ // Append Shadow Stack after normal stack with 1 more page as known good shadow stack.
+ // 1 more pages is allocated for each processor, it is known good stack.
+ //
+ //
+ // |= Stacks
+ // +-------------------------------------+--------------------------------------------------+
+ // | Known Good Stack | SMM Stack | Known Good Shadow Stack | SMM Shadow Stack |
+ // +-------------------------------------+--------------------------------------------------+
+ // | 4K |PcdCpuSmmStackSize| 4K |PcdCpuSmmShadowStackSize|
+ // |<---------- mSmmStackSize ---------->|<--------------- mSmmShadowStackSize ------------>|
+ // | |
+ // |<-------------------------------- Processor N ----------------------------------------->|
+ //
+ mSmmShadowStackSize += EFI_PAGES_TO_SIZE (1);
+ mSmmStackSize += EFI_PAGES_TO_SIZE (1);
}
}
diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h b/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h
index 2248a8c5ee..fc9b748948 100644
--- a/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h
+++ b/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h
@@ -558,6 +558,20 @@ InitializeIDTSmmStackGuard (
);
/**
+ Initialize IDT IST Field.
+
+ @param[in] ExceptionType Exception type.
+ @param[in] Ist IST value.
+
+**/
+VOID
+EFIAPI
+InitializeIdtIst (
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN UINT8 Ist
+ );
+
+/**
Initialize Gdt for all processors.
@param[in] Cr3 CR3 value.
diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/X64/PageTbl.c b/UefiCpuPkg/PiSmmCpuDxeSmm/X64/PageTbl.c
index d6f8dd94d3..211a78b1c4 100644
--- a/UefiCpuPkg/PiSmmCpuDxeSmm/X64/PageTbl.c
+++ b/UefiCpuPkg/PiSmmCpuDxeSmm/X64/PageTbl.c
@@ -481,7 +481,17 @@ SmmInitPageTable (
// Additional SMM IDT initialization for SMM stack guard
//
if (FeaturePcdGet (PcdCpuSmmStackGuard)) {
- InitializeIDTSmmStackGuard ();
+ DEBUG ((DEBUG_INFO, "Initialize IDT IST field for SMM Stack Guard\n"));
+ InitializeIdtIst (EXCEPT_IA32_PAGE_FAULT, 1);
+ }
+
+ //
+ // Additional SMM IDT initialization for SMM CET shadow stack
+ //
+ if ((PcdGet32 (PcdControlFlowEnforcementPropertyMask) != 0) && mCetSupported) {
+ DEBUG ((DEBUG_INFO, "Initialize IDT IST field for SMM Shadow Stack\n"));
+ InitializeIdtIst (EXCEPT_IA32_PAGE_FAULT, 1);
+ InitializeIdtIst (EXCEPT_IA32_MACHINE_CHECK, 1);
}
//
diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmmFuncsArch.c b/UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmmFuncsArch.c
index ca3f5ff91a..ce7afce6d4 100644
--- a/UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmmFuncsArch.c
+++ b/UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmmFuncsArch.c
@@ -24,24 +24,24 @@ UINT32 mCetInterruptSspTable;
UINTN mSmmInterruptSspTables;
/**
- Initialize IDT for SMM Stack Guard.
+ Initialize IDT IST Field.
+
+ @param[in] ExceptionType Exception type.
+ @param[in] Ist IST value.
**/
VOID
EFIAPI
-InitializeIDTSmmStackGuard (
- VOID
+InitializeIdtIst (
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN UINT8 Ist
)
{
IA32_IDT_GATE_DESCRIPTOR *IdtGate;
- //
- // If SMM Stack Guard feature is enabled, set the IST field of
- // the interrupt gate for Page Fault Exception to be 1
- //
IdtGate = (IA32_IDT_GATE_DESCRIPTOR *)gcSmiIdtr.Base;
- IdtGate += EXCEPT_IA32_PAGE_FAULT;
- IdtGate->Bits.Reserved_0 = 1;
+ IdtGate += ExceptionType;
+ IdtGate->Bits.Reserved_0 = Ist;
}
/**
@@ -89,7 +89,7 @@ InitGdt (
GdtDescriptor->Bits.BaseMid = (UINT8)((UINTN)TssBase >> 16);
GdtDescriptor->Bits.BaseHigh = (UINT8)((UINTN)TssBase >> 24);
- if (FeaturePcdGet (PcdCpuSmmStackGuard)) {
+ if ((FeaturePcdGet (PcdCpuSmmStackGuard)) || ((PcdGet32 (PcdControlFlowEnforcementPropertyMask) != 0) && mCetSupported)) {
//
// Setup top of known good stack as IST1 for each processor.
//
@@ -177,8 +177,16 @@ InitShadowStack (
if ((PcdGet32 (PcdControlFlowEnforcementPropertyMask) != 0) && mCetSupported) {
SmmShadowStackSize = EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (PcdGet32 (PcdCpuSmmShadowStackSize)));
+ //
+ // Add 1 page as known good shadow stack
+ //
+ SmmShadowStackSize += EFI_PAGES_TO_SIZE (1);
+
if (FeaturePcdGet (PcdCpuSmmStackGuard)) {
- SmmShadowStackSize += EFI_PAGES_TO_SIZE (2);
+ //
+ // Add one guard page between Known Good Shadow Stack and SMM Shadow Stack.
+ //
+ SmmShadowStackSize += EFI_PAGES_TO_SIZE (1);
}
mCetPl0Ssp = (UINT32)((UINTN)ShadowStack + SmmShadowStackSize - sizeof(UINT64));
PatchInstructionX86 (mPatchCetPl0Ssp, mCetPl0Ssp, 4);
@@ -186,33 +194,32 @@ InitShadowStack (
DEBUG ((DEBUG_INFO, "ShadowStack - 0x%x\n", ShadowStack));
DEBUG ((DEBUG_INFO, " SmmShadowStackSize - 0x%x\n", SmmShadowStackSize));
- if (FeaturePcdGet (PcdCpuSmmStackGuard)) {
- if (mSmmInterruptSspTables == 0) {
- mSmmInterruptSspTables = (UINTN)AllocateZeroPool(sizeof(UINT64) * 8 * gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus);
- ASSERT (mSmmInterruptSspTables != 0);
- DEBUG ((DEBUG_INFO, "mSmmInterruptSspTables - 0x%x\n", mSmmInterruptSspTables));
- }
-
- //
- // The highest address on the stack (0xFF8) is a save-previous-ssp token pointing to a location that is 40 bytes away - 0xFD0.
- // The supervisor shadow stack token is just above it at address 0xFF0. This is where the interrupt SSP table points.
- // So when an interrupt of exception occurs, we can use SAVESSP/RESTORESSP/CLEARSSBUSY for the supervisor shadow stack,
- // due to the reason the RETF in SMM exception handler cannot clear the BUSY flag with same CPL.
- // (only IRET or RETF with different CPL can clear BUSY flag)
- // Please refer to UefiCpuPkg/Library/CpuExceptionHandlerLib/X64 for the full stack frame at runtime.
- //
- InterruptSsp = (UINT32)((UINTN)ShadowStack + EFI_PAGES_TO_SIZE(1) - sizeof(UINT64));
- *(UINT64 *)(UINTN)InterruptSsp = (InterruptSsp - sizeof(UINT64) * 4) | 0x2;
- mCetInterruptSsp = InterruptSsp - sizeof(UINT64);
-
- mCetInterruptSspTable = (UINT32)(UINTN)(mSmmInterruptSspTables + sizeof(UINT64) * 8 * CpuIndex);
- InterruptSspTable = (UINT64 *)(UINTN)mCetInterruptSspTable;
- InterruptSspTable[1] = mCetInterruptSsp;
- PatchInstructionX86 (mPatchCetInterruptSsp, mCetInterruptSsp, 4);
- PatchInstructionX86 (mPatchCetInterruptSspTable, mCetInterruptSspTable, 4);
- DEBUG ((DEBUG_INFO, "mCetInterruptSsp - 0x%x\n", mCetInterruptSsp));
- DEBUG ((DEBUG_INFO, "mCetInterruptSspTable - 0x%x\n", mCetInterruptSspTable));
+ if (mSmmInterruptSspTables == 0) {
+ mSmmInterruptSspTables = (UINTN)AllocateZeroPool(sizeof(UINT64) * 8 * gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus);
+ ASSERT (mSmmInterruptSspTables != 0);
+ DEBUG ((DEBUG_INFO, "mSmmInterruptSspTables - 0x%x\n", mSmmInterruptSspTables));
}
+
+ //
+ // The highest address on the stack (0xFE0) is a save-previous-ssp token pointing to a location that is 40 bytes away - 0xFB8.
+ // The supervisor shadow stack token is just above it at address 0xFD8. This is where the interrupt SSP table points.
+ // So when an interrupt of exception occurs, we can use SAVESSP/RESTORESSP/CLEARSSBUSY for the supervisor shadow stack,
+ // due to the reason the RETF in SMM exception handler cannot clear the BUSY flag with same CPL.
+ // (only IRET or RETF with different CPL can clear BUSY flag)
+ // Please refer to UefiCpuPkg/Library/CpuExceptionHandlerLib/X64 for the full stack frame at runtime.
+ // According to SDM (ver. 075 June 2021), shadow stack should be 32 bytes aligned.
+ //
+ InterruptSsp = (UINT32)(((UINTN)ShadowStack + EFI_PAGES_TO_SIZE(1) - (sizeof(UINT64) * 4)) & ~0x1f);
+ *(UINT64 *)(UINTN)InterruptSsp = (InterruptSsp - sizeof(UINT64) * 4) | 0x2;
+ mCetInterruptSsp = InterruptSsp - sizeof(UINT64);
+
+ mCetInterruptSspTable = (UINT32)(UINTN)(mSmmInterruptSspTables + sizeof(UINT64) * 8 * CpuIndex);
+ InterruptSspTable = (UINT64 *)(UINTN)mCetInterruptSspTable;
+ InterruptSspTable[1] = mCetInterruptSsp;
+ PatchInstructionX86 (mPatchCetInterruptSsp, mCetInterruptSsp, 4);
+ PatchInstructionX86 (mPatchCetInterruptSspTable, mCetInterruptSspTable, 4);
+ DEBUG ((DEBUG_INFO, "mCetInterruptSsp - 0x%x\n", mCetInterruptSsp));
+ DEBUG ((DEBUG_INFO, "mCetInterruptSspTable - 0x%x\n", mCetInterruptSspTable));
}
}