Skip to content

Commit

Permalink
UefiCpuPkg/PiSmmCpu: Add Shadow Stack Support for X86 SMM.
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
jyao1 authored and lgao4 committed Feb 28, 2019
1 parent 0d25074 commit 3eb69b0
Show file tree
Hide file tree
Showing 19 changed files with 807 additions and 47 deletions.
23 changes: 21 additions & 2 deletions UefiCpuPkg/Include/Library/SmmCpuFeaturesLib.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/** @file
Library that provides CPU specific functions to support the PiSmmCpuDxeSmm module.
Copyright (c) 2015, 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
Expand Down Expand Up @@ -160,14 +160,33 @@ SmmCpuFeaturesGetSmiHandlerSize (
than zero and is called by the CPU that was elected as monarch during System
Management Mode initialization.
//
// Append Shadow Stack after normal stack
//
// |= SmiStack
// +--------------------------------------------------+---------------------------------------------------------------+
// | Known Good Stack | Guard Page | SMM Stack | Known Good Shadow Stack | Guard Page | SMM Shadow Stack |
// +--------------------------------------------------+---------------------------------------------------------------+
// | |PcdCpuSmmStackSize| |PcdCpuSmmShadowStackSize|
// |<-------------------- StackSize ----------------->|<------------------------- ShadowStackSize ------------------->|
// | |
// |<-------------------------------------------- Processor N ------------------------------------------------------->|
// | low address (bottom) high address (top) |
//
@param[in] CpuIndex The index of the CPU to install the custom SMI handler.
The value must be between 0 and the NumberOfCpus field
in the System Management System Table (SMST).
@param[in] SmBase The SMBASE address for the CPU specified by CpuIndex.
@param[in] SmiStack The stack to use when an SMI is processed by the
@param[in] SmiStack The bottom of stack to use when an SMI is processed by the
the CPU specified by CpuIndex.
@param[in] StackSize The size, in bytes, if the stack used when an SMI is
processed by the CPU specified by CpuIndex.
StackSize should be PcdCpuSmmStackSize, with 2 more pages
if PcdCpuSmmStackGuard is true.
If ShadowStack is enabled, the shadow stack is allocated
after the normal Stack. The size is PcdCpuSmmShadowStackSize.
with 2 more pages if PcdCpuSmmStackGuard is true.
@param[in] GdtBase The base address of the GDT to use when an SMI is
processed by the CPU specified by CpuIndex.
@param[in] GdtSize The size, in bytes, of the GDT used when an SMI is
Expand Down
39 changes: 39 additions & 0 deletions UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/Cet.nasm
Original file line number Diff line number Diff line change
@@ -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

38 changes: 37 additions & 1 deletion UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/PageTbl.c
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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.
Expand Down Expand Up @@ -138,6 +156,7 @@ SmiPFHandler (
}
}
CpuDeadLoop ();
goto Exit;
}

//
Expand All @@ -152,6 +171,7 @@ SmiPFHandler (
DumpModuleInfoByIp (*(UINTN *)(UINTN)SystemContext.SystemContextIa32->Esp);
);
CpuDeadLoop ();
goto Exit;
}

//
Expand All @@ -171,6 +191,7 @@ SmiPFHandler (
}

CpuDeadLoop ();
goto Exit;
}

if (IsSmmCommBufferForbiddenAddress (PFAddress)) {
Expand All @@ -180,6 +201,7 @@ SmiPFHandler (
DumpModuleInfoByIp ((UINTN)SystemContext.SystemContextIa32->Eip);
);
CpuDeadLoop ();
goto Exit;
}
}

Expand Down Expand Up @@ -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.
Expand All @@ -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 {
Expand Down Expand Up @@ -277,6 +307,12 @@ SetPageTableAttributes (
// Enable write protection, after page table updated.
//
AsmWriteCr0 (AsmReadCr0() | CR0_WP);
if (CetEnabled) {
//
// re-enable CET.
//
EnableCet();
}

return ;
}
99 changes: 94 additions & 5 deletions UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiEntry.nasm
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand All @@ -206,6 +294,7 @@ ASM_PFX(SmiHandler):
wrmsr

.7:

StuffRsb32
rsm

Expand Down
6 changes: 4 additions & 2 deletions UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiException.nasm
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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 '
Expand Down
Loading

0 comments on commit 3eb69b0

Please sign in to comment.