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,6 +1,6 @@
/** @file
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
@@ -38,6 +38,23 @@ PAGE_ATTRIBUTE_TABLE mPageAttributeTable[] = {
{Page1G, SIZE_1GB, PAGING_1G_ADDRESS_MASK_64},
};
UINTN mInternalGr3;
/**
Set the internal page table base address.
If it is non zero, further MemoryAttribute modification will be on this page table.
If it is zero, further MemoryAttribute modification will be on real page table.
@param Cr3 page table base.
**/
VOID
SetPageTableBase (
IN UINTN Cr3
)
{
mInternalGr3 = Cr3;
}
/**
Return page table base.
@@ -48,6 +65,9 @@ GetPageTableBase (
VOID
)
{
if (mInternalGr3 != 0) {
return mInternalGr3;
}
return (AsmReadCr3 () & PAGING_4K_ADDRESS_MASK_64);
}
@@ -220,6 +240,17 @@ ConvertPageEntryAttribute (
if ((Attributes & EFI_MEMORY_RO) != 0) {
if (IsSet) {
NewPageEntry &= ~(UINT64)IA32_PG_RW;
if (mInternalGr3 != 0) {
// Environment setup
// ReadOnly page need set Dirty bit for shadow stack
NewPageEntry |= IA32_PG_D;
// Clear user bit for supervisor shadow stack
NewPageEntry &= ~(UINT64)IA32_PG_U;
} else {
// Runtime update
// Clear dirty bit for non shadow stack, to protect RO page.
NewPageEntry &= ~(UINT64)IA32_PG_D;
}
} else {
NewPageEntry |= IA32_PG_RW;
}
@@ -661,7 +692,59 @@ SmmClearMemoryAttributes (
return SmmClearMemoryAttributesEx (BaseAddress, Length, Attributes, NULL);
}
/**
Set ShadowStack memory.
@param[in] Cr3 The page table base address.
@param[in] BaseAddress The physical address that is the start address of a memory region.
@param[in] Length The size in bytes of the memory region.
@retval EFI_SUCCESS The shadow stack memory is set.
**/
EFI_STATUS
SetShadowStack (
IN UINTN Cr3,
IN EFI_PHYSICAL_ADDRESS BaseAddress,
IN UINT64 Length
)
{
EFI_STATUS Status;
SetPageTableBase (Cr3);
Status = SmmSetMemoryAttributes (BaseAddress, Length, EFI_MEMORY_RO);
SetPageTableBase (0);
return Status;
}
/**
Set not present memory.
@param[in] Cr3 The page table base address.
@param[in] BaseAddress The physical address that is the start address of a memory region.
@param[in] Length The size in bytes of the memory region.
@retval EFI_SUCCESS The not present memory is set.
**/
EFI_STATUS
SetNotPresentPage (
IN UINTN Cr3,
IN EFI_PHYSICAL_ADDRESS BaseAddress,
IN UINT64 Length
)
{
EFI_STATUS Status;
SetPageTableBase (Cr3);
Status = SmmSetMemoryAttributes (BaseAddress, Length, EFI_MEMORY_RP);
SetPageTableBase (0);
return Status;
}
/**
Retrieves a pointer to the system configuration table from the SMM System Table