--- /dev/null
+//------------------------------------------------------------------------------\r
+// AArch64/StackCookieInterrupt.S\r
+//\r
+// Copyright (c) Microsoft Corporation.\r
+// SPDX-License-Identifier: BSD-2-Clause-Patent\r
+//------------------------------------------------------------------------------\r
+\r
+ .text\r
+\r
+//------------------------------------------------------------------------------\r
+// Calls an interrupt using the vector specified by PcdStackCookieExceptionVector\r
+//\r
+// VOID\r
+// TriggerStackCookieInterrupt (\r
+// VOID\r
+// );\r
+//------------------------------------------------------------------------------\r
+.global ASM_PFX(TriggerStackCookieInterrupt)\r
+ASM_PFX(TriggerStackCookieInterrupt):\r
+ svc FixedPcdGet8 (PcdStackCookieExceptionVector)\r
+ ret\r
--- /dev/null
+;------------------------------------------------------------------------------\r
+; AArch64/StackCookieInterrupt.asm\r
+;\r
+; Copyright (c) Microsoft Corporation.\r
+; SPDX-License-Identifier: BSD-2-Clause-Patent\r
+;------------------------------------------------------------------------------\r
+\r
+ EXPORT TriggerStackCookieInterrupt\r
+\r
+ AREA |.text|, CODE, READONLY\r
+\r
+;------------------------------------------------------------------------------\r
+; Calls an interrupt using the vector specified by PcdStackCookieExceptionVector\r
+;\r
+; VOID\r
+; TriggerStackCookieInterrupt (\r
+; VOID\r
+; );\r
+;------------------------------------------------------------------------------\r
+TriggerStackCookieInterrupt PROC\r
+ SVC FixedPcdGet8 (PcdStackCookieExceptionVector)\r
+ RET\r
+TriggerStackCookieInterrupt ENDP\r
+\r
+ END\r
--- /dev/null
+//------------------------------------------------------------------------------\r
+// Arm/StackCookieInterrupt.S\r
+//\r
+// Copyright (c) Microsoft Corporation.\r
+// SPDX-License-Identifier: BSD-2-Clause-Patent\r
+//------------------------------------------------------------------------------\r
+\r
+ .text\r
+\r
+//------------------------------------------------------------------------------\r
+// Calls an interrupt using the vector specified by PcdStackCookieExceptionVector\r
+//\r
+// VOID\r
+// TriggerStackCookieInterrupt (\r
+// VOID\r
+// );\r
+//------------------------------------------------------------------------------\r
+.global ASM_PFX(TriggerStackCookieInterrupt)\r
+ASM_PFX(TriggerStackCookieInterrupt):\r
+ swi FixedPcdGet8 (PcdStackCookieExceptionVector)\r
+ bx lr\r
--- /dev/null
+;------------------------------------------------------------------------------\r
+; Arm/StackCookieInterrupt.asm\r
+;\r
+; Copyright (c) Microsoft Corporation.\r
+; SPDX-License-Identifier: BSD-2-Clause-Patent\r
+;------------------------------------------------------------------------------\r
+\r
+ EXPORT TriggerStackCookieInterrupt\r
+\r
+ AREA |.text|, CODE, READONLY\r
+\r
+;------------------------------------------------------------------------------\r
+; Calls an interrupt using the vector specified by PcdStackCookieExceptionVector\r
+;\r
+; VOID\r
+; TriggerStackCookieInterrupt (\r
+; VOID\r
+; );\r
+;------------------------------------------------------------------------------\r
+TriggerStackCookieInterrupt PROC\r
+ SWI FixedPcdGet8 (PcdStackCookieExceptionVector)\r
+ BX LR\r
+TriggerStackCookieInterrupt ENDP\r
+\r
+ END\r
--- /dev/null
+;------------------------------------------------------------------------------\r
+; IA32/CheckCookieMsvc.nasm\r
+;\r
+; Copyright (c) Microsoft Corporation.\r
+; SPDX-License-Identifier: BSD-2-Clause-Patent\r
+;------------------------------------------------------------------------------\r
+\r
+ DEFAULT REL\r
+ SECTION .text\r
+\r
+extern ASM_PFX(StackCheckFailure)\r
+extern ASM_PFX(__security_cookie)\r
+extern ASM_PFX(CpuDeadLoop)\r
+\r
+; Called when a buffer check fails. This functionality is dependent on MSVC\r
+; C runtime libraries and so is unsupported in UEFI.\r
+global ASM_PFX(__report_rangecheckfailure)\r
+ASM_PFX(__report_rangecheckfailure):\r
+ jmp ASM_PFX(CpuDeadLoop)\r
+ ret\r
+\r
+; The GS handler is for checking the stack cookie during SEH or\r
+; EH exceptions and is unsupported in UEFI.\r
+global ASM_PFX(__GSHandlerCheck)\r
+ASM_PFX(__GSHandlerCheck):\r
+ jmp ASM_PFX(CpuDeadLoop)\r
+ ret\r
+\r
+;------------------------------------------------------------------------------\r
+; Checks the stack cookie value against __security_cookie and calls the\r
+; stack cookie failure handler if there is a mismatch.\r
+;\r
+; VOID\r
+; EFIAPI\r
+; __security_check_cookie (\r
+; IN UINTN CheckValue\r
+; );\r
+;------------------------------------------------------------------------------\r
+global @__security_check_cookie@4\r
+@__security_check_cookie@4:\r
+ cmp ecx, [ASM_PFX(__security_cookie)]\r
+ jne ASM_PFX(StackCheckFailure)\r
+ ret\r
--- /dev/null
+;------------------------------------------------------------------------------\r
+; IA32/StackCookieInterrupt.nasm\r
+;\r
+; Copyright (c) Microsoft Corporation.\r
+; SPDX-License-Identifier: BSD-2-Clause-Patent\r
+;------------------------------------------------------------------------------\r
+\r
+ DEFAULT REL\r
+ SECTION .text\r
+\r
+;------------------------------------------------------------------------------\r
+; Checks the stack cookie value against __security_cookie and calls the\r
+; stack cookie failure handler if there is a mismatch.\r
+;\r
+; VOID\r
+; TriggerStackCookieInterrupt (\r
+; VOID\r
+; );\r
+;------------------------------------------------------------------------------\r
+global ASM_PFX(TriggerStackCookieInterrupt)\r
+ASM_PFX(TriggerStackCookieInterrupt):\r
+ int FixedPcdGet8 (PcdStackCookieExceptionVector)\r
+ ret\r
--- /dev/null
+# StackCheckLib\r
+\r
+## Table of Contents\r
+\r
+- [StackCheckLib](#stackchecklib)\r
+ - [Table of Contents](#table-of-contents)\r
+ - [Introduction and Library Instances](#introduction-and-library-instances)\r
+ - [StackCheckLibStaticInit](#stackchecklibstaticinit)\r
+ - [StackCheckLibDynamicInit](#stackchecklibdynamicinit)\r
+ - [StackCheckLibNull](#stackchecklibnull)\r
+ - [How Failures are Handled](#how-failures-are-handled)\r
+ - [Debugging Stack Cookie Check Failures](#debugging-stack-cookie-check-failures)\r
+ - [Usage](#usage)\r
+\r
+## Introduction and Library Instances\r
+\r
+`StackCheckLib` contains the required functionality for initializing the stack cookie\r
+value, checking the value, and triggering an interrupt when a mismatch occurs.\r
+The stack cookie is a random value placed on the stack between the stack variables\r
+and the return address so that continuously writing past the stack variables will\r
+cause the stack cookie to be overwritten. Before the function returns, the stack\r
+cookie value will be checked and if there is a mismatch then `StackCheckLib` handles\r
+the failure.\r
+\r
+Because UEFI doesn't use the C runtime libraries provided by MSVC, the stack\r
+check code is written in assembly within this library. GCC and Clang compilers\r
+have built-in support for stack cookie checking, so this library only handles failures.\r
+\r
+### StackCheckLibStaticInit\r
+\r
+`StackCheckLibStaticInit` is an instance of `StackCheckLib` which does not update the\r
+stack cookie value for the module at runtime. It's always preferable to use\r
+`StackCheckLibDynamicInit` for improved security but there are cases where the stack\r
+cookie global cannot be written to such as in execute-in-place (XIP) modules and during\r
+the Cache-as-RAM (CAR) phase of the boot process. The stack cookie value is initialized\r
+at compile time via updates to the AutoGen process. Each module will define\r
+`STACK_COOKIE_VALUE` which is used for the module stack cookie value.\r
+\r
+### StackCheckLibDynamicInit\r
+\r
+This section is future work. The below is the proposed instance.\r
+\r
+`StackCheckLibDynamicInit` is an instance of `StackCheckLib` which updates the stack\r
+cookie value for the module at runtime. This is the preferred method for stack cookie\r
+initialization as it provides improved security. The stack cookie value is initialized\r
+at runtime by calling `GetRandomNumber32()` or `GetRandomNumber64()` to generate a random\r
+value via the platform's random number generator protocol. If the random number generator\r
+returns an error, then the value will still have the build-time randomized value to fall\r
+back on.\r
+\r
+### StackCheckLibNull\r
+\r
+`StackCheckLibNull` is an instance of `StackCheckLib` which does not perform any stack\r
+cookie checks. This is useful for modules which will fail if stack cookie checks are\r
+inserted. Of course, this is not recommended for production code.\r
+\r
+## How Failures are Handled\r
+\r
+When a stack cookie check fails, the `StackCheckLib` library will first call into a hook\r
+function `StackCheckFailureHook()` which only has a NULL implementation in edk2.\r
+The NULL implementation will simply print the failure address and return, but a platform\r
+can implement their own instance of this library which can perform additional actions\r
+before the system triggers an interrupt.\r
+\r
+After `StackCheckFailureHook()` returns, the library will trigger an interrupt with\r
+PcdStackCookieExceptionVector.\r
+\r
+- On IA32 and X64 platforms, PcdStackCookieExceptionVector is used as an index into the\r
+Interrupt Descriptor Table.\r
+- On ARM platforms, a software interrupt (`SWI`) is called with the value of\r
+PcdStackCookieExceptionVector. The value can be retrieved by the handler by reading\r
+bits [7:0] of the instruction opcode which will allow the handler to determine if the\r
+interrupt was triggered by the stack cookie check. Reference:\r
+[Arm A64 Instruction Set Architecture Version 2024-3](https://developer.arm.com/documentation/ddi0597/2024-03/Base-Instructions/SVC--Supervisor-Call-?lang=en)\r
+- On AARCH64 platforms, a supervisor call (`SVC`) is called with the value\r
+of PcdStackCookieExceptionVector. This value can similarly be retrieved by the\r
+handler to determine if the interrupt was triggered by the stack cookie check. Reference:\r
+[Arm A64 Instruction Set Architecture Version 2024-3](https://developer.arm.com/documentation/ddi0602/2024-03/Base-Instructions/SVC--Supervisor-Call-?lang=en)\r
+\r
+## Debugging Stack Cookie Check Failures\r
+\r
+Tracking down the origin of stack cookie failures can be difficult. Programmers may attempt\r
+printf debugging to determine which function has an overflow only to find that the failure\r
+disappears on the next boot. This curiosity is usually due to the black-box heuristic used\r
+by compilers to determine where to put stack cookie checks or compiler optimization features\r
+removing the failing check. The address where the failed stack cookie check occurred will\r
+be printed using DebugLib. If .map files are available, the address combined with the image\r
+offset can be used to determine the function which failed.\r
+\r
+GNU-based compilers have the `-fstack-protector-all` flag to force stack cookie checks on\r
+all functions which could create a more consistent environment for debugging assuming an\r
+earlier failure doesn't mask the targeted one and the flash space can accommodate the\r
+increased size.\r
+\r
+The Visual Studio (MSVC) toolchain has the ability to generate `.cod` files during compilation\r
+which interleave C and the generated assembly code. These files will contain the stack cookie\r
+checks and are useful for determining where the checks are placed. To generate these files,\r
+append `/FAcs` to the build options for each target module. The easiest way to do this is to\r
+update the tools_def file so the `<TARGET>_<TOOLCHAIN>_<ARCH>_CC_FLAGS` includes `/FAcs`.\r
+\r
+## Usage\r
+\r
+edk2 updated the tools_def to add `/GS` to VS2022 and VS2019 IA32/X64 builds and\r
+`-fstack-protector` to GCC builds. This will cause stack cookie references to be inserted\r
+throughout the code. Every module should have a `StackCheckLib` instances linked to satisfy\r
+these references. So every module doesn't need to add `StackCheckLib` to the LibraryClasses\r
+section of the INF file, `StackCheckLib` instances should be linked as NULL in the platform\r
+DSC fies. The only exception to this is host-based unit tests as they will be compiled with\r
+the runtime libraries which already contain the stack cookie definitions and will collide\r
+with `StackCheckLib`.\r
+\r
+SEC and PEI_CORE modules should always use `StackCheckLibNull` and pre-memory modules\r
+should use `StackCheckLibStaticInit`. All other modules should use `StackCheckLibDynamicInit`.\r
+Below is an **example** of how to link the `StackCheckLib` instances in the platform DSC file\r
+but it may need customization based on the platform's requirements:\r
+\r
+```text\r
+[LibraryClasses.common.SEC, LibraryClasses.common.PEI_CORE]\r
+ NULL|MdePkg/Library/StackCheckLibNull/StackCheckLibNull.inf\r
+\r
+[LibraryClasses.common.PEIM]\r
+ NULL|MdePkg/Library/StackCheckLib/StackCheckLibStaticInit.inf\r
+\r
+[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]\r
+ NULL|MdePkg/Library/StackCheckLib/StackCheckLibDynamicInit.inf\r
+```\r
--- /dev/null
+/** @file\r
+ Provides the required functionality for handling stack\r
+ cookie check failures in GCC.\r
+\r
+ Copyright (c) Microsoft Corporation.\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
+**/\r
+\r
+#include <Base.h>\r
+\r
+#include <Library/DebugLib.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/StackCheckFailureHookLib.h>\r
+\r
+/**\r
+ Triggers an interrupt using the vector specified by PcdStackCookieExceptionVector\r
+**/\r
+VOID\r
+TriggerStackCookieInterrupt (\r
+ VOID\r
+ );\r
+\r
+VOID *__stack_chk_guard = (VOID *)(UINTN)STACK_COOKIE_VALUE;\r
+\r
+/**\r
+ This function gets called when a gcc/clang generated stack cookie fails. This implementation calls into a platform\r
+ failure hook lib and then triggers the stack cookie interrupt.\r
+\r
+**/\r
+VOID\r
+__stack_chk_fail (\r
+ VOID\r
+ )\r
+{\r
+ DEBUG ((DEBUG_ERROR, "Stack cookie check failed at address 0x%llx!\n", RETURN_ADDRESS (0)));\r
+ StackCheckFailureHook (RETURN_ADDRESS (0));\r
+ TriggerStackCookieInterrupt ();\r
+}\r
--- /dev/null
+/** @file\r
+ Provides the required functionality for handling stack\r
+ cookie check failures for MSVC.\r
+\r
+ Copyright (c) Microsoft Corporation.\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
+**/\r
+\r
+#include <Base.h>\r
+\r
+#include <Library/DebugLib.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/StackCheckFailureHookLib.h>\r
+\r
+/**\r
+ Triggers an interrupt using the vector specified by PcdStackCookieExceptionVector\r
+**/\r
+VOID\r
+TriggerStackCookieInterrupt (\r
+ VOID\r
+ );\r
+\r
+VOID *__security_cookie = (VOID *)(UINTN)STACK_COOKIE_VALUE;\r
+\r
+/**\r
+ This function gets called when an MSVC generated stack cookie fails. This implementation calls into a platform\r
+ failure hook lib and then triggers the stack cookie interrupt.\r
+\r
+ @param[in] ActualCookieValue The value that was written onto the stack, corrupting the stack cookie.\r
+\r
+**/\r
+VOID\r
+StackCheckFailure (\r
+ VOID *ActualCookieValue\r
+ )\r
+{\r
+ DEBUG ((DEBUG_ERROR, "Stack cookie check failed at address 0x%llx!\n", RETURN_ADDRESS (0)));\r
+ StackCheckFailureHook (RETURN_ADDRESS (0));\r
+ TriggerStackCookieInterrupt ();\r
+}\r
--- /dev/null
+## @file\r
+# Provides the required functionality for checking the stack cookie.\r
+#\r
+# Copyright (c) Microsoft Corporation.\r
+# SPDX-License-Identifier: BSD-2-Clause-Patent\r
+##\r
+\r
+[Defines]\r
+ INF_VERSION = 1.29\r
+ BASE_NAME = StackCheckLibStaticInit\r
+ FILE_GUID = 2b24dc50-e33d-4c9f-8b62-e826f06e483f\r
+ MODULE_TYPE = BASE\r
+ VERSION_STRING = 1.0\r
+ LIBRARY_CLASS = NULL\r
+\r
+[Sources]\r
+ StackCheckLibCommonMsvc.c | MSFT\r
+ StackCheckLibCommonGcc.c | GCC\r
+\r
+[Sources.IA32]\r
+ IA32/CheckCookieMsvc.nasm | MSFT\r
+\r
+[Sources.X64]\r
+ X64/CheckCookieMsvc.nasm | MSFT\r
+\r
+[Sources.IA32, Sources.X64]\r
+ IA32/StackCookieInterrupt.nasm\r
+\r
+[Sources.ARM]\r
+ Arm/StackCookieInterrupt.S |GCC\r
+ Arm/StackCookieInterrupt.asm |MSFT\r
+\r
+[Sources.AARCH64]\r
+ AArch64/StackCookieInterrupt.S |GCC\r
+ AArch64/StackCookieInterrupt.asm |MSFT\r
+\r
+[Packages]\r
+ MdePkg/MdePkg.dec\r
+\r
+[LibraryClasses]\r
+ StackCheckFailureHookLib\r
+ BaseLib\r
+ DebugLib\r
+\r
+[FixedPcd]\r
+ gEfiMdePkgTokenSpaceGuid.PcdStackCookieExceptionVector\r
+\r
+[BuildOptions]\r
+ # We cannot build the MSVC version with /GL (whole program optimization) because we run into linker error\r
+ # LNK1237, which is a failure to link against a symbol from a library compiled with /GL. The whole program\r
+ # optimization tries to do away with references to this symbol. The solution is to not compile the stack\r
+ # check libs with /GL\r
+ MSFT:*_*_*_CC_FLAGS = /GL-\r
+\r
+ # We cannot build the GCC version with LTO (link time optimization) because we run into linker errors where\r
+ # the stack cookie variable has been optimized away, as it looks to GCC like the variable is not used, because\r
+ # the compiler inserts the usage.\r
+ GCC:*_*_*_CC_FLAGS = -fno-lto\r
--- /dev/null
+;------------------------------------------------------------------------------\r
+; X64/CheckCookieMsvc.nasm\r
+;\r
+; Copyright (c) Microsoft Corporation.\r
+; SPDX-License-Identifier: BSD-2-Clause-Patent\r
+;------------------------------------------------------------------------------\r
+\r
+ DEFAULT REL\r
+ SECTION .text\r
+\r
+extern ASM_PFX(StackCheckFailure)\r
+extern ASM_PFX(__security_cookie)\r
+extern ASM_PFX(CpuDeadLoop)\r
+\r
+; Called when a buffer check fails. This functionality is dependent on MSVC\r
+; C runtime libraries and so is unsupported in UEFI.\r
+global ASM_PFX(__report_rangecheckfailure)\r
+ASM_PFX(__report_rangecheckfailure):\r
+ jmp ASM_PFX(CpuDeadLoop)\r
+ ret\r
+\r
+; The GS handler is for checking the stack cookie during SEH or\r
+; EH exceptions and is unsupported in UEFI.\r
+global ASM_PFX(__GSHandlerCheck)\r
+ASM_PFX(__GSHandlerCheck):\r
+ jmp ASM_PFX(CpuDeadLoop)\r
+ ret\r
+\r
+;------------------------------------------------------------------------------\r
+; Checks the stack cookie value against __security_cookie and calls the\r
+; stack cookie failure handler if there is a mismatch.\r
+;\r
+; VOID\r
+; EFIAPI\r
+; __security_check_cookie (\r
+; IN UINTN CheckValue\r
+; );\r
+;------------------------------------------------------------------------------\r
+global ASM_PFX(__security_check_cookie)\r
+ASM_PFX(__security_check_cookie):\r
+ cmp rcx, [ASM_PFX(__security_cookie)]\r
+ jne ASM_PFX(StackCheckFailure)\r
+ ret\r
\r
MdePkg/Library/StackCheckFailureHookLibNull/StackCheckFailureHookLibNull.inf\r
MdePkg/Library/StackCheckLibNull/StackCheckLibNull.inf\r
+ MdePkg/Library/StackCheckLib/StackCheckLibStaticInit.inf\r
\r
[Components.IA32, Components.X64, Components.ARM, Components.AARCH64]\r
#\r