Tracking issue: https://github.com/llvm/llvm-project/issues/201242 Migration guide docs: https://llvm.org/docs/SphinxQuickstartTemplate.html#markdown-migration-guidelines RFC: https://discourse.llvm.org/t/rfc-make-myst-markdown-the-llvm-docs-format-rip-rest/90840 This change was produced with rst2myst plus LLM cleanups. I manually paged through all of the linked HTML documents looking for visual artifacts, and I fixed everything I found. To reviewers: Please spot check the generated HTML below, and spot check the diff to look for artifacts. This change is too large to review everything line-by-line, but if you check 10 pages of documentation, and only find one migration bug, I hope you think that this is good enough to land. We have existing reST bugs that this fixes (mostly italic blocks that should be code font spans). ----- Links to the updated HTML for validation: | Source file | Before HTML | After HTML | |---|---|---| | `clang/docs/UsersManual.md` | [before](https://clang.llvm.org/docs/UsersManual.html) | [after](https://llvmdocs.staging.reidkleckner.dev/clang/docs/UsersManual.html) | | `clang/docs/SanitizerStats.md` | [before](https://clang.llvm.org/docs/SanitizerStats.html) | [after](https://llvmdocs.staging.reidkleckner.dev/clang/docs/SanitizerStats.html) | | `clang/docs/SanitizerSpecialCaseList.md` | [before](https://clang.llvm.org/docs/SanitizerSpecialCaseList.html) | [after](https://llvmdocs.staging.reidkleckner.dev/clang/docs/SanitizerSpecialCaseList.html) | | `clang/docs/OverflowBehaviorTypes.md` | [before](https://clang.llvm.org/docs/OverflowBehaviorTypes.html) | [after](https://llvmdocs.staging.reidkleckner.dev/clang/docs/OverflowBehaviorTypes.html) | | `clang/docs/LTOVisibility.md` | [before](https://clang.llvm.org/docs/LTOVisibility.html) | [after](https://llvmdocs.staging.reidkleckner.dev/clang/docs/LTOVisibility.html) | | `clang/docs/PointerAuthentication.md` | [before](https://clang.llvm.org/docs/PointerAuthentication.html) | [after](https://llvmdocs.staging.reidkleckner.dev/clang/docs/PointerAuthentication.html) | | `clang/docs/SafeStack.md` | [before](https://clang.llvm.org/docs/SafeStack.html) | [after](https://llvmdocs.staging.reidkleckner.dev/clang/docs/SafeStack.html) | | `clang/docs/ShadowCallStack.md` | [before](https://clang.llvm.org/docs/ShadowCallStack.html) | [after](https://llvmdocs.staging.reidkleckner.dev/clang/docs/ShadowCallStack.html) | | `clang/docs/StructureProtection.md` | [before](https://clang.llvm.org/docs/StructureProtection.html) | [after](https://llvmdocs.staging.reidkleckner.dev/clang/docs/StructureProtection.html) | | `clang/docs/SourceBasedCodeCoverage.md` | [before](https://clang.llvm.org/docs/SourceBasedCodeCoverage.html) | [after](https://llvmdocs.staging.reidkleckner.dev/clang/docs/SourceBasedCodeCoverage.html) | | `clang/docs/StandardCPlusPlusModules.md` | [before](https://clang.llvm.org/docs/StandardCPlusPlusModules.html) | [after](https://llvmdocs.staging.reidkleckner.dev/clang/docs/StandardCPlusPlusModules.html) | | `clang/docs/Modules.md` | [before](https://clang.llvm.org/docs/Modules.html) | [after](https://llvmdocs.staging.reidkleckner.dev/clang/docs/Modules.html) | | `clang/docs/MSVCCompatibility.md` | [before](https://clang.llvm.org/docs/MSVCCompatibility.html) | [after](https://llvmdocs.staging.reidkleckner.dev/clang/docs/MSVCCompatibility.html) | | `clang/docs/MisExpect.md` | [before](https://clang.llvm.org/docs/MisExpect.html) | [after](https://llvmdocs.staging.reidkleckner.dev/clang/docs/MisExpect.html) | | `clang/docs/OpenCLSupport.md` | [before](https://clang.llvm.org/docs/OpenCLSupport.html) | [after](https://llvmdocs.staging.reidkleckner.dev/clang/docs/OpenCLSupport.html) | | `clang/docs/OpenMPSupport.md` | [before](https://clang.llvm.org/docs/OpenMPSupport.html) | [after](https://llvmdocs.staging.reidkleckner.dev/clang/docs/OpenMPSupport.html) | | `clang/docs/SYCLSupport.md` | [before](https://clang.llvm.org/docs/SYCLSupport.html) | [after](https://llvmdocs.staging.reidkleckner.dev/clang/docs/SYCLSupport.html) | | `clang/docs/HIPSupport.md` | [before](https://clang.llvm.org/docs/HIPSupport.html) | [after](https://llvmdocs.staging.reidkleckner.dev/clang/docs/HIPSupport.html) | | `clang/docs/HLSL/HLSLDocs.md` | [before](https://clang.llvm.org/docs/HLSL/HLSLDocs.html) | [after](https://llvmdocs.staging.reidkleckner.dev/clang/docs/HLSL/HLSLDocs.html) | | `clang/docs/ThinLTO.md` | [before](https://clang.llvm.org/docs/ThinLTO.html) | [after](https://llvmdocs.staging.reidkleckner.dev/clang/docs/ThinLTO.html) | --------- Co-authored-by: Chris B <chris.bieneman@me.com>
9 KiB
SafeStack
:local:
Introduction
SafeStack is an instrumentation pass that protects programs against attacks based on stack buffer overflows, without introducing any measurable performance overhead. It works by separating the program stack into two distinct regions: the safe stack and the unsafe stack. The safe stack stores return addresses, register spills, and local variables that are always accessed in a safe way, while the unsafe stack stores everything else. This separation ensures that buffer overflows on the unsafe stack cannot be used to overwrite anything on the safe stack.
SafeStack is a part of the Code-Pointer Integrity (CPI) Project.
Performance
The performance overhead of the SafeStack instrumentation is less than 0.1% on average across a variety of benchmarks (see the Code-Pointer Integrity paper for details). This is mainly because most small functions do not have any variables that require the unsafe stack and, hence, do not need unsafe stack frames to be created. The cost of creating unsafe stack frames for large functions is amortized by the cost of executing the function.
In some cases, SafeStack actually improves the performance. Objects that end up being moved to the unsafe stack are usually large arrays or variables that are used through multiple stack frames. Moving such objects away from the safe stack increases the locality of frequently accessed values on the stack, such as register spills, return addresses, and small local variables.
Compatibility
Most programs, static libraries, or individual files can be compiled with SafeStack as is. SafeStack requires basic runtime support, which, on most platforms, is implemented as a compiler-rt library that is automatically linked in when the program is compiled with SafeStack.
Linking a DSO with SafeStack is not currently supported.
Known compatibility limitations
Certain code that relies on low-level stack manipulations requires adaption to work with SafeStack. One example is mark-and-sweep garbage collection implementations for C/C++ (e.g., Oilpan in chromium/blink), which must be changed to look for the live pointers on both safe and unsafe stacks.
SafeStack supports linking statically modules that are compiled with and without SafeStack. An executable compiled with SafeStack can load dynamic libraries that are not compiled with SafeStack. At the moment, compiling dynamic libraries with SafeStack is not supported.
Signal handlers that use sigaltstack() must not use the unsafe stack (see
__attribute__((no_sanitize("safe-stack"))) below).
Programs that use APIs from ucontext.h are not supported yet.
Security
SafeStack protects return addresses, spilled registers and local variables that are always accessed in a safe way by separating them in a dedicated safe stack region. The safe stack is automatically protected against stack-based buffer overflows, since it is disjoint from the unsafe stack in memory, and it itself is always accessed in a safe way. In the current implementation, the safe stack is protected against arbitrary memory write vulnerabilities through randomization and information hiding: the safe stack is allocated at a random address and the instrumentation ensures that no pointers to the safe stack are ever stored outside of the safe stack itself (see limitations below).
Known security limitations
A complete protection against control-flow hijack attacks requires combining
SafeStack with another mechanism that enforces the integrity of code pointers
that are stored on the heap or the unsafe stack, such as CPI, or a forward-edge control flow integrity
mechanism that enforces correct calling conventions at indirect call sites,
such as IFCC with arity
checks. Clang has control-flow integrity protection scheme for {doc}C++ virtual calls <ControlFlowIntegrity>, but not non-virtual indirect calls. With
SafeStack alone, an attacker can overwrite a function pointer on the heap or
the unsafe stack and cause a program to call arbitrary location, which in turn
might enable stack pivoting and return-oriented programming.
In its current implementation, SafeStack provides precise protection against
stack-based buffer overflows, but protection against arbitrary memory write
vulnerabilities is probabilistic and relies on randomization and information
hiding. The randomization is currently based on system-enforced ASLR and shares
its known security limitations. The safe stack pointer hiding is not perfect
yet either: system library functions such as swapcontext, exception
handling mechanisms, intrinsics such as __builtin_frame_address, or
low-level bugs in runtime support could leak the safe stack pointer. In the
future, such leaks could be detected by static or dynamic analysis tools and
prevented by adjusting such functions to either encrypt the stack pointer when
storing it in the heap (as already done e.g., by setjmp/longjmp
implementation in glibc), or store it in a safe region instead.
The CPI paper describes two alternative, stronger safe stack protection mechanisms, that rely on software fault isolation, or hardware segmentation (as available on x86-32 and some x86-64 CPUs).
At the moment, SafeStack assumes that the compiler's implementation is correct. This has not been verified except through manual code inspection, and could always regress in the future. It's therefore desirable to have a separate static or dynamic binary verification tool that would check the correctness of the SafeStack instrumentation in final binaries.
Usage
To enable SafeStack, just pass -fsanitize=safe-stack flag to both compile
and link command lines.
Supported Platforms
SafeStack was tested on Linux, NetBSD, FreeBSD and macOS.
Low-level API
__has_feature(safe_stack)
In some rare cases one may need to execute different code depending on
whether SafeStack is enabled. The macro __has_feature(safe_stack) can
be used for this purpose.
#if __has_feature(safe_stack)
// code that builds only under SafeStack
#endif
__attribute__((no_sanitize("safe-stack")))
Use __attribute__((no_sanitize("safe-stack"))) on a function declaration
to specify that the safe stack instrumentation should not be applied to that
function, even if enabled globally (see -fsanitize=safe-stack flag). This
attribute may be required for functions that make assumptions about the
exact layout of their stack frames.
All local variables in functions with this attribute will be stored on the safe stack. The safe stack remains unprotected against memory errors when accessing these variables, so extra care must be taken to manually ensure that all such accesses are safe. Furthermore, the addresses of such local variables should never be stored on the heap, as it would leak the location of the SafeStack.
sanitizer/safestack_interface.h
To use the low-level API, include the header <sanitizer/safestack_interface.h>.
__safestack_get_unsafe_stack_ptr()
This function returns current unsafe stack pointer of the current thread.
__safestack_get_unsafe_stack_bottom()
This function returns a pointer to the bottom of the unsafe stack of the current thread.
__safestack_get_unsafe_stack_top()
This function returns a pointer to the top of the unsafe stack of the current thread.
Deprecated Builtins
The following builtins are still supported but are deprecated and will emit a
warning. Use the corresponding functions from <sanitizer/safestack_interface.h>
instead.
__builtin___get_unsafe_stack_ptr()
Deprecated alias for __safestack_get_unsafe_stack_ptr().
__builtin___get_unsafe_stack_bottom()
Deprecated alias for __safestack_get_unsafe_stack_bottom().
__builtin___get_unsafe_stack_top()
Deprecated alias for __safestack_get_unsafe_stack_top().
__builtin___get_unsafe_stack_start()
Deprecated alias for __safestack_get_unsafe_stack_bottom().
Design
Please refer to the Code-Pointer Integrity project page for more information about the design of the SafeStack and its related technologies.
setjmp and exception handling
The OSDI'14 paper mentions that
on Linux the instrumentation pass finds calls to setjmp or functions that
may throw an exception, and inserts required instrumentation at their call
sites. Specifically, the instrumentation pass saves the shadow stack pointer
on the safe stack before the call site, and restores it either after the
call to setjmp or after an exception has been caught. This is implemented
in the function SafeStack::createStackRestorePoints.
Publications
Code-Pointer Integrity. Volodymyr Kuznetsov, Laszlo Szekeres, Mathias Payer, George Candea, R. Sekar, Dawn Song. USENIX Symposium on Operating Systems Design and Implementation (OSDI), Broomfield, CO, October 2014