MdePkg: Add Dynamic Stack Cookie Support

Adds dynamic stack cookies in the form of copies of the entry
point libraries that use shared logic to update stack cookies
at runtime.

This relies on RDRAND on IA32/X64 and RNDR on AARCH64 to get a
random number to apply to the stack cookie on module entry point.

This simplifies the logic a platform must do to include stack
check functionality.

Signed-off-by: Oliver Smith-Denny <osde@microsoft.com>
This commit is contained in:
Oliver Smith-Denny 2025-01-29 11:05:03 -08:00 committed by mergify[bot]
parent efbf5ed08c
commit e6b6aa90d4
31 changed files with 1783 additions and 78 deletions

View File

@ -0,0 +1,56 @@
#------------------------------------------------------------------------------
#
# Copyright (c) Microsoft Corporation.
# SPDX-License-Identifier: BSD-2-Clause-Patent
#
# Module Name:
#
# DynamicCookie.S
#
# Abstract:
#
# Generates random number through the RNDR instruction on a 64-bit AARCH64 platform
# to store a random value in the GCC __stack_check_guard stack cookie.
# The first byte is 0'd to prevent string copy functions from clobbering
# the stack cookie.
#
# Notes:
#
# If RNDR fails, the build time static stack cookie value will be used instead.
#
#------------------------------------------------------------------------------
#include <AArch64/AArch64.h>
.text
.p2align 2
GCC_ASM_IMPORT(__stack_chk_guard)
GCC_ASM_IMPORT(_CModuleEntryPoint)
GCC_ASM_EXPORT(_ModuleEntryPoint)
#------------------------------------------------------------------------------
# VOID
# EFIAPI
# _ModuleEntryPoint (
# Parameters are passed through.
# )
#------------------------------------------------------------------------------
ASM_PFX(_ModuleEntryPoint):
AARCH64_BTI(c)
mrs x9, ID_AA64ISAR0_EL1 // Read the AArch64 Instruction Set Attribute Register 0
ubfx x9, x9, #60, #4 // Extract the RNDR bit field (bits 60-63)
cbz x9, c_entry // If RNDR is not supported, jump to c_entry
mrs x9, RNDR // Generate a random number
b.eq c_entry // RNDR sets NZCV to 0b0100 on failure
// So if the zero flag is set, use the static stack guard
and x9, x9, #0xFFFFFFFFFFFFFF00 // Zero the first byte of the random value
adrp x8, ASM_PFX(__stack_chk_guard) // Load the page address of __stack_chk_guard
str x9, [x8, :lo12:ASM_PFX(__stack_chk_guard)] // Store the random value in __stack_chk_guard
c_entry:
b ASM_PFX(_CModuleEntryPoint) // Jump to the C module entry point

View File

@ -0,0 +1,70 @@
/** @file
Entry point to the DXE Core.
Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include <PiDxe.h>
#include <Library/DxeCoreEntryPoint.h>
#include <Library/DebugLib.h>
#include <Library/BaseLib.h>
//
// Cache copy of HobList pointer.
//
VOID *gHobList = NULL;
/**
The entry point of PE/COFF Image for the DXE Core.
This function is the entry point for the DXE Core. This function is required to call
ProcessModuleEntryPointList() and ProcessModuleEntryPointList() is never expected to return.
The DXE Core is responsible for calling ProcessLibraryConstructorList() as soon as the EFI
System Table and the image handle for the DXE Core itself have been established.
If ProcessModuleEntryPointList() returns, then ASSERT() and halt the system.
@param HobStart The pointer to the beginning of the HOB List passed in from the PEI Phase.
**/
VOID
EFIAPI
_CModuleEntryPoint (
IN VOID *HobStart
)
{
//
// Cache a pointer to the HobList
//
gHobList = HobStart;
//
// Call the DXE Core entry point
//
ProcessModuleEntryPointList (HobStart);
//
// Should never return
//
ASSERT (FALSE);
CpuDeadLoop ();
}
/**
Required by the EBC compiler and identical in functionality to _ModuleEntryPoint().
This function is required to call _ModuleEntryPoint() passing in HobStart.
@param HobStart The pointer to the beginning of the HOB List passed in from the PEI Phase.
**/
VOID
EFIAPI
EfiMain (
IN VOID *HobStart
)
{
_ModuleEntryPoint (HobStart);
}

View File

@ -0,0 +1,16 @@
// /** @file
// Module entry point library for DXE core.
//
// Module entry point library for DXE core.
//
// Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.<BR>
//
// SPDX-License-Identifier: BSD-2-Clause-Patent
//
// **/
#string STR_MODULE_ABSTRACT #language en-US "Module entry point library for DXE core"
#string STR_MODULE_DESCRIPTION #language en-US "Module entry point library for DXE core."

View File

@ -0,0 +1,45 @@
## @file
# Module entry point library for DXE core that dynamically updates the stack cookie.
#
# Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
#
# SPDX-License-Identifier: BSD-2-Clause-Patent
#
#
##
[Defines]
INF_VERSION = 0x00010005
BASE_NAME = DxeCoreEntryPointDynamicInit
MODULE_UNI_FILE = DxeCore/DxeCoreEntryPoint.uni
FILE_GUID = FD044D85-1407-4043-B527-471F16ABD8C6
MODULE_TYPE = DXE_CORE
VERSION_STRING = 1.0
LIBRARY_CLASS = DxeCoreEntryPoint|DXE_CORE
#
# VALID_ARCHITECTURES = IA32 X64 AARCH64
#
[Sources]
DxeCore/DxeCoreEntryPoint.c
[Sources.IA32]
IA32/DynamicCookieGcc.nasm | GCC
IA32/DynamicCookieMsvc.nasm | MSFT
[Sources.X64]
X64/DynamicCookieGcc.nasm | GCC
X64/DynamicCookieMsvc.nasm | MSFT
[Sources.AARCH64]
AArch64/DynamicCookieGcc.S | GCC
[Packages]
MdePkg/MdePkg.dec
[LibraryClasses]
BaseLib
DebugLib
StackCheckLib

View File

@ -0,0 +1,63 @@
;------------------------------------------------------------------------------
;
; Copyright (c) Microsoft Corporation.
; SPDX-License-Identifier: BSD-2-Clause-Patent
;
; Module Name:
;
; DynamicCookie.nasm
;
; Abstract:
;
; Generates random number through CPU RdRand instruction on a 32-bit platform
; to store a random value in the GCC __stack_check_guard stack cookie.
; The first byte is 0'd to prevent string copy functions from clobbering
; the stack cookie.
;
; Notes:
;
; If RdRand fails, the build time static stack cookie value will be used instead.
;
;------------------------------------------------------------------------------
SECTION .text
extern ASM_PFX(__stack_chk_guard)
extern ASM_PFX(_CModuleEntryPoint)
global ASM_PFX(_ModuleEntryPoint)
;------------------------------------------------------------------------------
; VOID
; EFIAPI
; _ModuleEntryPoint (
; Parameters are passed through
; );
;------------------------------------------------------------------------------
global _ModuleEntryPoint
_ModuleEntryPoint:
push ebx
push ecx
push edx
mov eax, 1 ; CPUID function 1
cpuid
test ecx, 0x40000000 ; Check if the RdRand bit (bit 30) is set in ECX
jz c_entry ; If not set, jump to c_entry
rdrand eax ; Use rdrand, getting a 32 bit value as on
; IA32, __stack_chk_guard is a 32 bit value.
; CF=1 if RN generated ok, otherwise CF=0
jnc c_entry ; If the cmd fails, don't update __stack_chk_guard, we'll have to move forward
; with the static value provided at build time.
lea ebx, [ASM_PFX(__stack_chk_guard)] ; load the address of __stack_chk_guard into ebx
xor ah, ah ; Zero a byte of the __stack_chk_guard value to protect against string functions
; (such as strcpy like functions) clobbering past the canary
mov [ebx], eax ; Store our random value, with 0'd first byte to __stack_chk_guard
c_entry:
pop edx
pop ecx
pop ebx
jmp ASM_PFX(_CModuleEntryPoint)

View File

@ -0,0 +1,63 @@
;------------------------------------------------------------------------------
;
; Copyright (c) Microsoft Corporation.
; SPDX-License-Identifier: BSD-2-Clause-Patent
;
; Module Name:
;
; DynamicCookie.nasm
;
; Abstract:
;
; Generates random number through CPU RdRand instruction on a 32-bit platform
; to store a random value in the GCC __stack_check_guard stack cookie.
; The first byte is 0'd to prevent string copy functions from clobbering
; the stack cookie.
;
; Notes:
;
; If RdRand fails, the build time static stack cookie value will be used instead.
;
;------------------------------------------------------------------------------
SECTION .text
extern ASM_PFX(__security_cookie)
extern ASM_PFX(_CModuleEntryPoint)
global ASM_PFX(_ModuleEntryPoint)
;------------------------------------------------------------------------------
; VOID
; EFIAPI
; _ModuleEntryPoint (
; Parameters are passed through
; );
;------------------------------------------------------------------------------
global _ModuleEntryPoint
_ModuleEntryPoint:
push ebx
push ecx
push edx
mov eax, 1 ; CPUID function 1
cpuid
test ecx, 0x40000000 ; Check if the RdRand bit (bit 30) is set in ECX
jz c_entry ; If not set, jump to c_entry
rdrand eax ; Use rdrand, getting a 32 bit value as on
; IA32, __security_cookie is a 32 bit value.
; CF=1 if RN generated ok, otherwise CF=0
jnc c_entry ; If the cmd fails, don't update __security_cookie, we'll have to move forward
; with the static value provided at build time.
lea ebx, [ASM_PFX(__security_cookie)] ; load the address of __stack_chk_guard into ebx
xor ah, ah ; Zero a byte of the __security_cookie value to protect against string functions
; (such as strcpy like functions) clobbering past the canary
mov [ebx], eax ; Store our random value, with 0'd first byte to __security_cookie
c_entry:
pop edx
pop ecx
pop ebx
jmp ASM_PFX(_CModuleEntryPoint)

View File

@ -0,0 +1,93 @@
/** @file
Entry point to a the PEI Core.
Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include <PiPei.h>
//
// The Library classes this module produced
//
#include <Library/PeiCoreEntryPoint.h>
#include <Library/BaseLib.h>
#include <Library/DebugLib.h>
/**
The entry point of PE/COFF Image for the PEI Core.
This function is the entry point for the PEI Foundation, which allows the SEC phase
to pass information about the stack, temporary RAM and the Boot Firmware Volume.
In addition, it also allows the SEC phase to pass services and data forward for use
during the PEI phase in the form of one or more PPIs.
There is no limit to the number of additional PPIs that can be passed from SEC into
the PEI Foundation. As part of its initialization phase, the PEI Foundation will add
these SEC-hosted PPIs to its PPI database such that both the PEI Foundation and any
modules can leverage the associated service calls and/or code in these early PPIs.
This function is required to call ProcessModuleEntryPointList() with the Context
parameter set to NULL. ProcessModuleEntryPoint() is never expected to return.
The PEI Core is responsible for calling ProcessLibraryConstructorList() as soon as
the PEI Services Table and the file handle for the PEI Core itself have been established.
If ProcessModuleEntryPointList() returns, then ASSERT() and halt the system.
@param SecCoreData Points to a data structure containing information about the
PEI core's operating environment, such as the size and
location of temporary RAM, the stack location and the BFV
location.
@param PpiList Points to a list of one or more PPI descriptors to be
installed initially by the PEI core. An empty PPI list
consists of a single descriptor with the end-tag
EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST.
As part of its initialization phase, the PEI Foundation will
add these SEC-hosted PPIs to its PPI database, such that both
the PEI Foundation and any modules can leverage the associated
service calls and/or code in these early PPIs.
**/
VOID
EFIAPI
_CModuleEntryPoint (
IN CONST EFI_SEC_PEI_HAND_OFF *SecCoreData,
IN CONST EFI_PEI_PPI_DESCRIPTOR *PpiList
)
{
ProcessModuleEntryPointList (SecCoreData, PpiList, NULL);
//
// Should never return
//
ASSERT (FALSE);
CpuDeadLoop ();
}
/**
Required by the EBC compiler and identical in functionality to _ModuleEntryPoint().
This function is required to call _CModuleEntryPoint() passing in SecCoreData and PpiList.
@param SecCoreData Points to a data structure containing information about the PEI core's
operating environment, such as the size and location of temporary RAM,
the stack location and the BFV location.
@param PpiList Points to a list of one or more PPI descriptors to be installed
initially by the PEI core. An empty PPI list consists of
a single descriptor with the end-tag
EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST.
As part of its initialization phase, the PEI Foundation will
add these SEC-hosted PPIs to its PPI database, such that both
the PEI Foundationand any modules can leverage the associated
service calls and/or code in these early PPIs.
**/
VOID
EFIAPI
EfiMain (
IN CONST EFI_SEC_PEI_HAND_OFF *SecCoreData,
IN CONST EFI_PEI_PPI_DESCRIPTOR *PpiList
)
{
_CModuleEntryPoint (SecCoreData, PpiList);
}

View File

@ -0,0 +1,16 @@
// /** @file
// Module entry point library for PEI core.
//
// Module entry point library for PEI core.
//
// Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.<BR>
//
// SPDX-License-Identifier: BSD-2-Clause-Patent
//
// **/
#string STR_MODULE_ABSTRACT #language en-US "Module entry point library for PEI core"
#string STR_MODULE_DESCRIPTION #language en-US "Module entry point library for PEI core."

View File

@ -0,0 +1,66 @@
/** @file
Entry point to a the PEI Core that does not update the stack cookie dynamically.
Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include <PiPei.h>
//
// The Library classes this module produced
//
#include <Library/PeiCoreEntryPoint.h>
#include <Library/BaseLib.h>
#include <Library/DebugLib.h>
extern
VOID
EFIAPI
_CModuleEntryPoint (
IN CONST EFI_SEC_PEI_HAND_OFF *SecCoreData,
IN CONST EFI_PEI_PPI_DESCRIPTOR *PpiList
);
/**
The entry point of PE/COFF Image for the PEI Core.
This function is the entry point for the PEI Foundation, which allows the SEC phase
to pass information about the stack, temporary RAM and the Boot Firmware Volume.
In addition, it also allows the SEC phase to pass services and data forward for use
during the PEI phase in the form of one or more PPIs.
There is no limit to the number of additional PPIs that can be passed from SEC into
the PEI Foundation. As part of its initialization phase, the PEI Foundation will add
these SEC-hosted PPIs to its PPI database such that both the PEI Foundation and any
modules can leverage the associated service calls and/or code in these early PPIs.
This function is required to call ProcessModuleEntryPointList() with the Context
parameter set to NULL. ProcessModuleEntryPoint() is never expected to return.
The PEI Core is responsible for calling ProcessLibraryConstructorList() as soon as
the PEI Services Table and the file handle for the PEI Core itself have been established.
If ProcessModuleEntryPointList() returns, then ASSERT() and halt the system.
@param SecCoreData Points to a data structure containing information about the
PEI core's operating environment, such as the size and
location of temporary RAM, the stack location and the BFV
location.
@param PpiList Points to a list of one or more PPI descriptors to be
installed initially by the PEI core. An empty PPI list
consists of a single descriptor with the end-tag
EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST.
As part of its initialization phase, the PEI Foundation will
add these SEC-hosted PPIs to its PPI database, such that both
the PEI Foundation and any modules can leverage the associated
service calls and/or code in these early PPIs.
**/
VOID
EFIAPI
_ModuleEntryPoint (
IN CONST EFI_SEC_PEI_HAND_OFF *SecCoreData,
IN CONST EFI_PEI_PPI_DESCRIPTOR *PpiList
)
{
_CModuleEntryPoint (SecCoreData, PpiList);
}

View File

@ -0,0 +1,44 @@
## @file
# Module entry point library for PEI core that dynamically updates the stack cookie.
#
# Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
#
# SPDX-License-Identifier: BSD-2-Clause-Patent
#
#
##
[Defines]
INF_VERSION = 0x00010005
BASE_NAME = PeiCoreEntryPointDynamicInit
MODULE_UNI_FILE = PeiCore/PeiCoreEntryPoint.uni
FILE_GUID = 2627DFCD-054D-403E-B812-E67034865D29
MODULE_TYPE = PEI_CORE
VERSION_STRING = 1.0
LIBRARY_CLASS = PeiCoreEntryPoint|PEI_CORE
#
# VALID_ARCHITECTURES = IA32 X64 AARCH64
#
[Sources]
PeiCore/PeiCoreEntryPoint.c
[Sources.IA32]
IA32/DynamicCookieGcc.nasm | GCC
IA32/DynamicCookieMsvc.nasm | MSFT
[Sources.X64]
X64/DynamicCookieGcc.nasm | GCC
X64/DynamicCookieMsvc.nasm | MSFT
[Sources.AARCH64]
AArch64/DynamicCookieGcc.S | GCC
[Packages]
MdePkg/MdePkg.dec
[LibraryClasses]
BaseLib
DebugLib
StackCheckLib

View File

@ -0,0 +1,72 @@
/** @file
Entry point to a PEIM.
Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include <PiPei.h>
#include <Library/PeimEntryPoint.h>
#include <Library/DebugLib.h>
/**
The entry point of PE/COFF Image for a PEIM.
This function is the entry point for a PEIM. This function must call ProcessLibraryConstructorList()
and ProcessModuleEntryPointList(). The return value from ProcessModuleEntryPointList() is returned.
If _gPeimRevision is not zero and PeiServices->Hdr.Revision is less than _gPeimRevison, then ASSERT().
@param FileHandle Handle of the file being invoked.
@param PeiServices Describes the list of possible PEI Services.
@retval EFI_SUCCESS The PEIM executed normally.
@retval !EFI_SUCCESS The PEIM failed to execute normally.
**/
EFI_STATUS
EFIAPI
_CModuleEntryPoint (
IN EFI_PEI_FILE_HANDLE FileHandle,
IN CONST EFI_PEI_SERVICES **PeiServices
)
{
if (_gPeimRevision != 0) {
//
// Make sure that the PEI spec revision of the platform is >= PEI spec revision of the driver
//
ASSERT ((*PeiServices)->Hdr.Revision >= _gPeimRevision);
}
//
// Call constructor for all libraries
//
ProcessLibraryConstructorList (FileHandle, PeiServices);
//
// Call the driver entry point
//
return ProcessModuleEntryPointList (FileHandle, PeiServices);
}
/**
Required by the EBC compiler and identical in functionality to _ModuleEntryPoint().
This function is required to call _ModuleEntryPoint() passing in FileHandle and PeiServices.
@param FileHandle Handle of the file being invoked.
@param PeiServices Describes the list of possible PEI Services.
@retval EFI_SUCCESS The PEIM executed normally.
@retval !EFI_SUCCESS The PEIM failed to execute normally.
**/
EFI_STATUS
EFIAPI
EfiMain (
IN EFI_PEI_FILE_HANDLE FileHandle,
IN CONST EFI_PEI_SERVICES **PeiServices
)
{
return _CModuleEntryPoint (FileHandle, PeiServices);
}

View File

@ -0,0 +1,16 @@
// /** @file
// Module entry point library for PEIM.
//
// Module entry point library for PEIM.
//
// Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.<BR>
//
// SPDX-License-Identifier: BSD-2-Clause-Patent
//
// **/
#string STR_MODULE_ABSTRACT #language en-US "Module entry point library for PEIM"
#string STR_MODULE_DESCRIPTION #language en-US "Module entry point library for PEIM."

View File

@ -0,0 +1,46 @@
/** @file
Entry point to a PEIM that does not update the stack cookie dynamically.
Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include <PiPei.h>
#include <Library/PeimEntryPoint.h>
#include <Library/DebugLib.h>
extern
EFI_STATUS
EFIAPI
_CModuleEntryPoint (
IN EFI_PEI_FILE_HANDLE FileHandle,
IN CONST EFI_PEI_SERVICES **PeiServices
);
/**
The entry point of PE/COFF Image for a PEIM.
This function is the entry point for a PEIM. This function must call ProcessLibraryConstructorList()
and ProcessModuleEntryPointList(). The return value from ProcessModuleEntryPointList() is returned.
If _gPeimRevision is not zero and PeiServices->Hdr.Revision is less than _gPeimRevison, then ASSERT().
@param FileHandle Handle of the file being invoked.
@param PeiServices Describes the list of possible PEI Services.
@retval EFI_SUCCESS The PEIM executed normally.
@retval !EFI_SUCCESS The PEIM failed to execute normally.
**/
EFI_STATUS
EFIAPI
_ModuleEntryPoint (
IN EFI_PEI_FILE_HANDLE FileHandle,
IN CONST EFI_PEI_SERVICES **PeiServices
)
{
//
// Call the driver entry point
//
return _CModuleEntryPoint (FileHandle, PeiServices);
}

View File

@ -0,0 +1,43 @@
## @file
# Module entry point library for PEIM that dynamically updates the stack cookie.
#
# Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
#
# SPDX-License-Identifier: BSD-2-Clause-Patent
#
#
##
[Defines]
INF_VERSION = 0x00010005
BASE_NAME = PeimEntryPointDynamicInit
MODULE_UNI_FILE = Peim/PeimEntryPoint.uni
FILE_GUID = 0E53AFCB-7FDD-461E-B8CE-6DA9F3F9014C
MODULE_TYPE = PEIM
VERSION_STRING = 1.0
LIBRARY_CLASS = PeimEntryPoint|PEIM
#
# VALID_ARCHITECTURES = IA32 X64 AARCH64
#
[Sources]
Peim/PeimEntryPoint.c
[Sources.IA32]
IA32/DynamicCookieGcc.nasm | GCC
IA32/DynamicCookieMsvc.nasm | MSFT
[Sources.X64]
X64/DynamicCookieGcc.nasm | GCC
X64/DynamicCookieMsvc.nasm | MSFT
[Sources.AARCH64]
AArch64/DynamicCookieGcc.S | GCC
[Packages]
MdePkg/MdePkg.dec
[LibraryClasses]
DebugLib
StackCheckLib

View File

@ -0,0 +1,65 @@
/** @file
Entry point to the Standalone Mm Core.
Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
Copyright (c) Microsoft Corporation.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include <PiMm.h>
#include <Library/StandaloneMmCoreEntryPoint.h>
#include <Library/DebugLib.h>
#include <Library/BaseLib.h>
//
// Cache copy of HobList pointer.
//
VOID *gHobList = NULL;
/**
The entry point of PE/COFF Image for the STANDALONE MM Core.
This function is the entry point for the STANDALONE MM Core. This function is required to call
ProcessModuleEntryPointList() and ProcessModuleEntryPointList() is never expected to return.
The STANDALONE MM Core is responsible for calling ProcessLibraryConstructorList() as soon as the EFI
System Table and the image handle for the STANDALONE MM Core itself have been established.
If ProcessModuleEntryPointList() returns, then ASSERT() and halt the system.
@param HobStart Pointer to the beginning of the HOB List passed in from the PEI Phase.
**/
VOID
EFIAPI
_CModuleEntryPoint (
IN VOID *HobStart
)
{
//
// Cache a pointer to the HobList
//
gHobList = HobStart;
//
// Call the Standalone MM Core entry point
//
ProcessModuleEntryPointList (HobStart);
}
/**
Required by the EBC compiler and identical in functionality to _ModuleEntryPoint().
This function is required to call _ModuleEntryPoint() passing in HobStart.
@param HobStart Pointer to the beginning of the HOB List passed in from the PEI Phase.
**/
VOID
EFIAPI
EfiMain (
IN VOID *HobStart
)
{
_ModuleEntryPoint (HobStart);
}

View File

@ -0,0 +1,38 @@
## @file
# Module entry point library for StandaloneMm core that dynamically updates the stack cookie.
# The AARCH64 version of this library lives in ArmPkg.
#
# Copyright (c) 2017 - 2021, Arm Ltd. All rights reserved.<BR>
#
# SPDX-License-Identifier: BSD-2-Clause-Patent
#
#
##
[Defines]
INF_VERSION = 0x0001001A
BASE_NAME = StandaloneMmCoreEntryPointDynamicInit
FILE_GUID = 490073A1-4DBC-4E9E-B30D-A4204139FC5F
MODULE_TYPE = MM_CORE_STANDALONE
VERSION_STRING = 1.0
PI_SPECIFICATION_VERSION = 0x00010032
LIBRARY_CLASS = StandaloneMmCoreEntryPoint|MM_CORE_STANDALONE
#
# VALID_ARCHITECTURES = X64
#
[Sources.X64]
StandaloneMmCore/X64/StandaloneMmCoreEntryPoint.c
[Sources.X64]
X64/DynamicCookieGcc.nasm | GCC
X64/DynamicCookieMsvc.nasm | MSFT
[Packages]
MdePkg/MdePkg.dec
[LibraryClasses]
BaseLib
DebugLib
StackCheckLib

View File

@ -0,0 +1,135 @@
/** @file
Entry point to a Standalone MM driver.
Copyright (c) 2015 - 2021, Intel Corporation. All rights reserved.<BR>
Copyright (c) 2016 - 2018, ARM Ltd. All rights reserved.<BR>
Copyright (c) 2018, Linaro, Limited. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include <PiMm.h>
#include <Protocol/LoadedImage.h>
#include <Library/BaseLib.h>
#include <Library/DebugLib.h>
#include <Library/MmServicesTableLib.h>
#include <Library/StandaloneMmDriverEntryPoint.h>
/**
Unloads an image from memory.
This function is a callback that a driver registers to do cleanup
when the UnloadImage boot service function is called.
@param ImageHandle The handle to the image to unload.
@return Status returned by all unload().
**/
EFI_STATUS
EFIAPI
_DriverUnloadHandler (
EFI_HANDLE ImageHandle
)
{
EFI_STATUS Status;
//
// If an UnloadImage() handler is specified, then call it
//
Status = ProcessModuleUnloadList (ImageHandle);
//
// If the driver specific unload handler does not return an error, then call all of the
// library destructors. If the unload handler returned an error, then the driver can not be
// unloaded, and the library destructors should not be called
//
if (!EFI_ERROR (Status)) {
ProcessLibraryDestructorList (ImageHandle, gMmst);
}
//
// Return the status from the driver specific unload handler
//
return Status;
}
/**
The entry point of PE/COFF Image for a Standalone MM Driver.
This function is the entry point for a Standalone MM Driver.
This function must call ProcessLibraryConstructorList() and
ProcessModuleEntryPointList().
If the return status from ProcessModuleEntryPointList()
is an error status, then ProcessLibraryDestructorList() must be called.
The return value from ProcessModuleEntryPointList() is returned.
If _gMmRevision is not zero and SystemTable->Hdr.Revision is
less than _gMmRevision, then return EFI_INCOMPATIBLE_VERSION.
@param ImageHandle The image handle of the Standalone MM Driver.
@param MmSystemTable A pointer to the MM System Table.
@retval EFI_SUCCESS The Standalone MM Driver exited normally.
@retval EFI_INCOMPATIBLE_VERSION _gMmRevision is greater than
MmSystemTable->Hdr.Revision.
@retval Other Return value from
ProcessModuleEntryPointList().
**/
EFI_STATUS
EFIAPI
_CModuleEntryPoint (
IN EFI_HANDLE ImageHandle,
IN IN EFI_MM_SYSTEM_TABLE *MmSystemTable
)
{
EFI_STATUS Status;
EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
if (_gMmRevision != 0) {
//
// Make sure that the MM spec revision of the platform
// is >= MM spec revision of the driver
//
if (MmSystemTable->Hdr.Revision < _gMmRevision) {
return EFI_INCOMPATIBLE_VERSION;
}
}
//
// Call constructor for all libraries
//
ProcessLibraryConstructorList (ImageHandle, MmSystemTable);
//
// Install unload handler...
//
if (_gDriverUnloadImageCount != 0) {
Status = gMmst->MmHandleProtocol (
ImageHandle,
&gEfiLoadedImageProtocolGuid,
(VOID **)&LoadedImage
);
ASSERT_EFI_ERROR (Status);
LoadedImage->Unload = _DriverUnloadHandler;
}
//
// Call the driver entry point
//
Status = ProcessModuleEntryPointList (ImageHandle, MmSystemTable);
//
// If all of the drivers returned errors, then invoke all of the library destructors
//
if (EFI_ERROR (Status)) {
ProcessLibraryDestructorList (ImageHandle, MmSystemTable);
}
//
// Return the cumulative return status code from all of the driver entry points
//
return Status;
}

View File

@ -0,0 +1,17 @@
// /** @file
//
// Module entry point library for standalone MM driver
//
// Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.<BR>
// Copyright (c) 2016 - 2018, ARM Limited. All rights reserved.<BR>
// Copyright (c) 2018, Linaro, Limited. All rights reserved.<BR>
//
// SPDX-License-Identifier: BSD-2-Clause-Patent
//
// **/
#string STR_MODULE_ABSTRACT #language en-US "Module entry point library for standalone MM driver"
#string STR_MODULE_DESCRIPTION #language en-US "Module entry point library for standalone MM driver."

View File

@ -0,0 +1,53 @@
## @file
# Module entry point library for Standalone MM drivers that dynamically updates the stack cookie.
#
# Copyright (c) 2015 - 2021, Intel Corporation. All rights reserved.<BR>
# Copyright (c) 2016-2018, ARM Ltd. All rights reserved.<BR>
# Copyright (c) 2018, Linaro, Limited. All rights reserved.<BR>
#
# SPDX-License-Identifier: BSD-2-Clause-Patent
#
#
##
[Defines]
INF_VERSION = 0x0001001B
BASE_NAME = StandaloneMmDriverEntryPointDynamicInit
MODULE_UNI_FILE = StandaloneMmDriver/StandaloneMmDriverEntryPoint.uni
FILE_GUID = 28CBCD87-2FEE-4D46-BB5C-B37732BBEEB1
MODULE_TYPE = MM_STANDALONE
VERSION_STRING = 1.0
PI_SPECIFICATION_VERSION = 0x00010032
LIBRARY_CLASS = StandaloneMmDriverEntryPoint|MM_STANDALONE
#
# The following information is for reference only and not required by the build tools.
#
# VALID_ARCHITECTURES = X64 AARCH64
#
[Sources]
StandaloneMmDriver/StandaloneMmDriverEntryPoint.c
[Sources.IA32]
IA32/DynamicCookieGcc.nasm | GCC
IA32/DynamicCookieMsvc.nasm | MSFT
[Sources.X64]
X64/DynamicCookieGcc.nasm | GCC
X64/DynamicCookieMsvc.nasm | MSFT
[Sources.AARCH64]
AArch64/DynamicCookieGcc.S | GCC
[Packages]
MdePkg/MdePkg.dec
[LibraryClasses]
BaseLib
DebugLib
MmServicesTableLib
StackCheckLib
[Protocols]
gEfiLoadedImageProtocolGuid ## SOMETIMES_CONSUMES

View File

@ -0,0 +1,112 @@
/** @file
Entry point library instance to a UEFI application.
Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include <Uefi.h>
#include <Library/UefiApplicationEntryPoint.h>
#include <Library/BaseLib.h>
#include <Library/DebugLib.h>
#include <Library/UefiBootServicesTableLib.h>
/**
Entry point to UEFI Application.
This function is the entry point for a UEFI Application. This function must call
ProcessLibraryConstructorList(), ProcessModuleEntryPointList(), and ProcessLibraryDestructorList().
The return value from ProcessModuleEntryPointList() is returned.
If _gUefiDriverRevision is not zero and SystemTable->Hdr.Revision is less than _gUefiDriverRevison,
then return EFI_INCOMPATIBLE_VERSION.
@param ImageHandle The image handle of the UEFI Application.
@param SystemTable A pointer to the EFI System Table.
@retval EFI_SUCCESS The UEFI Application exited normally.
@retval EFI_INCOMPATIBLE_VERSION _gUefiDriverRevision is greater than SystemTable->Hdr.Revision.
@retval Other Return value from ProcessModuleEntryPointList().
**/
EFI_STATUS
EFIAPI
_CModuleEntryPoint (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
if (_gUefiDriverRevision != 0) {
//
// Make sure that the EFI/UEFI spec revision of the platform is >= EFI/UEFI spec revision of the application.
//
if (SystemTable->Hdr.Revision < _gUefiDriverRevision) {
return EFI_INCOMPATIBLE_VERSION;
}
}
//
// Call constructor for all libraries.
//
ProcessLibraryConstructorList (ImageHandle, SystemTable);
//
// Call the module's entry point
//
Status = ProcessModuleEntryPointList (ImageHandle, SystemTable);
//
// Process destructor for all libraries.
//
ProcessLibraryDestructorList (ImageHandle, SystemTable);
//
// Return the return status code from the driver entry point
//
return Status;
}
/**
Invokes the library destructors for all dependent libraries and terminates
the UEFI Application.
This function calls ProcessLibraryDestructorList() and the EFI Boot Service Exit()
with a status specified by Status.
@param Status Status returned by the application that is exiting.
**/
VOID
EFIAPI
Exit (
IN EFI_STATUS Status
)
{
ProcessLibraryDestructorList (gImageHandle, gST);
gBS->Exit (gImageHandle, Status, 0, NULL);
}
/**
Required by the EBC compiler and identical in functionality to _ModuleEntryPoint().
@param ImageHandle The image handle of the UEFI Application.
@param SystemTable A pointer to the EFI System Table.
@retval EFI_SUCCESS The UEFI Application exited normally.
@retval EFI_INCOMPATIBLE_VERSION _gUefiDriverRevision is greater than SystemTable->Hdr.Revision.
@retval Other Return value from ProcessModuleEntryPointList().
**/
EFI_STATUS
EFIAPI
EfiMain (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
return _ModuleEntryPoint (ImageHandle, SystemTable);
}

View File

@ -0,0 +1,50 @@
/** @file
Entry point library instance to a UEFI application that does not update the stack cookie dynamically.
Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include <Uefi.h>
#include <Library/UefiApplicationEntryPoint.h>
#include <Library/BaseLib.h>
#include <Library/DebugLib.h>
extern
EFI_STATUS
EFIAPI
_CModuleEntryPoint (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
);
/**
Entry point to UEFI Application.
This function is the entry point for a UEFI Application. This function must call
ProcessLibraryConstructorList(), ProcessModuleEntryPointList(), and ProcessLibraryDestructorList().
The return value from ProcessModuleEntryPointList() is returned.
If _gUefiDriverRevision is not zero and SystemTable->Hdr.Revision is less than _gUefiDriverRevison,
then return EFI_INCOMPATIBLE_VERSION.
@param ImageHandle The image handle of the UEFI Application.
@param SystemTable A pointer to the EFI System Table.
@retval EFI_SUCCESS The UEFI Application exited normally.
@retval EFI_INCOMPATIBLE_VERSION _gUefiDriverRevision is greater than SystemTable->Hdr.Revision.
@retval Other Return value from ProcessModuleEntryPointList().
**/
EFI_STATUS
EFIAPI
_ModuleEntryPoint (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
//
// Call the module's entry point
//
return _CModuleEntryPoint (ImageHandle, SystemTable);
}

View File

@ -0,0 +1,16 @@
// /** @file
// Module entry point library for UEFI Application.
//
// Module entry point library for UEFI Application.
//
// Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.<BR>
//
// SPDX-License-Identifier: BSD-2-Clause-Patent
//
// **/
#string STR_MODULE_ABSTRACT #language en-US "Module entry point library for UEFI Application"
#string STR_MODULE_DESCRIPTION #language en-US "Module entry point library for UEFI Application."

View File

@ -0,0 +1,45 @@
## @file
# Module entry point library for UEFI Application that dynamically updates the stack cookie.
#
# Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
#
# SPDX-License-Identifier: BSD-2-Clause-Patent
#
#
##
[Defines]
INF_VERSION = 0x00010005
BASE_NAME = UefiApplicationEntryPointDynamicInit
MODULE_UNI_FILE = UefiApplication/UefiApplicationEntryPoint.uni
FILE_GUID = 755B9094-E5AF-4E5B-BE33-D430CDE2C5D2
MODULE_TYPE = UEFI_APPLICATION
VERSION_STRING = 1.0
LIBRARY_CLASS = UefiApplicationEntryPoint|UEFI_APPLICATION
#
# VALID_ARCHITECTURES = IA32 X64 AARCH64
#
[Sources]
UefiApplication/ApplicationEntryPoint.c
[Sources.IA32]
IA32/DynamicCookieGcc.nasm | GCC
IA32/DynamicCookieMsvc.nasm | MSFT
[Sources.X64]
X64/DynamicCookieGcc.nasm | GCC
X64/DynamicCookieMsvc.nasm | MSFT
[Sources.AARCH64]
AArch64/DynamicCookieGcc.S | GCC
[Packages]
MdePkg/MdePkg.dec
[LibraryClasses]
UefiBootServicesTableLib
DebugLib
BaseLib
StackCheckLib

View File

@ -0,0 +1,162 @@
/** @file
Entry point to a EFI/DXE driver.
Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include <Uefi.h>
#include <Protocol/LoadedImage.h>
#include <Library/UefiDriverEntryPoint.h>
#include <Library/BaseLib.h>
#include <Library/DebugLib.h>
#include <Library/UefiBootServicesTableLib.h>
/**
Unloads an image from memory.
This function is a callback that a driver registers to do cleanup
when the UnloadImage boot service function is called.
@param ImageHandle The handle to the image to unload.
@return Status returned by all unload().
**/
EFI_STATUS
EFIAPI
_DriverUnloadHandler (
EFI_HANDLE ImageHandle
)
{
EFI_STATUS Status;
//
// If an UnloadImage() handler is specified, then call it
//
Status = ProcessModuleUnloadList (ImageHandle);
//
// If the driver specific unload handler does not return an error, then call all of the
// library destructors. If the unload handler returned an error, then the driver can not be
// unloaded, and the library destructors should not be called
//
if (!EFI_ERROR (Status)) {
ProcessLibraryDestructorList (ImageHandle, gST);
}
//
// Return the status from the driver specific unload handler
//
return Status;
}
/**
The entry point of PE/COFF Image for a DXE Driver, DXE Runtime Driver, DXE SMM
Driver, or UEFI Driver.
This function is the entry point for a DXE Driver, DXE Runtime Driver, DXE SMM Driver,
or UEFI Driver. This function must call ProcessLibraryConstructorList() and
ProcessModuleEntryPointList(). If the return status from ProcessModuleEntryPointList()
is an error status, then ProcessLibraryDestructorList() must be called. The return
value from ProcessModuleEntryPointList() is returned. If _gDriverUnloadImageCount
is greater than zero, then an unload handler must be registered for this image
and the unload handler must invoke ProcessModuleUnloadList().
If _gUefiDriverRevision is not zero and SystemTable->Hdr.Revision is less than
_gUefiDriverRevison, then return EFI_INCOMPATIBLE_VERSION.
@param ImageHandle The image handle of the DXE Driver, DXE Runtime Driver,
DXE SMM Driver, or UEFI Driver.
@param SystemTable A pointer to the EFI System Table.
@retval EFI_SUCCESS The DXE Driver, DXE Runtime Driver, DXE SMM
Driver, or UEFI Driver exited normally.
@retval EFI_INCOMPATIBLE_VERSION _gUefiDriverRevision is greater than
SystemTable->Hdr.Revision.
@retval Other Return value from ProcessModuleEntryPointList().
**/
EFI_STATUS
EFIAPI
_CModuleEntryPoint (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
if (_gUefiDriverRevision != 0) {
//
// Make sure that the EFI/UEFI spec revision of the platform is >= EFI/UEFI spec revision of the driver
//
if (SystemTable->Hdr.Revision < _gUefiDriverRevision) {
return EFI_INCOMPATIBLE_VERSION;
}
}
//
// Call constructor for all libraries
//
ProcessLibraryConstructorList (ImageHandle, SystemTable);
//
// Install unload handler...
//
if (_gDriverUnloadImageCount != 0) {
Status = gBS->HandleProtocol (
ImageHandle,
&gEfiLoadedImageProtocolGuid,
(VOID **)&LoadedImage
);
ASSERT_EFI_ERROR (Status);
LoadedImage->Unload = _DriverUnloadHandler;
}
//
// Call the driver entry point
//
Status = ProcessModuleEntryPointList (ImageHandle, SystemTable);
//
// If all of the drivers returned errors, then invoke all of the library destructors
//
if (EFI_ERROR (Status)) {
ProcessLibraryDestructorList (ImageHandle, SystemTable);
}
//
// Return the cummalative return status code from all of the driver entry points
//
return Status;
}
/**
Required by the EBC compiler and identical in functionality to _ModuleEntryPoint().
This function is required to call _ModuleEntryPoint() passing in ImageHandle,
and SystemTable.
@param ImageHandle The image handle of the DXE Driver, DXE Runtime Driver, DXE
SMM Driver, or UEFI Driver.
@param SystemTable A pointer to the EFI System Table.
@retval EFI_SUCCESS The DXE Driver, DXE Runtime Driver, DXE SMM
Driver, or UEFI Driver exited normally.
@retval EFI_INCOMPATIBLE_VERSION _gUefiDriverRevision is greater than
SystemTable->Hdr.Revision.
@retval Other Return value from ProcessModuleEntryPointList().
**/
EFI_STATUS
EFIAPI
EfiMain (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
return _ModuleEntryPoint (ImageHandle, SystemTable);
}

View File

@ -0,0 +1,16 @@
// /** @file
// Module entry point library for UEFI driver, DXE driver and SMM driver.
//
// Module entry point library for UEFI driver, DXE driver and SMM driver.
//
// Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.<BR>
//
// SPDX-License-Identifier: BSD-2-Clause-Patent
//
// **/
#string STR_MODULE_ABSTRACT #language en-US "Module entry point library for UEFI driver, DXE driver and SMM driver"
#string STR_MODULE_DESCRIPTION #language en-US "Module entry point library for UEFI driver, DXE driver and SMM driver."

View File

@ -0,0 +1,68 @@
## @file
# Module entry point library for UEFI driver, DXE driver and SMM driver that dynamically sets the stack cookie.
#
# Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
#
# SPDX-License-Identifier: BSD-2-Clause-Patent
#
#
##
[Defines]
INF_VERSION = 0x00010005
BASE_NAME = UefiDriverEntryPointDynamicInit
MODULE_UNI_FILE = UefiDriver/UefiDriverEntryPoint.uni
FILE_GUID = 900238F9-1421-4596-9548-A1BF58C97693
MODULE_TYPE = UEFI_DRIVER
VERSION_STRING = 1.0
LIBRARY_CLASS = UefiDriverEntryPoint|DXE_DRIVER DXE_RUNTIME_DRIVER UEFI_DRIVER SMM_CORE DXE_SMM_DRIVER
#
# The following information is for reference only and not required by the build tools.
#
# VALID_ARCHITECTURES = IA32 X64 AARCH64
#
[Sources]
UefiDriver/DriverEntryPoint.c
[Packages]
MdePkg/MdePkg.dec
[Sources.IA32]
IA32/DynamicCookieGcc.nasm | GCC
IA32/DynamicCookieMsvc.nasm | MSFT
[Sources.X64]
X64/DynamicCookieGcc.nasm | GCC
X64/DynamicCookieMsvc.nasm | MSFT
[Sources.AARCH64]
AArch64/DynamicCookieGcc.S | GCC
[LibraryClasses]
UefiBootServicesTableLib
DebugLib
BaseLib
StackCheckLib
[Protocols]
gEfiLoadedImageProtocolGuid ## SOMETIMES_CONSUMES
#
# For UEFI drivers, these architectural protocols defined in PI 1.0 spec need
# to be appended and merged to the final dependency section.
#
[Depex.common.UEFI_DRIVER]
gEfiBdsArchProtocolGuid AND
gEfiCpuArchProtocolGuid AND
gEfiMetronomeArchProtocolGuid AND
gEfiMonotonicCounterArchProtocolGuid AND
gEfiRealTimeClockArchProtocolGuid AND
gEfiResetArchProtocolGuid AND
gEfiRuntimeArchProtocolGuid AND
gEfiSecurityArchProtocolGuid AND
gEfiTimerArchProtocolGuid AND
gEfiVariableWriteArchProtocolGuid AND
gEfiVariableArchProtocolGuid AND
gEfiWatchdogTimerArchProtocolGuid

View File

@ -0,0 +1,63 @@
;------------------------------------------------------------------------------
;
; Copyright (c) Microsoft Corporation.
; SPDX-License-Identifier: BSD-2-Clause-Patent
;
; Module Name:
;
; DynamicCookie.nasm
;
; Abstract:
;
; Generates random number through CPU RdRand instruction on 64-bit platform
; to store a random value in the GCC __stack_check_guard stack cookie.
; The first byte is 0'd to prevent string copy functions from clobbering
; the stack cookie.
;
; Notes:
;
; If RdRand fails, the build time static stack cookie value will be used instead.
;
;------------------------------------------------------------------------------
DEFAULT REL
SECTION .text
extern ASM_PFX(__stack_chk_guard)
extern ASM_PFX(_CModuleEntryPoint)
;------------------------------------------------------------------------------
; VOID
; EFIAPI
; _ModuleEntryPoint (
; Parameters are passed through. TODO: Make sure there are only two args on X64
; );
;------------------------------------------------------------------------------
global ASM_PFX(_ModuleEntryPoint)
ASM_PFX(_ModuleEntryPoint):
push rbx
push rcx
push rdx
mov eax, 1 ; Set eax to 1 to get feature information
cpuid ; Call cpuid
test ecx, 0x40000000 ; Test the rdrand bit (bit 30) in ecx
jz c_entry ; If rdrand is not supported, jump to c_entry
rdrand rax ; Call rdrand functionality here, getting a 64 bit value as on
; X64, __stack_chk_guard is a 64 bit value.
; CF=1 if RN generated ok, otherwise CF=0
jnc c_entry ; If the cmd fails, don't, update __stack_chk_guard, we'll have to move forward
; with the static value provided at build time.
lea rbx, [rel ASM_PFX(__stack_chk_guard)] ; load the address of __stack_check_guard into rbx
xor ah, ah ; Zero a byte of the __stack_chk_guard value to protect against string functions
; (such as strcpy like functions) clobbering past the canary
mov [rbx], rax ; Store our random value, with 0'd first byte to __stack_chk_guard
c_entry:
pop rdx
pop rcx
pop rbx
jmp ASM_PFX(_CModuleEntryPoint)

View File

@ -0,0 +1,63 @@
;------------------------------------------------------------------------------
;
; Copyright (c) Microsoft Corporation.
; SPDX-License-Identifier: BSD-2-Clause-Patent
;
; Module Name:
;
; DynamicCookie.nasm
;
; Abstract:
;
; Generates random number through CPU RdRand instruction on 64-bit platform
; to store a random value in the GCC __stack_check_guard stack cookie.
; The first byte is 0'd to prevent string copy functions from clobbering
; the stack cookie.
;
; Notes:
;
; If RdRand fails, the build time static stack cookie value will be used instead.
;
;------------------------------------------------------------------------------
DEFAULT REL
SECTION .text
extern ASM_PFX(__security_cookie)
extern ASM_PFX(_CModuleEntryPoint)
;------------------------------------------------------------------------------
; VOID
; EFIAPI
; _ModuleEntryPoint (
; Parameters are passed through. TODO: Make sure there are only two args on X64
; );
;------------------------------------------------------------------------------
global ASM_PFX(_ModuleEntryPoint)
ASM_PFX(_ModuleEntryPoint):
push rbx
push rcx
push rdx
mov eax, 1 ; Set eax to 1 to get feature information
cpuid ; Call cpuid
test ecx, 0x40000000 ; Test the rdrand bit (bit 30) in ecx
jz c_entry ; If rdrand is not supported, jump to c_entry
rdrand rax ; Call rdrand functionality here, getting a 64 bit value as on
; X64, __stack_chk_guard is a 64 bit value.
; CF=1 if RN generated ok, otherwise CF=0
jnc c_entry ; If the cmd fails, don't, update __stack_chk_guard, we'll have to move forward
; with the static value provided at build time.
lea rbx, [rel ASM_PFX(__security_cookie)] ; load the address of __stack_check_guard into rbx
xor ah, ah ; Zero a byte of the __stack_chk_guard value to protect against string functions
; (such as strcpy like functions) clobbering past the canary
mov [rbx], rax ; Store our random value, with 0'd first byte to __stack_chk_guard
c_entry:
pop rdx
pop rcx
pop rbx
jmp ASM_PFX(_CModuleEntryPoint)

View File

@ -1,12 +1,12 @@
# StackCheckLib
# StackCheckLib Overview
## Table of Contents
- [StackCheckLib](#stackchecklib)
- [Table of Contents](#table-of-contents)
- [Introduction and Library Instances](#introduction-and-library-instances)
- [StackCheckLibStaticInit](#stackchecklibstaticinit)
- [StackCheckLibDynamicInit](#stackchecklibdynamicinit)
- [StackCheckLib](#stackchecklib)
- [DynamicStackCookieEntryPointLib](#dynamicstackcookieentrypointlib)
- [StackCheckLibNull](#stackchecklibnull)
- [How Failures are Handled](#how-failures-are-handled)
- [Debugging Stack Cookie Check Failures](#debugging-stack-cookie-check-failures)
@ -15,44 +15,79 @@
## Introduction and Library Instances
`StackCheckLib` contains the required functionality for initializing the stack cookie
value, checking the value, and triggering an interrupt when a mismatch occurs.
The stack cookie is a random value placed on the stack between the stack variables
and the return address so that continuously writing past the stack variables will
cause the stack cookie to be overwritten. Before the function returns, the stack
cookie value will be checked and if there is a mismatch then `StackCheckLib` handles
the failure.
value (based on a randomly generated value during build time), checking the value,
and triggering an interrupt when a mismatch occurs. The stack cookie is a random value
placed on the stack between the stack variables and the return address so that
continuously writing past the stack variables will cause the stack cookie to be
overwritten. Before the function returns, the stack cookie value will be checked and
if there is a mismatch then `StackCheckLib` handles the failure.
Because UEFI doesn't use the C runtime libraries provided by MSVC, the stack
check code is written in assembly within this library. GCC and Clang compilers
have built-in support for stack cookie checking, so this library only handles failures.
### StackCheckLibStaticInit
The stack cookie value is initialized at compile time via updates to the AutoGen process.
Each module will define `STACK_COOKIE_VALUE` which is used for the module stack cookie
value.
`StackCheckLibStaticInit` is an instance of `StackCheckLib` which does not update the
stack cookie value for the module at runtime. It's always preferable to use
`StackCheckLibDynamicInit` for improved security but there are cases where the stack
cookie global cannot be written to such as in execute-in-place (XIP) modules and during
the Cache-as-RAM (CAR) phase of the boot process. The stack cookie value is initialized
at compile time via updates to the AutoGen process. Each module will define
`STACK_COOKIE_VALUE` which is used for the module stack cookie value.
The entry point libraries under `MdePkg/DynamicStackCookieEntryPointLib/` update the stack
cookie value at runtime for improved security, but there are cases where the stack cookie
global cannot be written to such as in execute-in-place (XIP) modules and during the
temporary RAM phase of the boot process. It is always preferable to use
one of the dynamic stack cookie entry points when possible.
### StackCheckLibDynamicInit
### StackCheckLib
This section is future work. The below is the proposed instance.
`StackCheckLib` provides the stack cookie checking functionality per architecture and
toolchain. The currently supported pairs are IA32{GCC,MSVC}, X64{GCC, MSVC},
ARM{GCC, MSVC}, and AARCH64{GCC, MSVC}. `StackCheckLib` is agnostic as to
whether the stack cookie was updated during build time or run time; it simply
checks the cookie in the MSVC case and in both GCC and MSVC responds to stack
cookie checking failures.
`StackCheckLibDynamicInit` is an instance of `StackCheckLib` which updates the stack
cookie value for the module at runtime. This is the preferred method for stack cookie
initialization as it provides improved security. The stack cookie value is initialized
at runtime by calling `GetRandomNumber32()` or `GetRandomNumber64()` to generate a random
value via the platform's random number generator protocol. If the random number generator
returns an error, then the value will still have the build-time randomized value to fall
back on.
To add support for other architectures/toolchains, additional assembly files
should be added to `StackCheckLib.inf` and scoped to that architecture/toolchain.
Note: Stack cookie failures generate exceptions and SEC and PEI_CORE may not have
exception handlers registered. In order to safely use stack cookie checking in
these phases, a platform should implement exception handlers because unhandled
exceptions may lead to a hung system state. If a platform does not implement
exception handlers in SEC and PEI_CORE, it is recommended to use `StackCheckLibNull`
for these phases, except for development purposes.
### DynamicStackCookieEntryPointLib
Each EntryPoint lib under `MdePkg/DynamicStackCookieEntryPointLib/` is an instance of
that module type entry point lib which updates the stack cookie value for the module at
runtime. This is the preferred method for stack cookie initialization as it provides
improved security. The stack cookie value is initialized at runtime in `_ModuleEntryPoint`
by calling `rdrand` on x86 and `RNDR` on AARCH64. If the random number generator is not
supported on that platform or otherwise returns an error, then the value will still have
the build-time randomized value to fall back on.
Typically, dynamic cookies cannot be used for SEC, PEI_CORE, and PEIM modules, due to
the lack of the ability to write to globals for many architectures. If a given platform
can write to globals during these phases, it is recommended to use the provided dynamic
stack cookie entry point lib for those types. Note that SEC does not have a universal
entry point, so there is no dynamic stack cookie entry point lib there.
The dynamic stack cookie entry point lib is used in place of the standard entry point lib,
e.g. for UefiDriverEntryPoint to have dynamic stack cookies, a platform would remove
MdePkg/Library/UefiDriverEntryPoint/UefiDriverEntryPoint.inf from its DSC and instead
include MdePkg/Library/DynamicStackCookieEntryPointLib/UefiDriverEntryPoint.inf.
See the Usage section for other ways of including these libraries.
Note: Standalone MM Core support for dynamic cookies for AARCH64 is currently not
supported, due to the unique entry point mechanism there. This support will be
added at a future date.
### StackCheckLibNull
`StackCheckLibNull` is an instance of `StackCheckLib` which does not perform any stack
cookie checks. This is useful for modules which will fail if stack cookie checks are
inserted. Of course, this is not recommended for production code.
inserted. Of course, this is not recommended for production code outside of
SEC and PEI_CORE.
## How Failures are Handled
@ -104,8 +139,9 @@ edk2 updated the tools_def to add `/GS` to VS2022 and VS2019 IA32/X64 builds and
`-fstack-protector` to GCC builds. This will cause stack cookie references to be inserted
throughout the code. Every module should have a `StackCheckLib` instance linked to satisfy
these references. So every module doesn't need to add `StackCheckLib` to the LibraryClasses
section of the INF file, `StackCheckLib` instances should be linked as NULL in the platform
DSC files. The only exception to this is MSVC built host-based unit tests as they will be
section of the INF file, `StackCheckLib` is added as a dependency for each entry point lib.
This means that custom entry point libs need to have StackCheckLib added as a dependency.
The only exception to this is MSVC built host-based unit tests as they will be
compiled with the runtime libraries which already contain the stack cookie definitions
and will collide with `StackCheckLib`. A `StackCheckLibHostApplication.inf` is linked
by `UnitTestFrameworkPkg/UnitTestFrameworkPkgHost.dsc.inc` that provides the stack
@ -113,70 +149,80 @@ cookie functions for GCC HOST_APPLICATIONS but not for MSVC HOST_APPLICATIONS.
### Default Stack Check Library Configuration
`MdePkg/MdeLibs.dsc.inc` links `StackCheckLibNull` for all types except SEC, HOST_APPLICATION,
and USER_DEFINED in order to not break existing DSCs. SEC cannot be generically linked to
because there are some SEC modules which do not link against the standard entry point
libraries and thus do not get stack cookies inserted by the compiler. USER_DEFINED modules
are by nature different from other modules, so we do not make any assumptions about their
state.
`MdePkg/MdeLibs.dsc.inc` links `StackCheckLibNull` and `StackCheckFailureLibNull` for all
types.
As stated above, all HOST_APPLICATIONS will link against a HOST_APPLICATION specific
implementation provided in `UnitTestFrameworkPkg/UnitTestFrameworkPkgHost.dsc.inc`.
To link the rest of a platform's modules to `StackCheckLibNull`, a platform would needs
to link it for all SEC and USER_DEFINED modules. If all of the DSC's SEC and USER_DEFINED
modules link against the entry point libs, it would look like the following:
```inf
[LibraryClasses.common.SEC, LibraryClasses.common.USER_DEFINED]
NULL|MdePkg/Library/StackCheckLibNull/StackCheckLibNull.inf
```
If some do not, then the individual SEC/USER_DEFINED modules that do link against
the entry point libs will need to be linked to `StackCheckLibNull`, such as below.
This case is identifiable if a DSC is built and the linker complains the stack
check functions are not found for a module.
```inf
UefiCpuPkg/SecCore/SecCore.inf {
<LibraryClasses>
NULL|MdePkg/Library/StackCheckLibNull/StackCheckLibNull.inf
}
```
### Custom Stack Check Library Configuration
In order to use a different instance of StackCheckLib than `MdeLibs.dsc.inc` provides, a DSC
should add the following:
should add one of the following:
#### Static Stack Check Cookie Configuration
```inf
[Defines]
DEFINE CUSTOM_STACK_CHECK_LIB = TRUE
DEFINE CUSTOM_STACK_CHECK_LIB = STATIC
```
This will cause `MdeLibs.dsc.inc` to not link `StackCheckLibNull` and rely on a DSC to
link whichever version(s) of `StackCheckLib` it desires.
This will cause `MdeLibs.dsc.inc` to not link `StackCheckLibNull` and instead link
`StackCheckLib` to perform stack cookie checking on the static stack cookies, but not update
any of the stack cookies at runtime.
It is recommended that SEC and PEI_CORE modules use `StackCheckLibNull` and pre-memory modules
should use `StackCheckLibStaticInit`. All other modules should use `StackCheckLibDynamicInit`.
Below is an **example** of how to link the `StackCheckLib` instances in the platform DSC file
but it may need customization based on the platform's requirements:
Because edk2 does not implement exception handling for `SEC` and `PEI_CORE`, `MdeLibs.dsc.inc`
uses `StackCheckLibNull` for these phases always. If a platform wishes to use `StackCheckLib`
for these phases, it should override this in its DSC, e.g.:
```inf
[LibraryClasses.common.SEC, LibraryClasses.common.PEI_CORE]
NULL|MdePkg/Library/StackCheckLibNull/StackCheckLibNull.inf
[LibraryClasses.common.PEIM]
NULL|MdePkg/Library/StackCheckLib/StackCheckLibStaticInit.inf
[LibraryClasses.common.MM_CORE_STANDALONE, LibraryClasses.common.MM_STANDALONE, LibraryClasses.common.DXE_CORE,
LibraryClasses.common.SMM_CORE, LibraryClasses.common.DXE_SMM_DRIVER, LibraryClasses.common.DXE_DRIVER,
LibraryClasses.common.DXE_RUNTIME_DRIVER, LibraryClasses.common.DXE_SAL_DRIVER, LibraryClasses.common.UEFI_DRIVER,
LibraryClasses.common.UEFI_APPLICATION]
NULL|MdePkg/Library/StackCheckLib/StackCheckLibDynamicInit.inf
StackCheckLib|MdePkg/Library/StackCheckLib/StackCheckLib.inf
```
It is recommended that a platform only do this for debugging or if they have implemented
exception handlers for these phases.
#### Dynamic Stack Cookie Configuration
```inf
[Defines]
DEFINE CUSTOM_STACK_CHECK_LIB = DYNAMIC
```
This will cause `MdeLibs.dsc.inc` to not link `StackCheckLibNull` and instead link
`StackCheckLib` to perform stack cookie checking. It will also link the dynamic
stack cookie updating versions of `DxeCoreEntryPoint`, `StandaloneMmDriverEntryPoint`,
`UefiApplicationEntryPoint`, and `UefiDriverEntryPoint`.
Because edk2 does not implement exception handling for `SEC` and `PEI_CORE`, `MdeLibs.dsc.inc`
uses `StackCheckLibNull` for these phases always. As a result, dynamic stack cookies are also
not set for `PEI_CORE`. There is no standard `SEC` entrypoint, so it is not supported generically
to apply dynamic stack cookies there. If a platform wishes to use `StackCheckLib` and dynamic stack
cookies for these phases, it should override this in its DSC, e.g.:
```inf
[LibraryClasses.common.SEC, LibraryClasses.common.PEI_CORE]
StackCheckLib|MdePkg/Library/StackCheckLib/StackCheckLib.inf
PeiCoreEntryPoint|MdePkg/Library/DynamicStackCookieEntryPointLib/PeiCoreEntryPoint.inf
```
It is recommended that a platform only do this for debugging or if they have implemented
exception handlers for these phases.
Note: `StandaloneMmCoreEntryPoint` is recommended to use the dynamic stack cookie if
possible, but as it is not supported on AARCH64 today, it is not included in MdeLibs.dsc.inc.
Platforms should include this separately, e.g.:
```inf
[LibraryClasses.X64]
StandaloneMmCoreEntryPoint|MdePkg/Library/DynamicStackCookieEntryPointLib/StandaloneMmCoreEntryPoint.inf
```
Platforms then must remove any references to these entry point libs in their DSC, so that
the `MdeLibs.dsc.inc` versions are chosen. Alternatively, for better DSC readability,
a platform can directly reference the dynamic stack cookie entry points.
### Disable Stack Check Library
If a platform would like to disable stack cookies (say for debugging purposes),
@ -191,4 +237,14 @@ they can add the following to their DSC:
The same build options can be put in a module's INF to only disable stack cookies
for that module.
Alternatively, a module can have the stack cookies inserted but checking disabled
by including the following in a DSC:
```inf
SomePkg/SomeDirectory/SomeModule.inf {
<LibraryClasses>
StackCheckLib|MdePkg/Library/StackCheckLibNull/StackCheckLibNull.inf
}
```
It is not recommended to disable stack cookie checking in production scenarios.

View File

@ -11,6 +11,14 @@
#
##
[Defines]
!ifndef CUSTOM_STACK_CHECK_LIB
# The DSC parser will set any unset macros to 0. Then, below when we check for STATIC or DYNAMIC, even if we couch
# that in a !ifdef CUSTOM_STACK_CHECK_LIB, the parser will issue a warning that we are comparing a boolean (0) against
# a string, which will always fail. So we set it to a dummy value here.
DEFINE CUSTOM_STACK_CHECK_LIB = NONE
!endif
[LibraryClasses]
OrderedCollectionLib|MdePkg/Library/BaseOrderedCollectionRedBlackTreeLib/BaseOrderedCollectionRedBlackTreeLib.inf
ArmTrngLib|MdePkg/Library/BaseArmTrngLibNull/BaseArmTrngLibNull.inf
@ -22,13 +30,35 @@
MmUnblockMemoryLib|MdePkg/Library/MmUnblockMemoryLib/MmUnblockMemoryLibNull.inf
StackCheckFailureHookLib|MdePkg/Library/StackCheckFailureHookLibNull/StackCheckFailureHookLibNull.inf
!ifndef CUSTOM_STACK_CHECK_LIB
!if $(CUSTOM_STACK_CHECK_LIB) == STATIC
# To only use the static stack cookie, we just include the checking functionality.
StackCheckLib|MdePkg/Library/StackCheckLib/StackCheckLib.inf
!elseif $(CUSTOM_STACK_CHECK_LIB) == DYNAMIC
StackCheckLib|MdePkg/Library/StackCheckLib/StackCheckLib.inf
# To use the dynamic stack cookie, we need to include the entry point libraries that will set up the stack cookie.
# Typically, PeiCore and PEIMs will not use dynamic stack cookies, so they are not included generally.
# If dynamic stack cookies are not enabled, we do not setup the entry points, as the existing behavior was
# for a platform to define them.
# StandaloneMmCoreEntryPoint is not included here because support dynamic stack cookies is not available for
# AARCH64 here. X64 platforms should include the DynamicStackCookieEntryPointLib in their DSC file.
DxeCoreEntryPoint|MdePkg/Library/DynamicStackCookieEntryPointLib/DxeCoreEntryPoint.inf
StandaloneMmDriverEntryPoint|MdePkg/Library/DynamicStackCookieEntryPointLib/StandaloneMmDriverEntryPoint.inf
UefiApplicationEntryPoint|MdePkg/Library/DynamicStackCookieEntryPointLib/UefiApplicationEntryPoint.inf
UefiDriverEntryPoint|MdePkg/Library/DynamicStackCookieEntryPointLib/UefiDriverEntryPoint.inf
!else
# If CUSTOM_STACK_CHECK_LIB is set, MdeLibs.dsc.inc will not link StackCheckLibNull and it is expected that the
# DSC being built is providing it's own implementation of StackCheckLib.
NULL|MdePkg/Library/StackCheckLibNull/StackCheckLibNull.inf
StackCheckLib|MdePkg/Library/StackCheckLibNull/StackCheckLibNull.inf
!endif
[LibraryClasses.common.SEC, LibraryClasses.common.PEI_CORE]
# edk2 does not implement exception handling for SEC and PEI_CORE, so StackCheckLibNull is used, as failing
# stack cookies will generate an exception, which if unhandled can lead to a hung system state. If a platform
# implements exception handling for SEC and PEI_CORE, it can use StackCheckLib for these phases in its DSC.
StackCheckLib|MdePkg/Library/StackCheckLibNull/StackCheckLibNull.inf
[LibraryClasses.ARM, LibraryClasses.AARCH64]
#
# It is not possible to prevent the ARM/AARCH64 compilers from inserting generic intrinsic functions.

View File

@ -143,6 +143,12 @@
MdePkg/Library/StackCheckFailureHookLibNull/StackCheckFailureHookLibNull.inf
MdePkg/Library/StackCheckLibNull/StackCheckLibNull.inf
MdePkg/Library/StackCheckLib/StackCheckLib.inf
MdePkg/Library/DynamicStackCookieEntryPointLib/DxeCoreEntryPoint.inf
MdePkg/Library/DynamicStackCookieEntryPointLib/PeiCoreEntryPoint.inf
MdePkg/Library/DynamicStackCookieEntryPointLib/PeimEntryPoint.inf
MdePkg/Library/DynamicStackCookieEntryPointLib/StandaloneMmDriverEntryPoint.inf
MdePkg/Library/DynamicStackCookieEntryPointLib/UefiApplicationEntryPoint.inf
MdePkg/Library/DynamicStackCookieEntryPointLib/UefiDriverEntryPoint.inf
[Components.IA32, Components.X64, Components.ARM, Components.AARCH64]
#
@ -193,6 +199,7 @@
MdePkg/Library/TraceHubDebugSysTLibNull/TraceHubDebugSysTLibNull.inf
[Components.X64]
MdePkg/Library/DynamicStackCookieEntryPointLib/StandaloneMmCoreEntryPoint.inf
MdePkg/Library/StandaloneMmCoreEntryPoint/StandaloneMmCoreEntryPoint.inf
[Components.EBC]