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:
Jiewen Yao
2019-02-22 21:30:36 +08:00
committed by Liming Gao
parent 0d25074cbc
commit 3eb69b081c
19 changed files with 807 additions and 47 deletions

View File

@@ -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,11 +19,26 @@
;-------------------------------------------------------------------------------
%include "StuffRsbNasm.inc"
%include "Nasm.inc"
;
; Variables referrenced by C code
;
%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 MSR_IA32_INTERRUPT_SSP_TABLE_ADDR 0x6A8
%define CR4_CET 0x800000
%define MSR_IA32_MISC_ENABLE 0x1A0
%define MSR_EFER 0xc0000080
%define MSR_EFER_XD 0x800
@@ -63,6 +78,12 @@ global ASM_PFX(gPatchSmiCr3)
global ASM_PFX(gcSmiHandlerTemplate)
global ASM_PFX(gcSmiHandlerSize)
extern ASM_PFX(mCetSupported)
global ASM_PFX(mPatchCetSupported)
global ASM_PFX(mPatchCetPl0Ssp)
global ASM_PFX(mPatchCetInterruptSsp)
global ASM_PFX(mPatchCetInterruptSspTable)
DEFAULT REL
SECTION .text
@@ -174,8 +195,71 @@ SmiHandlerIdtrAbsAddr:
mov ax, [rbx + DSC_SS]
mov ss, eax
_SmiHandler:
mov rbx, [rsp + 0x8] ; rcx <- CpuIndex
mov rbx, [rsp + 0x8] ; rbx <- 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 rdx
push rax
mov ecx, MSR_IA32_PL0_SSP
rdmsr
push rdx
push rax
mov ecx, MSR_IA32_INTERRUPT_SSP_TABLE_ADDR
rdmsr
push rdx
push rax
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 rcx, cr0
btr ecx, 16 ; clear WP
mov cr0, rcx
mov [eax], eax ; reload SSP, and clear busyflag.
xor ecx, ecx
mov [eax + 4], ecx
mov ecx, MSR_IA32_INTERRUPT_SSP_TABLE_ADDR
mov eax, strict dword 0 ; source operand will be patched
ASM_PFX(mPatchCetInterruptSspTable):
xor edx, edx
wrmsr
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 rcx, cr0
bts ecx, 16 ; set WP
mov cr0, rcx
mov eax, 0x668 | CR4_CET
mov cr4, rax
SETSSBSY
CetDone:
;
; Save FP registers
@@ -209,6 +293,31 @@ CpuSmmDebugExitAbsAddr:
add rsp, 0x200
mov rax, strict qword 0 ; mov rax, ASM_PFX(mCetSupported)
mCetSupportedAbsAddr:
mov al, [rax]
cmp al, 0
jz CetDone2
mov eax, 0x668
mov cr4, rax ; disable CET
mov ecx, MSR_IA32_INTERRUPT_SSP_TABLE_ADDR
pop rax
pop rdx
wrmsr
mov ecx, MSR_IA32_PL0_SSP
pop rax
pop rdx
wrmsr
mov ecx, MSR_IA32_S_CET
pop rax
pop rdx
wrmsr
CetDone2:
mov rax, strict qword 0 ; lea rax, [ASM_PFX(mXdSupported)]
mXdSupportedAbsAddr:
mov al, [rax]
@@ -223,6 +332,7 @@ mXdSupportedAbsAddr:
wrmsr
.1:
StuffRsb64
rsm
@@ -257,4 +367,8 @@ ASM_PFX(PiSmmCpuSmiEntryFixupAddress):
lea rax, [ASM_PFX(mXdSupported)]
lea rcx, [mXdSupportedAbsAddr]
mov qword [rcx - 8], rax
lea rax, [ASM_PFX(mCetSupported)]
lea rcx, [mCetSupportedAbsAddr]
mov qword [rcx - 8], rax
ret