2015-10-19 21:13:13 +02:00
|
|
|
/** @file
|
|
|
|
Page table manipulation functions for IA-32 processors
|
|
|
|
|
2023-06-07 09:46:58 +02:00
|
|
|
Copyright (c) 2009 - 2023, Intel Corporation. All rights reserved.<BR>
|
2017-02-26 18:43:07 +01:00
|
|
|
Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>
|
|
|
|
|
2019-04-04 01:07:22 +02:00
|
|
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
2015-10-19 21:13:13 +02:00
|
|
|
|
|
|
|
**/
|
|
|
|
|
|
|
|
#include "PiSmmCpuDxeSmm.h"
|
|
|
|
|
|
|
|
/**
|
|
|
|
Create PageTable for SMM use.
|
|
|
|
|
|
|
|
@return PageTable Address
|
|
|
|
|
|
|
|
**/
|
|
|
|
UINT32
|
|
|
|
SmmInitPageTable (
|
|
|
|
VOID
|
|
|
|
)
|
|
|
|
{
|
|
|
|
UINTN PageFaultHandlerHookAddress;
|
|
|
|
IA32_IDT_GATE_DESCRIPTOR *IdtEntry;
|
2016-11-16 15:25:56 +01:00
|
|
|
EFI_STATUS Status;
|
2015-10-19 21:13:13 +02:00
|
|
|
|
|
|
|
//
|
|
|
|
// Initialize spin lock
|
|
|
|
//
|
2016-03-22 03:15:53 +01:00
|
|
|
InitializeSpinLock (mPFLock);
|
2015-10-19 21:13:13 +02:00
|
|
|
|
2017-08-24 04:59:14 +02:00
|
|
|
mPhysicalAddressBits = 32;
|
2023-06-07 09:46:58 +02:00
|
|
|
mPagingMode = PagingPae;
|
2017-08-24 04:59:14 +02:00
|
|
|
|
2018-08-20 05:35:58 +02:00
|
|
|
if (FeaturePcdGet (PcdCpuSmmProfileEnable) ||
|
|
|
|
HEAP_GUARD_NONSTOP_MODE ||
|
|
|
|
NULL_DETECTION_NONSTOP_MODE)
|
|
|
|
{
|
2015-10-19 21:13:13 +02:00
|
|
|
//
|
|
|
|
// Set own Page Fault entry instead of the default one, because SMM Profile
|
|
|
|
// feature depends on IRET instruction to do Single Step
|
|
|
|
//
|
|
|
|
PageFaultHandlerHookAddress = (UINTN)PageFaultIdtHandlerSmmProfile;
|
|
|
|
IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *)gcSmiIdtr.Base;
|
|
|
|
IdtEntry += EXCEPT_IA32_PAGE_FAULT;
|
|
|
|
IdtEntry->Bits.OffsetLow = (UINT16)PageFaultHandlerHookAddress;
|
|
|
|
IdtEntry->Bits.Reserved_0 = 0;
|
|
|
|
IdtEntry->Bits.GateType = IA32_IDT_GATE_TYPE_INTERRUPT_32;
|
|
|
|
IdtEntry->Bits.OffsetHigh = (UINT16)(PageFaultHandlerHookAddress >> 16);
|
|
|
|
} else {
|
|
|
|
//
|
|
|
|
// Register SMM Page Fault Handler
|
|
|
|
//
|
2016-11-16 15:25:56 +01:00
|
|
|
Status = SmmRegisterExceptionHandler (&mSmmCpuService, EXCEPT_IA32_PAGE_FAULT, SmiPFHandler);
|
|
|
|
ASSERT_EFI_ERROR (Status);
|
2015-10-19 21:13:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Additional SMM IDT initialization for SMM stack guard
|
|
|
|
//
|
|
|
|
if (FeaturePcdGet (PcdCpuSmmStackGuard)) {
|
|
|
|
InitializeIDTSmmStackGuard ();
|
|
|
|
}
|
2021-12-05 23:54:17 +01:00
|
|
|
|
2023-05-15 09:47:54 +02:00
|
|
|
return GenSmmPageTable (PagingPae, mPhysicalAddressBits);
|
2015-10-19 21:13:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
Page Fault handler for SMM use.
|
|
|
|
|
|
|
|
**/
|
|
|
|
VOID
|
|
|
|
SmiDefaultPFHandler (
|
|
|
|
VOID
|
|
|
|
)
|
|
|
|
{
|
|
|
|
CpuDeadLoop ();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
ThePage Fault handler wrapper for SMM use.
|
|
|
|
|
|
|
|
@param InterruptType Defines the type of interrupt or exception that
|
|
|
|
occurred on the processor.This parameter is processor architecture specific.
|
|
|
|
@param SystemContext A pointer to the processor context when
|
|
|
|
the interrupt occurred on the processor.
|
|
|
|
**/
|
|
|
|
VOID
|
|
|
|
EFIAPI
|
|
|
|
SmiPFHandler (
|
2017-04-01 13:39:22 +02:00
|
|
|
IN EFI_EXCEPTION_TYPE InterruptType,
|
|
|
|
IN EFI_SYSTEM_CONTEXT SystemContext
|
2015-10-19 21:13:13 +02:00
|
|
|
)
|
|
|
|
{
|
|
|
|
UINTN PFAddress;
|
2016-11-22 08:05:11 +01:00
|
|
|
UINTN GuardPageAddress;
|
|
|
|
UINTN CpuIndex;
|
2015-10-19 21:13:13 +02:00
|
|
|
|
|
|
|
ASSERT (InterruptType == EXCEPT_IA32_PAGE_FAULT);
|
|
|
|
|
2016-03-22 03:15:53 +01:00
|
|
|
AcquireSpinLock (mPFLock);
|
2015-10-19 21:13:13 +02:00
|
|
|
|
|
|
|
PFAddress = AsmReadCr2 ();
|
|
|
|
|
2016-11-22 08:05:11 +01:00
|
|
|
//
|
|
|
|
// If a page fault occurs in SMRAM range, it might be in a SMM stack guard page,
|
|
|
|
// or SMM page protection violation.
|
|
|
|
//
|
|
|
|
if ((PFAddress >= mCpuHotPlugData.SmrrBase) &&
|
2015-10-19 21:13:13 +02:00
|
|
|
(PFAddress < (mCpuHotPlugData.SmrrBase + mCpuHotPlugData.SmrrSize)))
|
|
|
|
{
|
2017-04-01 13:39:22 +02:00
|
|
|
DumpCpuContext (InterruptType, SystemContext);
|
2016-11-22 08:05:11 +01:00
|
|
|
CpuIndex = GetCpuIndex ();
|
|
|
|
GuardPageAddress = (mSmmStackArrayBase + EFI_PAGE_SIZE + CpuIndex * mSmmStackSize);
|
|
|
|
if ((FeaturePcdGet (PcdCpuSmmStackGuard)) &&
|
|
|
|
(PFAddress >= GuardPageAddress) &&
|
|
|
|
(PFAddress < (GuardPageAddress + EFI_PAGE_SIZE)))
|
|
|
|
{
|
|
|
|
DEBUG ((DEBUG_ERROR, "SMM stack overflow!\n"));
|
|
|
|
} else {
|
|
|
|
if ((SystemContext.SystemContextIa32->ExceptionData & IA32_PF_EC_ID) != 0) {
|
|
|
|
DEBUG ((DEBUG_ERROR, "SMM exception at execution (0x%x)\n", PFAddress));
|
|
|
|
DEBUG_CODE (
|
|
|
|
DumpModuleInfoByIp (*(UINTN *)(UINTN)SystemContext.SystemContextIa32->Esp);
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
DEBUG ((DEBUG_ERROR, "SMM exception at access (0x%x)\n", PFAddress));
|
|
|
|
DEBUG_CODE (
|
|
|
|
DumpModuleInfoByIp ((UINTN)SystemContext.SystemContextIa32->Eip);
|
|
|
|
);
|
|
|
|
}
|
2018-08-20 05:35:58 +02:00
|
|
|
|
|
|
|
if (HEAP_GUARD_NONSTOP_MODE) {
|
|
|
|
GuardPagePFHandler (SystemContext.SystemContextIa32->ExceptionData);
|
|
|
|
goto Exit;
|
|
|
|
}
|
2016-11-22 08:05:11 +01:00
|
|
|
}
|
2021-12-05 23:54:17 +01:00
|
|
|
|
2015-10-19 21:13:13 +02:00
|
|
|
CpuDeadLoop ();
|
UefiCpuPkg/PiSmmCpu: Add Shadow Stack Support for X86 SMM.
REF: https://bugzilla.tianocore.org/show_bug.cgi?id=1521
We scan the SMM code with ROPgadget.
http://shell-storm.org/project/ROPgadget/
https://github.com/JonathanSalwan/ROPgadget/tree/master
This tool reports the gadget in SMM driver.
This patch enabled CET ShadowStack for X86 SMM.
If CET is supported, SMM will enable CET ShadowStack.
SMM CET will save the OS CET context at SmmEntry and
restore OS CET context at SmmExit.
Test:
1) test Intel internal platform (x64 only, CET enabled/disabled)
Boot test:
CET supported or not supported CPU
on CET supported platform
CET enabled/disabled
PcdCpuSmmCetEnable enabled/disabled
Single core/Multiple core
PcdCpuSmmStackGuard enabled/disabled
PcdCpuSmmProfileEnable enabled/disabled
PcdCpuSmmStaticPageTable enabled/disabled
CET exception test:
#CF generated with PcdCpuSmmStackGuard enabled/disabled.
Other exception test:
#PF for normal stack overflow
#PF for NX protection
#PF for RO protection
CET env test:
Launch SMM in CET enabled/disabled environment (DXE) - no impact to DXE
The test case can be found at
https://github.com/jyao1/SecurityEx/tree/master/ControlFlowPkg
2) test ovmf (both IA32 and X64 SMM, CET disabled only)
test OvmfIa32/Ovmf3264, with -D SMM_REQUIRE.
qemu-system-x86_64.exe -machine q35,smm=on -smp 4
-serial file:serial.log
-drive if=pflash,format=raw,unit=0,file=OVMF_CODE.fd,readonly=on
-drive if=pflash,format=raw,unit=1,file=OVMF_VARS.fd
QEMU emulator version 3.1.0 (v3.1.0-11736-g7a30e7adb0-dirty)
3) not tested
IA32 CET enabled platform
Cc: Eric Dong <eric.dong@intel.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Yao Jiewen <jiewen.yao@intel.com>
Reviewed-by: Ray Ni <ray.ni@intel.com>
Regression-tested-by: Laszlo Ersek <lersek@redhat.com>
2019-02-22 14:30:36 +01:00
|
|
|
goto Exit;
|
2015-10-19 21:13:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//
|
2017-12-06 12:02:04 +01:00
|
|
|
// If a page fault occurs in non-SMRAM range.
|
2015-10-19 21:13:13 +02:00
|
|
|
//
|
|
|
|
if ((PFAddress < mCpuHotPlugData.SmrrBase) ||
|
|
|
|
(PFAddress >= mCpuHotPlugData.SmrrBase + mCpuHotPlugData.SmrrSize))
|
|
|
|
{
|
|
|
|
if ((SystemContext.SystemContextIa32->ExceptionData & IA32_PF_EC_ID) != 0) {
|
2017-12-06 12:02:04 +01:00
|
|
|
DumpCpuContext (InterruptType, SystemContext);
|
2016-10-23 17:19:52 +02:00
|
|
|
DEBUG ((DEBUG_ERROR, "Code executed on IP(0x%x) out of SMM range after SMM is locked!\n", PFAddress));
|
2015-10-19 21:13:13 +02:00
|
|
|
DEBUG_CODE (
|
|
|
|
DumpModuleInfoByIp (*(UINTN *)(UINTN)SystemContext.SystemContextIa32->Esp);
|
|
|
|
);
|
|
|
|
CpuDeadLoop ();
|
UefiCpuPkg/PiSmmCpu: Add Shadow Stack Support for X86 SMM.
REF: https://bugzilla.tianocore.org/show_bug.cgi?id=1521
We scan the SMM code with ROPgadget.
http://shell-storm.org/project/ROPgadget/
https://github.com/JonathanSalwan/ROPgadget/tree/master
This tool reports the gadget in SMM driver.
This patch enabled CET ShadowStack for X86 SMM.
If CET is supported, SMM will enable CET ShadowStack.
SMM CET will save the OS CET context at SmmEntry and
restore OS CET context at SmmExit.
Test:
1) test Intel internal platform (x64 only, CET enabled/disabled)
Boot test:
CET supported or not supported CPU
on CET supported platform
CET enabled/disabled
PcdCpuSmmCetEnable enabled/disabled
Single core/Multiple core
PcdCpuSmmStackGuard enabled/disabled
PcdCpuSmmProfileEnable enabled/disabled
PcdCpuSmmStaticPageTable enabled/disabled
CET exception test:
#CF generated with PcdCpuSmmStackGuard enabled/disabled.
Other exception test:
#PF for normal stack overflow
#PF for NX protection
#PF for RO protection
CET env test:
Launch SMM in CET enabled/disabled environment (DXE) - no impact to DXE
The test case can be found at
https://github.com/jyao1/SecurityEx/tree/master/ControlFlowPkg
2) test ovmf (both IA32 and X64 SMM, CET disabled only)
test OvmfIa32/Ovmf3264, with -D SMM_REQUIRE.
qemu-system-x86_64.exe -machine q35,smm=on -smp 4
-serial file:serial.log
-drive if=pflash,format=raw,unit=0,file=OVMF_CODE.fd,readonly=on
-drive if=pflash,format=raw,unit=1,file=OVMF_VARS.fd
QEMU emulator version 3.1.0 (v3.1.0-11736-g7a30e7adb0-dirty)
3) not tested
IA32 CET enabled platform
Cc: Eric Dong <eric.dong@intel.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Yao Jiewen <jiewen.yao@intel.com>
Reviewed-by: Ray Ni <ray.ni@intel.com>
Regression-tested-by: Laszlo Ersek <lersek@redhat.com>
2019-02-22 14:30:36 +01:00
|
|
|
goto Exit;
|
2015-10-19 21:13:13 +02:00
|
|
|
}
|
2018-08-20 05:35:58 +02:00
|
|
|
|
|
|
|
//
|
|
|
|
// If NULL pointer was just accessed
|
|
|
|
//
|
|
|
|
if (((PcdGet8 (PcdNullPointerDetectionPropertyMask) & BIT1) != 0) &&
|
|
|
|
(PFAddress < EFI_PAGE_SIZE))
|
|
|
|
{
|
|
|
|
DumpCpuContext (InterruptType, SystemContext);
|
|
|
|
DEBUG ((DEBUG_ERROR, "!!! NULL pointer access !!!\n"));
|
|
|
|
DEBUG_CODE (
|
|
|
|
DumpModuleInfoByIp ((UINTN)SystemContext.SystemContextIa32->Eip);
|
|
|
|
);
|
|
|
|
|
|
|
|
if (NULL_DETECTION_NONSTOP_MODE) {
|
|
|
|
GuardPagePFHandler (SystemContext.SystemContextIa32->ExceptionData);
|
|
|
|
goto Exit;
|
|
|
|
}
|
|
|
|
|
|
|
|
CpuDeadLoop ();
|
UefiCpuPkg/PiSmmCpu: Add Shadow Stack Support for X86 SMM.
REF: https://bugzilla.tianocore.org/show_bug.cgi?id=1521
We scan the SMM code with ROPgadget.
http://shell-storm.org/project/ROPgadget/
https://github.com/JonathanSalwan/ROPgadget/tree/master
This tool reports the gadget in SMM driver.
This patch enabled CET ShadowStack for X86 SMM.
If CET is supported, SMM will enable CET ShadowStack.
SMM CET will save the OS CET context at SmmEntry and
restore OS CET context at SmmExit.
Test:
1) test Intel internal platform (x64 only, CET enabled/disabled)
Boot test:
CET supported or not supported CPU
on CET supported platform
CET enabled/disabled
PcdCpuSmmCetEnable enabled/disabled
Single core/Multiple core
PcdCpuSmmStackGuard enabled/disabled
PcdCpuSmmProfileEnable enabled/disabled
PcdCpuSmmStaticPageTable enabled/disabled
CET exception test:
#CF generated with PcdCpuSmmStackGuard enabled/disabled.
Other exception test:
#PF for normal stack overflow
#PF for NX protection
#PF for RO protection
CET env test:
Launch SMM in CET enabled/disabled environment (DXE) - no impact to DXE
The test case can be found at
https://github.com/jyao1/SecurityEx/tree/master/ControlFlowPkg
2) test ovmf (both IA32 and X64 SMM, CET disabled only)
test OvmfIa32/Ovmf3264, with -D SMM_REQUIRE.
qemu-system-x86_64.exe -machine q35,smm=on -smp 4
-serial file:serial.log
-drive if=pflash,format=raw,unit=0,file=OVMF_CODE.fd,readonly=on
-drive if=pflash,format=raw,unit=1,file=OVMF_VARS.fd
QEMU emulator version 3.1.0 (v3.1.0-11736-g7a30e7adb0-dirty)
3) not tested
IA32 CET enabled platform
Cc: Eric Dong <eric.dong@intel.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Yao Jiewen <jiewen.yao@intel.com>
Reviewed-by: Ray Ni <ray.ni@intel.com>
Regression-tested-by: Laszlo Ersek <lersek@redhat.com>
2019-02-22 14:30:36 +01:00
|
|
|
goto Exit;
|
2018-08-20 05:35:58 +02:00
|
|
|
}
|
|
|
|
|
2016-11-24 06:36:56 +01:00
|
|
|
if (IsSmmCommBufferForbiddenAddress (PFAddress)) {
|
2017-12-06 12:02:04 +01:00
|
|
|
DumpCpuContext (InterruptType, SystemContext);
|
2016-11-24 06:36:56 +01:00
|
|
|
DEBUG ((DEBUG_ERROR, "Access SMM communication forbidden address (0x%x)!\n", PFAddress));
|
|
|
|
DEBUG_CODE (
|
|
|
|
DumpModuleInfoByIp ((UINTN)SystemContext.SystemContextIa32->Eip);
|
|
|
|
);
|
|
|
|
CpuDeadLoop ();
|
UefiCpuPkg/PiSmmCpu: Add Shadow Stack Support for X86 SMM.
REF: https://bugzilla.tianocore.org/show_bug.cgi?id=1521
We scan the SMM code with ROPgadget.
http://shell-storm.org/project/ROPgadget/
https://github.com/JonathanSalwan/ROPgadget/tree/master
This tool reports the gadget in SMM driver.
This patch enabled CET ShadowStack for X86 SMM.
If CET is supported, SMM will enable CET ShadowStack.
SMM CET will save the OS CET context at SmmEntry and
restore OS CET context at SmmExit.
Test:
1) test Intel internal platform (x64 only, CET enabled/disabled)
Boot test:
CET supported or not supported CPU
on CET supported platform
CET enabled/disabled
PcdCpuSmmCetEnable enabled/disabled
Single core/Multiple core
PcdCpuSmmStackGuard enabled/disabled
PcdCpuSmmProfileEnable enabled/disabled
PcdCpuSmmStaticPageTable enabled/disabled
CET exception test:
#CF generated with PcdCpuSmmStackGuard enabled/disabled.
Other exception test:
#PF for normal stack overflow
#PF for NX protection
#PF for RO protection
CET env test:
Launch SMM in CET enabled/disabled environment (DXE) - no impact to DXE
The test case can be found at
https://github.com/jyao1/SecurityEx/tree/master/ControlFlowPkg
2) test ovmf (both IA32 and X64 SMM, CET disabled only)
test OvmfIa32/Ovmf3264, with -D SMM_REQUIRE.
qemu-system-x86_64.exe -machine q35,smm=on -smp 4
-serial file:serial.log
-drive if=pflash,format=raw,unit=0,file=OVMF_CODE.fd,readonly=on
-drive if=pflash,format=raw,unit=1,file=OVMF_VARS.fd
QEMU emulator version 3.1.0 (v3.1.0-11736-g7a30e7adb0-dirty)
3) not tested
IA32 CET enabled platform
Cc: Eric Dong <eric.dong@intel.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Yao Jiewen <jiewen.yao@intel.com>
Reviewed-by: Ray Ni <ray.ni@intel.com>
Regression-tested-by: Laszlo Ersek <lersek@redhat.com>
2019-02-22 14:30:36 +01:00
|
|
|
goto Exit;
|
2016-11-24 06:36:56 +01:00
|
|
|
}
|
2015-10-19 21:13:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (FeaturePcdGet (PcdCpuSmmProfileEnable)) {
|
|
|
|
SmmProfilePFHandler (
|
|
|
|
SystemContext.SystemContextIa32->Eip,
|
|
|
|
SystemContext.SystemContextIa32->ExceptionData
|
|
|
|
);
|
|
|
|
} else {
|
2017-04-01 13:39:22 +02:00
|
|
|
DumpCpuContext (InterruptType, SystemContext);
|
2015-10-19 21:13:13 +02:00
|
|
|
SmiDefaultPFHandler ();
|
|
|
|
}
|
|
|
|
|
2018-08-20 05:35:58 +02:00
|
|
|
Exit:
|
2016-03-22 03:15:53 +01:00
|
|
|
ReleaseSpinLock (mPFLock);
|
2015-10-19 21:13:13 +02:00
|
|
|
}
|
2016-10-23 17:19:52 +02:00
|
|
|
|
2019-04-01 10:16:01 +02:00
|
|
|
/**
|
|
|
|
This function returns with no action for 32 bit.
|
|
|
|
|
|
|
|
@param[out] *Cr2 Pointer to variable to hold CR2 register value.
|
|
|
|
**/
|
|
|
|
VOID
|
|
|
|
SaveCr2 (
|
|
|
|
OUT UINTN *Cr2
|
|
|
|
)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
This function returns with no action for 32 bit.
|
|
|
|
|
|
|
|
@param[in] Cr2 Value to write into CR2 register.
|
|
|
|
**/
|
|
|
|
VOID
|
|
|
|
RestoreCr2 (
|
|
|
|
IN UINTN Cr2
|
|
|
|
)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2019-08-26 00:13:17 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
Return whether access to non-SMRAM is restricted.
|
|
|
|
|
|
|
|
@retval TRUE Access to non-SMRAM is restricted.
|
|
|
|
@retval FALSE Access to non-SMRAM is not restricted.
|
2019-11-14 12:00:10 +01:00
|
|
|
**/
|
2019-08-26 00:13:17 +02:00
|
|
|
BOOLEAN
|
|
|
|
IsRestrictedMemoryAccess (
|
|
|
|
VOID
|
|
|
|
)
|
|
|
|
{
|
|
|
|
return TRUE;
|
|
|
|
}
|