From ac43bbacdef18a6fea6d978e096326ec0805885d Mon Sep 17 00:00:00 2001 From: Taylor Beebe Date: Tue, 27 Aug 2024 14:31:48 -0700 Subject: MdePkg: Create Stack Check Null Libs Add Null libs for Stack Check and Stack Check Failure Hook Lib that allow a platform to opt out of stack checks and the stack check failure hook lib. StackCheckLib allows implementation (or in this case null implementation) of stack checks on binaries. There is a Host Application specific version of this null lib because MSVC host applications must not be linked against our lib (so the file here is a no-op but that doesn't cause the build system to fail the build for not building a file for MSVC) as it links against the MSVC C runtime lib that provides the stack cookie definitions. GCC host applications do not link against such a C runtime lib and must be linked against our version. StackCheckFailureHookLib lets a platform do custom functionality when a stack check failure occurs (such as log it to a platform defined mechanism). The null lib simply returns. Signed-off-by: Oliver Smith-Denny --- MdePkg/Include/Library/StackCheckFailureHookLib.h | 26 ++++++++++++++ .../StackCheckFailureHook.c | 25 +++++++++++++ .../StackCheckFailureHookLibNull.inf | 20 +++++++++++ .../IA32/StackCheckFunctionsMsvc.nasm | 21 +++++++++++ .../StackCheckLibHostApplicationMsvc.c | 13 +++++++ .../StackCheckLibNull/StackCheckLibNull.inf | 41 ++++++++++++++++++++++ .../StackCheckLibNull/StackCheckLibNullGcc.c | 23 ++++++++++++ .../StackCheckLibNullHostApplication.inf | 34 ++++++++++++++++++ .../StackCheckLibNull/StackCheckLibNullMsvc.c | 10 ++++++ .../X64/StackCheckFunctionsMsvc.nasm | 21 +++++++++++ MdePkg/MdeLibs.dsc.inc | 6 ++++ MdePkg/MdePkg.ci.yaml | 4 ++- MdePkg/MdePkg.dec | 4 +++ MdePkg/MdePkg.dsc | 3 ++ MdePkg/Test/MdePkgHostTest.dsc | 2 ++ 15 files changed, 252 insertions(+), 1 deletion(-) create mode 100644 MdePkg/Include/Library/StackCheckFailureHookLib.h create mode 100644 MdePkg/Library/StackCheckFailureHookLibNull/StackCheckFailureHook.c create mode 100644 MdePkg/Library/StackCheckFailureHookLibNull/StackCheckFailureHookLibNull.inf create mode 100644 MdePkg/Library/StackCheckLibNull/IA32/StackCheckFunctionsMsvc.nasm create mode 100644 MdePkg/Library/StackCheckLibNull/StackCheckLibHostApplicationMsvc.c create mode 100644 MdePkg/Library/StackCheckLibNull/StackCheckLibNull.inf create mode 100644 MdePkg/Library/StackCheckLibNull/StackCheckLibNullGcc.c create mode 100644 MdePkg/Library/StackCheckLibNull/StackCheckLibNullHostApplication.inf create mode 100644 MdePkg/Library/StackCheckLibNull/StackCheckLibNullMsvc.c create mode 100644 MdePkg/Library/StackCheckLibNull/X64/StackCheckFunctionsMsvc.nasm (limited to 'MdePkg') diff --git a/MdePkg/Include/Library/StackCheckFailureHookLib.h b/MdePkg/Include/Library/StackCheckFailureHookLib.h new file mode 100644 index 0000000000..f0657ddfa0 --- /dev/null +++ b/MdePkg/Include/Library/StackCheckFailureHookLib.h @@ -0,0 +1,26 @@ +/** @file + Library provides a hook called when a stack cookie check fails. + + Copyright (c) Microsoft Corporation. + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#ifndef STACK_COOKIE_FAILURE_HOOK_LIB_H_ +#define STACK_COOKIE_FAILURE_HOOK_LIB_H_ + +#include + +/** + This function gets called when a compiler generated stack cookie fails. This allows a platform to hook this + call and perform any required actions/telemetry at that time. + + @param FailureAddress The address of the function that failed the stack cookie check. + +**/ +VOID +EFIAPI +StackCheckFailureHook ( + VOID *FailureAddress + ); + +#endif diff --git a/MdePkg/Library/StackCheckFailureHookLibNull/StackCheckFailureHook.c b/MdePkg/Library/StackCheckFailureHookLibNull/StackCheckFailureHook.c new file mode 100644 index 0000000000..0a258e4773 --- /dev/null +++ b/MdePkg/Library/StackCheckFailureHookLibNull/StackCheckFailureHook.c @@ -0,0 +1,25 @@ +/** @file + Library provides a hook called when a stack cookie check fails. + + Copyright (c) Microsoft Corporation. + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include +#include + +/** + This function gets called when a compiler generated stack cookie fails. This allows a platform to hook this + call and perform any required actions/telemetry at that time. + + @param FailureAddress The address of the function that failed the stack cookie check. + +**/ +VOID +EFIAPI +StackCheckFailureHook ( + VOID *FailureAddress + ) +{ + return; +} diff --git a/MdePkg/Library/StackCheckFailureHookLibNull/StackCheckFailureHookLibNull.inf b/MdePkg/Library/StackCheckFailureHookLibNull/StackCheckFailureHookLibNull.inf new file mode 100644 index 0000000000..300073a7e7 --- /dev/null +++ b/MdePkg/Library/StackCheckFailureHookLibNull/StackCheckFailureHookLibNull.inf @@ -0,0 +1,20 @@ +## @file +# Library provides a hook called when a stack cookie check fails. +# +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +[Defines] + INF_VERSION = 1.29 + BASE_NAME = StackCheckFailureHookLibNull + FILE_GUID = 9ca2587c-d1f2-451a-989a-d49a9a0a613e + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = StackCheckFailureHookLib + +[Sources] + StackCheckFailureHook.c + +[Packages] + MdePkg/MdePkg.dec diff --git a/MdePkg/Library/StackCheckLibNull/IA32/StackCheckFunctionsMsvc.nasm b/MdePkg/Library/StackCheckLibNull/IA32/StackCheckFunctionsMsvc.nasm new file mode 100644 index 0000000000..510d500847 --- /dev/null +++ b/MdePkg/Library/StackCheckLibNull/IA32/StackCheckFunctionsMsvc.nasm @@ -0,0 +1,21 @@ +;------------------------------------------------------------------------------ +; IA32/StackCheckFunctionsMsvc.nasm +; +; Copyright (c) Microsoft Corporation. +; SPDX-License-Identifier: BSD-2-Clause-Patent +;------------------------------------------------------------------------------ + + DEFAULT REL + SECTION .text + +global ASM_PFX(__report_rangecheckfailure) +ASM_PFX(__report_rangecheckfailure): + ret + +global ASM_PFX(__GSHandlerCheck) +ASM_PFX(__GSHandlerCheck): + ret + +global @__security_check_cookie@4 +@__security_check_cookie@4: + ret diff --git a/MdePkg/Library/StackCheckLibNull/StackCheckLibHostApplicationMsvc.c b/MdePkg/Library/StackCheckLibNull/StackCheckLibHostApplicationMsvc.c new file mode 100644 index 0000000000..6af9891c39 --- /dev/null +++ b/MdePkg/Library/StackCheckLibNull/StackCheckLibHostApplicationMsvc.c @@ -0,0 +1,13 @@ +/** @file + This file is empty to allow host applications + to use the MSVC C runtime lib that provides + stack cookie definitions without breaking the + build. + + Copyright (c) Microsoft Corporation. + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include + +extern VOID *__security_cookie; diff --git a/MdePkg/Library/StackCheckLibNull/StackCheckLibNull.inf b/MdePkg/Library/StackCheckLibNull/StackCheckLibNull.inf new file mode 100644 index 0000000000..bb42833d02 --- /dev/null +++ b/MdePkg/Library/StackCheckLibNull/StackCheckLibNull.inf @@ -0,0 +1,41 @@ +## @file +# Null library instance for StackCheckLib which can be included +# when a build needs to include stack check functions but does +# not want to generate stack check failures. +# +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +[Defines] + INF_VERSION = 1.29 + BASE_NAME = StackCheckLibNull + FILE_GUID = f6ef2763-ca3b-4c6f-a931-2a48de3ce352 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = StackCheckLib + +[Sources] + StackCheckLibNullGcc.c | GCC + StackCheckLibNullMsvc.c | MSFT + +[Sources.IA32] + IA32/StackCheckFunctionsMsvc.nasm | MSFT + +[Sources.X64] + X64/StackCheckFunctionsMsvc.nasm | MSFT + +[Packages] + MdePkg/MdePkg.dec + +[BuildOptions] + # We cannot build the MSVC version with /GL (whole program optimization) because we run into linker error + # LNK1237, which is a failure to link against a symbol from a library compiled with /GL. The whole program + # optimization tries to do away with references to this symbol. The solution is to not compile the stack + # check libs with /GL + MSFT:*_*_*_CC_FLAGS = /GL- + + # We cannot build the GCC version with LTO (link time optimization) because we run into linker errors where + # the stack cookie variable has been optimized away, as it looks to GCC like the variable is not used, because + # the compiler inserts the usage. + GCC:*_*_*_CC_FLAGS = -fno-lto diff --git a/MdePkg/Library/StackCheckLibNull/StackCheckLibNullGcc.c b/MdePkg/Library/StackCheckLibNull/StackCheckLibNullGcc.c new file mode 100644 index 0000000000..cc30632761 --- /dev/null +++ b/MdePkg/Library/StackCheckLibNull/StackCheckLibNullGcc.c @@ -0,0 +1,23 @@ +/** @file + Defines the stack cookie variable for GCC and Clang compilers. + + Copyright (c) Microsoft Corporation. + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include + +VOID *__stack_chk_guard = (VOID *)(UINTN)0x0; + +/** + This function gets called when a gcc/clang generated stack cookie fails. This implementation does nothing when + a stack cookie failure occurs. + +**/ +VOID +EFIAPI +__stack_chk_fail ( + VOID + ) +{ +} diff --git a/MdePkg/Library/StackCheckLibNull/StackCheckLibNullHostApplication.inf b/MdePkg/Library/StackCheckLibNull/StackCheckLibNullHostApplication.inf new file mode 100644 index 0000000000..3e898263c2 --- /dev/null +++ b/MdePkg/Library/StackCheckLibNull/StackCheckLibNullHostApplication.inf @@ -0,0 +1,34 @@ +## @file +# Null library instance for StackCheckLib which can be included +# when a build needs to include stack check functions but does +# not want to generate stack check failures. This instance is used +# for HOST_APPLICATIONS specifically, as MSVC host applications link +# to the C runtime lib that contains the stack cookie definitions, so +# must link to a completely null version of this lib, whereas GCC host +# host applications do not link to a C runtime lib that contains the stack +# cookie definitions, so we must link against our version. +# +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +[Defines] + INF_VERSION = 1.29 + BASE_NAME = StackCheckLibNullHostApplication + FILE_GUID = 7EBE7BD1-0D92-4609-89AA-6EA3815CB844 + MODULE_TYPE = HOST_APPLICATION + VERSION_STRING = 1.0 + LIBRARY_CLASS = StackCheckLib|HOST_APPLICATION + +[Sources] + StackCheckLibHostApplicationMsvc.c | MSFT + StackCheckLibNullGcc.c | GCC + +[Packages] + MdePkg/MdePkg.dec + +[BuildOptions] + # We cannot build the GCC version with LTO (link time optimization) because we run into linker errors where + # the stack cookie variable has been optimized away, as it looks to GCC like the variable is not used, because + # the compiler inserts the usage. We do not worry about the MSVC version here as it is a no-op. + GCC:*_*_*_CC_FLAGS = -fno-lto diff --git a/MdePkg/Library/StackCheckLibNull/StackCheckLibNullMsvc.c b/MdePkg/Library/StackCheckLibNull/StackCheckLibNullMsvc.c new file mode 100644 index 0000000000..ba9a4e6f3c --- /dev/null +++ b/MdePkg/Library/StackCheckLibNull/StackCheckLibNullMsvc.c @@ -0,0 +1,10 @@ +/** @file + Defines the stack cookie variable for GCC, Clang and MSVC compilers. + + Copyright (c) Microsoft Corporation. + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include + +VOID *__security_cookie = (VOID *)(UINTN)0x0; diff --git a/MdePkg/Library/StackCheckLibNull/X64/StackCheckFunctionsMsvc.nasm b/MdePkg/Library/StackCheckLibNull/X64/StackCheckFunctionsMsvc.nasm new file mode 100644 index 0000000000..f4639a03d2 --- /dev/null +++ b/MdePkg/Library/StackCheckLibNull/X64/StackCheckFunctionsMsvc.nasm @@ -0,0 +1,21 @@ +;------------------------------------------------------------------------------ +; X64/StackCheckFunctionsMsvc.nasm +; +; Copyright (c) Microsoft Corporation. +; SPDX-License-Identifier: BSD-2-Clause-Patent +;------------------------------------------------------------------------------ + + DEFAULT REL + SECTION .text + +global ASM_PFX(__report_rangecheckfailure) +ASM_PFX(__report_rangecheckfailure): + ret + +global ASM_PFX(__GSHandlerCheck) +ASM_PFX(__GSHandlerCheck): + ret + +global ASM_PFX(__security_check_cookie) +ASM_PFX(__security_check_cookie): + ret diff --git a/MdePkg/MdeLibs.dsc.inc b/MdePkg/MdeLibs.dsc.inc index e40ff7d95e..4e3858edb6 100644 --- a/MdePkg/MdeLibs.dsc.inc +++ b/MdePkg/MdeLibs.dsc.inc @@ -30,3 +30,9 @@ # definitions for the intrinsic functions. # NULL|MdePkg/Library/CompilerIntrinsicsLib/CompilerIntrinsicsLib.inf + +# Stack Cookies cannot be generically applied to SEC modules because they may not define _ModuleEntryPoint and when we +# link a library in, we have to be able to define the entry point. SEC modules that do define _ModuleEntryPoint can +# apply a library class override to get StackCheckLibNull.inf +[LibraryClasses.common.PEI_CORE, LibraryClasses.common.PEIM, LibraryClasses.common.DXE_CORE, LibraryClasses.common.SMM_CORE, LibraryClasses.common.MM_CORE_STANDALONE, LibraryClasses.common.DXE_DRIVER, LibraryClasses.common.DXE_RUNTIME_DRIVER, LibraryClasses.common.DXE_SMM_DRIVER, LibraryClasses.common.MM_STANDALONE, LibraryClasses.common.UEFI_DRIVER, LibraryClasses.common.UEFI_APPLICATION] + NULL|MdePkg/Library/StackCheckLibNull/StackCheckLibNull.inf diff --git a/MdePkg/MdePkg.ci.yaml b/MdePkg/MdePkg.ci.yaml index f2d81af080..cebccba59d 100644 --- a/MdePkg/MdePkg.ci.yaml +++ b/MdePkg/MdePkg.ci.yaml @@ -61,7 +61,9 @@ "7007", "_EFI_SPI_NOR_FLASH_PROTOCOL", "7007", "_EFI_SPI_HC_PROTOCOL", "8002", "aligned (", - "4002", "_ReturnAddress" + "4002", "_ReturnAddress", + "8005", "__security_cookie", + "8006", "__stack_chk_fail" ], ## Both file path and directory path are accepted. "IgnoreFiles": [ diff --git a/MdePkg/MdePkg.dec b/MdePkg/MdePkg.dec index 8d5947fc9e..b542d6d832 100644 --- a/MdePkg/MdePkg.dec +++ b/MdePkg/MdePkg.dec @@ -303,6 +303,10 @@ # TraceHubDebugSysTLib|Include/Library/TraceHubDebugSysTLib.h + ## @libraryclass Provides a hook called when a stack cookie check fails. + # + StackCheckFailureHookLib|Include/Library/StackCheckFailureHookLib.h + [LibraryClasses.IA32, LibraryClasses.X64, LibraryClasses.AARCH64] ## @libraryclass Provides services to generate random number. # diff --git a/MdePkg/MdePkg.dsc b/MdePkg/MdePkg.dsc index ebcd79864d..f410a89a00 100644 --- a/MdePkg/MdePkg.dsc +++ b/MdePkg/MdePkg.dsc @@ -139,6 +139,9 @@ MdePkg/Library/JedecJep106Lib/JedecJep106Lib.inf MdePkg/Library/BaseFdtLib/BaseFdtLib.inf + MdePkg/Library/StackCheckFailureHookLibNull/StackCheckFailureHookLibNull.inf + MdePkg/Library/StackCheckLibNull/StackCheckLibNull.inf + [Components.IA32, Components.X64, Components.ARM, Components.AARCH64] # # Add UEFI Target Based Unit Tests diff --git a/MdePkg/Test/MdePkgHostTest.dsc b/MdePkg/Test/MdePkgHostTest.dsc index 6a85d02236..1351d19157 100644 --- a/MdePkg/Test/MdePkgHostTest.dsc +++ b/MdePkg/Test/MdePkgHostTest.dsc @@ -47,3 +47,5 @@ MdePkg/Test/Mock/Library/GoogleTest/MockPeiServicesLib/MockPeiServicesLib.inf MdePkg/Test/Mock/Library/GoogleTest/MockHobLib/MockHobLib.inf MdePkg/Test/Mock/Library/GoogleTest/MockFdtLib/MockFdtLib.inf + + MdePkg/Library/StackCheckLibNull/StackCheckLibNullHostApplication.inf -- cgit v1.2.3