aboutsummaryrefslogtreecommitdiff
path: root/MdePkg/Library/StackCheckLib/Readme.md
diff options
context:
space:
mode:
Diffstat (limited to 'MdePkg/Library/StackCheckLib/Readme.md')
-rw-r--r--MdePkg/Library/StackCheckLib/Readme.md197
1 files changed, 124 insertions, 73 deletions
diff --git a/MdePkg/Library/StackCheckLib/Readme.md b/MdePkg/Library/StackCheckLib/Readme.md
index 6558c222cd24..2d3d34a8ef06 100644
--- a/MdePkg/Library/StackCheckLib/Readme.md
+++ b/MdePkg/Library/StackCheckLib/Readme.md
@@ -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
-
-`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.
-
-### StackCheckLibDynamicInit
-
-This section is future work. The below is the proposed instance.
-
-`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.
+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.
+
+### StackCheckLib
+
+`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.
+
+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,75 @@ 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:
+### Custom Stack Check Library Configuration
+
+In order to use a different instance of StackCheckLib than `MdeLibs.dsc.inc` provides, a DSC
+should add one of the following:
+
+#### Static Stack Check Cookie Configuration
```inf
-[LibraryClasses.common.SEC, LibraryClasses.common.USER_DEFINED]
- NULL|MdePkg/Library/StackCheckLibNull/StackCheckLibNull.inf
+[Defines]
+ DEFINE CUSTOM_STACK_CHECK_LIB = STATIC
```
-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.
+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.
+
+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
-UefiCpuPkg/SecCore/SecCore.inf {
- <LibraryClasses>
- NULL|MdePkg/Library/StackCheckLibNull/StackCheckLibNull.inf
- }
+[LibraryClasses.common.SEC, LibraryClasses.common.PEI_CORE]
+ StackCheckLib|MdePkg/Library/StackCheckLib/StackCheckLib.inf
```
-### Custom Stack Check Library Configuration
+It is recommended that a platform only do this for debugging or if they have implemented
+exception handlers for these phases.
-In order to use a different instance of StackCheckLib than `MdeLibs.dsc.inc` provides, a DSC
-should add the following:
+#### Dynamic Stack Cookie Configuration
```inf
[Defines]
- DEFINE CUSTOM_STACK_CHECK_LIB = TRUE
+ DEFINE CUSTOM_STACK_CHECK_LIB = DYNAMIC
```
-This will cause `MdeLibs.dsc.inc` to not link `StackCheckLibNull` and rely on a DSC to
-link whichever version(s) of `StackCheckLib` it desires.
-
-It is recommended that SEC and PEI_CORE modules use `StackCheckLibNull` and pre-memory modules
-should use `StackCheckLibStaticInit`. All other modules should use `StackCheckLibDynamicInit`.
+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`.
-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 can enable static
+stack cookie checking, as documented in the previous section. Due to the fact
+that writable global variables are not supported in the `SEC` or `PEI` phases
+of execution, dynamic stack cookie checking is not supported here.
-```inf
-[LibraryClasses.common.SEC, LibraryClasses.common.PEI_CORE]
- NULL|MdePkg/Library/StackCheckLibNull/StackCheckLibNull.inf
+It is recommended that a platform only do this for debugging or if they have implemented
+exception handlers for these phases.
-[LibraryClasses.common.PEIM]
- NULL|MdePkg/Library/StackCheckLib/StackCheckLibStaticInit.inf
+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.:
-[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
+```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 +232,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.