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>
This commit is contained in:
39
UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/Cet.nasm
Normal file
39
UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/Cet.nasm
Normal file
@@ -0,0 +1,39 @@
|
||||
;------------------------------------------------------------------------------ ;
|
||||
; Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
|
||||
; 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.
|
||||
;
|
||||
;-------------------------------------------------------------------------------
|
||||
|
||||
%include "Nasm.inc"
|
||||
|
||||
SECTION .text
|
||||
|
||||
global ASM_PFX(DisableCet)
|
||||
ASM_PFX(DisableCet):
|
||||
|
||||
; Skip the pushed data for call
|
||||
mov eax, 1
|
||||
INCSSP_EAX
|
||||
|
||||
mov eax, cr4
|
||||
btr eax, 23 ; clear CET
|
||||
mov cr4, eax
|
||||
ret
|
||||
|
||||
global ASM_PFX(EnableCet)
|
||||
ASM_PFX(EnableCet):
|
||||
|
||||
mov eax, cr4
|
||||
bts eax, 23 ; set CET
|
||||
mov cr4, eax
|
||||
|
||||
; use jmp to skip the check for ret
|
||||
pop eax
|
||||
jmp eax
|
||||
|
@@ -1,7 +1,7 @@
|
||||
/** @file
|
||||
Page table manipulation functions for IA-32 processors
|
||||
|
||||
Copyright (c) 2009 - 2017, Intel Corporation. All rights reserved.<BR>
|
||||
Copyright (c) 2009 - 2019, Intel Corporation. All rights reserved.<BR>
|
||||
Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>
|
||||
|
||||
This program and the accompanying materials
|
||||
@@ -16,6 +16,24 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
|
||||
#include "PiSmmCpuDxeSmm.h"
|
||||
|
||||
/**
|
||||
Disable CET.
|
||||
**/
|
||||
VOID
|
||||
EFIAPI
|
||||
DisableCet (
|
||||
VOID
|
||||
);
|
||||
|
||||
/**
|
||||
Enable CET.
|
||||
**/
|
||||
VOID
|
||||
EFIAPI
|
||||
EnableCet (
|
||||
VOID
|
||||
);
|
||||
|
||||
/**
|
||||
Create PageTable for SMM use.
|
||||
|
||||
@@ -138,6 +156,7 @@ SmiPFHandler (
|
||||
}
|
||||
}
|
||||
CpuDeadLoop ();
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
//
|
||||
@@ -152,6 +171,7 @@ SmiPFHandler (
|
||||
DumpModuleInfoByIp (*(UINTN *)(UINTN)SystemContext.SystemContextIa32->Esp);
|
||||
);
|
||||
CpuDeadLoop ();
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
//
|
||||
@@ -171,6 +191,7 @@ SmiPFHandler (
|
||||
}
|
||||
|
||||
CpuDeadLoop ();
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
if (IsSmmCommBufferForbiddenAddress (PFAddress)) {
|
||||
@@ -180,6 +201,7 @@ SmiPFHandler (
|
||||
DumpModuleInfoByIp ((UINTN)SystemContext.SystemContextIa32->Eip);
|
||||
);
|
||||
CpuDeadLoop ();
|
||||
goto Exit;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -212,6 +234,7 @@ SetPageTableAttributes (
|
||||
UINT64 *L3PageTable;
|
||||
BOOLEAN IsSplitted;
|
||||
BOOLEAN PageTableSplitted;
|
||||
BOOLEAN CetEnabled;
|
||||
|
||||
//
|
||||
// Don't mark page table to read-only if heap guard is enabled.
|
||||
@@ -238,6 +261,13 @@ SetPageTableAttributes (
|
||||
// Disable write protection, because we need mark page table to be write protected.
|
||||
// We need *write* page table memory, to mark itself to be *read only*.
|
||||
//
|
||||
CetEnabled = ((AsmReadCr4() & CR4_CET_ENABLE) != 0) ? TRUE : FALSE;
|
||||
if (CetEnabled) {
|
||||
//
|
||||
// CET must be disabled if WP is disabled.
|
||||
//
|
||||
DisableCet();
|
||||
}
|
||||
AsmWriteCr0 (AsmReadCr0() & ~CR0_WP);
|
||||
|
||||
do {
|
||||
@@ -277,6 +307,12 @@ SetPageTableAttributes (
|
||||
// Enable write protection, after page table updated.
|
||||
//
|
||||
AsmWriteCr0 (AsmReadCr0() | CR0_WP);
|
||||
if (CetEnabled) {
|
||||
//
|
||||
// re-enable CET.
|
||||
//
|
||||
EnableCet();
|
||||
}
|
||||
|
||||
return ;
|
||||
}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
;------------------------------------------------------------------------------ ;
|
||||
; Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
|
||||
; Copyright (c) 2016 - 2019, Intel Corporation. All rights reserved.<BR>
|
||||
; 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
|
||||
@@ -19,6 +19,20 @@
|
||||
;-------------------------------------------------------------------------------
|
||||
|
||||
%include "StuffRsbNasm.inc"
|
||||
%include "Nasm.inc"
|
||||
|
||||
%define MSR_IA32_S_CET 0x6A2
|
||||
%define MSR_IA32_CET_SH_STK_EN 0x1
|
||||
%define MSR_IA32_CET_WR_SHSTK_EN 0x2
|
||||
%define MSR_IA32_CET_ENDBR_EN 0x4
|
||||
%define MSR_IA32_CET_LEG_IW_EN 0x8
|
||||
%define MSR_IA32_CET_NO_TRACK_EN 0x10
|
||||
%define MSR_IA32_CET_SUPPRESS_DIS 0x20
|
||||
%define MSR_IA32_CET_SUPPRESS 0x400
|
||||
%define MSR_IA32_CET_TRACKER 0x800
|
||||
%define MSR_IA32_PL0_SSP 0x6A4
|
||||
|
||||
%define CR4_CET 0x800000
|
||||
|
||||
%define MSR_IA32_MISC_ENABLE 0x1A0
|
||||
%define MSR_EFER 0xc0000080
|
||||
@@ -53,6 +67,11 @@ extern ASM_PFX(mXdSupported)
|
||||
global ASM_PFX(gPatchXdSupported)
|
||||
extern ASM_PFX(gSmiHandlerIdtr)
|
||||
|
||||
extern ASM_PFX(mCetSupported)
|
||||
global ASM_PFX(mPatchCetSupported)
|
||||
global ASM_PFX(mPatchCetPl0Ssp)
|
||||
global ASM_PFX(mPatchCetInterruptSsp)
|
||||
|
||||
SECTION .text
|
||||
|
||||
BITS 16
|
||||
@@ -173,11 +192,61 @@ ASM_PFX(gPatchXdSupported):
|
||||
mov ax, [ebx + DSC_SS]
|
||||
mov ss, eax
|
||||
|
||||
; jmp _SmiHandler ; instruction is not needed
|
||||
mov ebx, [esp + 4] ; ebx <- CpuIndex
|
||||
|
||||
; enable CET if supported
|
||||
mov al, strict byte 1 ; source operand may be patched
|
||||
ASM_PFX(mPatchCetSupported):
|
||||
cmp al, 0
|
||||
jz CetDone
|
||||
|
||||
mov ecx, MSR_IA32_S_CET
|
||||
rdmsr
|
||||
push edx
|
||||
push eax
|
||||
|
||||
mov ecx, MSR_IA32_PL0_SSP
|
||||
rdmsr
|
||||
push edx
|
||||
push eax
|
||||
|
||||
mov ecx, MSR_IA32_S_CET
|
||||
mov eax, MSR_IA32_CET_SH_STK_EN
|
||||
xor edx, edx
|
||||
wrmsr
|
||||
|
||||
mov ecx, MSR_IA32_PL0_SSP
|
||||
mov eax, strict dword 0 ; source operand will be patched
|
||||
ASM_PFX(mPatchCetPl0Ssp):
|
||||
xor edx, edx
|
||||
wrmsr
|
||||
mov ecx, cr0
|
||||
btr ecx, 16 ; clear WP
|
||||
mov cr0, ecx
|
||||
mov [eax], eax ; reload SSP, and clear busyflag.
|
||||
xor ecx, ecx
|
||||
mov [eax + 4], ecx
|
||||
|
||||
mov eax, strict dword 0 ; source operand will be patched
|
||||
ASM_PFX(mPatchCetInterruptSsp):
|
||||
cmp eax, 0
|
||||
jz CetInterruptDone
|
||||
mov [eax], eax ; reload SSP, and clear busyflag.
|
||||
xor ecx, ecx
|
||||
mov [eax + 4], ecx
|
||||
CetInterruptDone:
|
||||
|
||||
mov ecx, cr0
|
||||
bts ecx, 16 ; set WP
|
||||
mov cr0, ecx
|
||||
|
||||
mov eax, 0x668 | CR4_CET
|
||||
mov cr4, eax
|
||||
|
||||
SETSSBSY
|
||||
|
||||
CetDone:
|
||||
|
||||
global ASM_PFX(SmiHandler)
|
||||
ASM_PFX(SmiHandler):
|
||||
mov ebx, [esp + 4] ; CPU Index
|
||||
push ebx
|
||||
mov eax, ASM_PFX(CpuSmmDebugEntry)
|
||||
call eax
|
||||
@@ -193,6 +262,25 @@ ASM_PFX(SmiHandler):
|
||||
call eax
|
||||
add esp, 4
|
||||
|
||||
mov eax, ASM_PFX(mCetSupported)
|
||||
mov al, [eax]
|
||||
cmp al, 0
|
||||
jz CetDone2
|
||||
|
||||
mov eax, 0x668
|
||||
mov cr4, eax ; disable CET
|
||||
|
||||
mov ecx, MSR_IA32_PL0_SSP
|
||||
pop eax
|
||||
pop edx
|
||||
wrmsr
|
||||
|
||||
mov ecx, MSR_IA32_S_CET
|
||||
pop eax
|
||||
pop edx
|
||||
wrmsr
|
||||
CetDone2:
|
||||
|
||||
mov eax, ASM_PFX(mXdSupported)
|
||||
mov al, [eax]
|
||||
cmp al, 0
|
||||
@@ -206,6 +294,7 @@ ASM_PFX(SmiHandler):
|
||||
wrmsr
|
||||
|
||||
.7:
|
||||
|
||||
StuffRsb32
|
||||
rsm
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
;------------------------------------------------------------------------------ ;
|
||||
; Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.<BR>
|
||||
; Copyright (c) 2009 - 2019, Intel Corporation. All rights reserved.<BR>
|
||||
; 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
|
||||
@@ -89,7 +89,7 @@ TssSeg:
|
||||
DB 0x80 ; LimitHigh
|
||||
DB 0 ; BaseHigh
|
||||
ExceptionTssSeg:
|
||||
DW TSS_DESC_SIZE ; LimitLow
|
||||
DW EXCEPTION_TSS_DESC_SIZE ; LimitLow
|
||||
DW 0 ; BaseLow
|
||||
DB 0 ; BaseMid
|
||||
DB 0x89
|
||||
@@ -223,6 +223,8 @@ ExceptionTssDescriptor:
|
||||
DW 0 ; Reserved
|
||||
DW 0 ; T
|
||||
DW 0 ; I/O Map Base
|
||||
DD 0 ; SSP
|
||||
EXCEPTION_TSS_DESC_SIZE equ $ - ExceptionTssDescriptor
|
||||
|
||||
ASM_PFX(gcPsd):
|
||||
DB 'PSDSIG '
|
||||
|
@@ -1,7 +1,7 @@
|
||||
/** @file
|
||||
SMM CPU misc functions for Ia32 arch specific.
|
||||
|
||||
Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
|
||||
Copyright (c) 2015 - 2019, Intel Corporation. All rights reserved.<BR>
|
||||
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
|
||||
@@ -19,6 +19,14 @@ extern UINT64 gTaskGateDescriptor;
|
||||
EFI_PHYSICAL_ADDRESS mGdtBuffer;
|
||||
UINTN mGdtBufferSize;
|
||||
|
||||
extern BOOLEAN mCetSupported;
|
||||
extern UINTN mSmmShadowStackSize;
|
||||
|
||||
X86_ASSEMBLY_PATCH_LABEL mPatchCetPl0Ssp;
|
||||
X86_ASSEMBLY_PATCH_LABEL mPatchCetInterruptSsp;
|
||||
UINT32 mCetPl0Ssp;
|
||||
UINT32 mCetInterruptSsp;
|
||||
|
||||
/**
|
||||
Initialize IDT for SMM Stack Guard.
|
||||
|
||||
@@ -62,6 +70,7 @@ InitGdt (
|
||||
UINTN GdtTssTableSize;
|
||||
UINT8 *GdtTssTables;
|
||||
UINTN GdtTableStepSize;
|
||||
UINTN InterruptShadowStack;
|
||||
|
||||
if (FeaturePcdGet (PcdCpuSmmStackGuard)) {
|
||||
//
|
||||
@@ -75,7 +84,7 @@ InitGdt (
|
||||
//
|
||||
gcSmiGdtr.Limit += (UINT16)(2 * sizeof (IA32_SEGMENT_DESCRIPTOR));
|
||||
|
||||
GdtTssTableSize = (gcSmiGdtr.Limit + 1 + TSS_SIZE * 2 + 7) & ~7; // 8 bytes aligned
|
||||
GdtTssTableSize = (gcSmiGdtr.Limit + 1 + TSS_SIZE + EXCEPTION_TSS_SIZE + 7) & ~7; // 8 bytes aligned
|
||||
mGdtBufferSize = GdtTssTableSize * gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus;
|
||||
//
|
||||
// IA32 Stack Guard need use task switch to switch stack that need
|
||||
@@ -88,7 +97,7 @@ InitGdt (
|
||||
GdtTableStepSize = GdtTssTableSize;
|
||||
|
||||
for (Index = 0; Index < gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus; Index++) {
|
||||
CopyMem (GdtTssTables + GdtTableStepSize * Index, (VOID*)(UINTN)gcSmiGdtr.Base, gcSmiGdtr.Limit + 1 + TSS_SIZE * 2);
|
||||
CopyMem (GdtTssTables + GdtTableStepSize * Index, (VOID*)(UINTN)gcSmiGdtr.Base, gcSmiGdtr.Limit + 1 + TSS_SIZE + EXCEPTION_TSS_SIZE);
|
||||
//
|
||||
// Fixup TSS descriptors
|
||||
//
|
||||
@@ -110,6 +119,14 @@ InitGdt (
|
||||
//
|
||||
*(UINTN *)(TssBase + TSS_IA32_ESP_OFFSET) = mSmmStackArrayBase + EFI_PAGE_SIZE + Index * mSmmStackSize;
|
||||
*(UINT32 *)(TssBase + TSS_IA32_CR3_OFFSET) = Cr3;
|
||||
|
||||
//
|
||||
// Setup ShadowStack for stack switch
|
||||
//
|
||||
if ((PcdGet32 (PcdControlFlowEnforcementPropertyMask) != 0) && mCetSupported) {
|
||||
InterruptShadowStack = (UINTN)(mSmmStackArrayBase + mSmmStackSize + EFI_PAGES_TO_SIZE (1) - sizeof(UINT64) + (mSmmStackSize + mSmmShadowStackSize) * Index);
|
||||
*(UINT32 *)(TssBase + TSS_IA32_SSP_OFFSET) = (UINT32)InterruptShadowStack;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//
|
||||
@@ -157,3 +174,37 @@ TransferApToSafeState (
|
||||
//
|
||||
ASSERT (FALSE);
|
||||
}
|
||||
|
||||
/**
|
||||
Initialize the shadow stack related data structure.
|
||||
|
||||
@param CpuIndex The index of CPU.
|
||||
@param ShadowStack The bottom of the shadow stack for this CPU.
|
||||
**/
|
||||
VOID
|
||||
InitShadowStack (
|
||||
IN UINTN CpuIndex,
|
||||
IN VOID *ShadowStack
|
||||
)
|
||||
{
|
||||
UINTN SmmShadowStackSize;
|
||||
|
||||
if ((PcdGet32 (PcdControlFlowEnforcementPropertyMask) != 0) && mCetSupported) {
|
||||
SmmShadowStackSize = EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (PcdGet32 (PcdCpuSmmShadowStackSize)));
|
||||
if (FeaturePcdGet (PcdCpuSmmStackGuard)) {
|
||||
SmmShadowStackSize += EFI_PAGES_TO_SIZE (2);
|
||||
}
|
||||
mCetPl0Ssp = (UINT32)((UINTN)ShadowStack + SmmShadowStackSize - sizeof(UINT64));
|
||||
PatchInstructionX86 (mPatchCetPl0Ssp, mCetPl0Ssp, 4);
|
||||
DEBUG ((DEBUG_INFO, "mCetPl0Ssp - 0x%x\n", mCetPl0Ssp));
|
||||
DEBUG ((DEBUG_INFO, "ShadowStack - 0x%x\n", ShadowStack));
|
||||
DEBUG ((DEBUG_INFO, " SmmShadowStackSize - 0x%x\n", SmmShadowStackSize));
|
||||
|
||||
if (FeaturePcdGet (PcdCpuSmmStackGuard)) {
|
||||
mCetInterruptSsp = (UINT32)((UINTN)ShadowStack + EFI_PAGES_TO_SIZE(1) - sizeof(UINT64));
|
||||
PatchInstructionX86 (mPatchCetInterruptSsp, mCetInterruptSsp, 4);
|
||||
DEBUG ((DEBUG_INFO, "mCetInterruptSsp - 0x%x\n", mCetInterruptSsp));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user