Index: docs/SafeStack.rst =================================================================== --- docs/SafeStack.rst +++ docs/SafeStack.rst @@ -78,6 +78,49 @@ address and the instrumentation ensures that no pointers to the safe stack are ever stored outside of the safe stack itself (see limitations below). +SafeStack can be combined with the ``separate-stack-seg`` feature (using the +``-mseparate-stack-seg`` command line option) for x86-32. Each x86 memory +operand has an effective segment. The ``separate-stack-seg`` feature emits +segment override prefixes as necessary to direct safe stack accesses to the SS +segment and ordinary data accesses to the DS and ES segments. That eliminates +one obstacle preventing the limits of the DS and ES segments from being set +below the start of the safe stacks. However, additional runtime support is +needed to actually perform that segment configuration. Furthermore, all code in +the program, including library routines, that may be run with such a segment +configuration must be compiled to support it. This is a more extensive level of +runtime support than is supplied by the compiler-rt library. Thus, the +compiler-rt library is not automatically linked when the ``separate-stack-seg`` +feature is enabled. + +The ``separate-stack-seg`` feature only performs intra-procedural analysis. It +assumes that only the stack register points to the safe stack at function +entry. It assumes that no pointers passed into the function or stored as global +variables point to the safe stack. SafeStack helps to satisfy this assumption +when the ``separate-stack-seg`` feature is enabled by moving additional types of +allocations to the unsafe stack if pointers to them may be passed to +subroutines. Note that variables can be annotated as pointing to address space +258 independent of the ``separate-stack-seg`` feature, and the compiler will +generate code to access the referenced data in the SS segment. + +Special handling is needed for variadic argument lists when the +``separate-stack-seg`` feature is enabled. Certain variadic argument intrinsics +(e.g. ``va_start`` and ``va_arg``) may store the addresses of variadic arguments +to memory. Variadic arguments are passed on the safe stack. Ordinarily, the +``separate-stack-seg`` feature attempts to block most pointers to the safe stack +from being stored, unless it is able to track them as register spills. The +``separate-stack-seg`` feature does not support tracking other types of stores +of safe stack pointers and pairing them with subsequent loads (i.e. register +fills) so that it can emit the necessary segment override prefixes for safe +stack accesses. However, the ``separate-stack-seg`` feature attempts to identify +and permit instructions that store safe stack pointers to support variadic +arguments. Its heuristics are only capable of identifying simple usages of the +variadic argument intrinsics. More complex usages may result in assertion +failures. The relevant assertion can be bypassed just for functions with a +``va_start`` by passing an argument to LLVM: ``-mllvm +-sep-stk-seg-sp-store-verif=ignore-va``. That assertion can be bypassed for all +functions by passing ``-mllvm -sep-stk-seg-sp-store-verif=none``. However, +passing either of these arguments may lead to incorrect code being generated. + Known security limitations ~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -109,7 +152,8 @@ 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). +CPUs). The ``separate-stack-seg`` feature can be used with appropriate runtime +support to enable hardware segmentation on x86-32. At the moment, SafeStack assumes that the compiler's implementation is correct. This has not been verified except through manual code inspection, and could @@ -123,6 +167,32 @@ To enable SafeStack, just pass ``-fsanitize=safe-stack`` flag to both compile and link command lines. +To store the unsafe stack pointer in an ordinary global variable instead of a +thread-local variable, add the ``-mllvm -safe-stack-usp-storage=single-thread`` +flag. This is only suitable for single-threaded programs and is incompatible +with the compiler-rt library. It was originally intended for certain embedded +systems. A linked object or library must define and initialize +``__safestack_unsafe_stack_ptr`` with type ``void*`` as well as associated +storage for the unsafe stack. + +A single-threaded unsafe stack pointer can also be useful during program +initialization in the dynamic linker and C library startup routines, before +thread-local storage is available. Some functions may need to be invoked both +during this stage and later after the program has switched to using thread-local +unsafe stack pointers. The ``-mllvm -safe-stack-usp-init`` flag adds support +both of these modes, assuming that appropriate runtime support is available. +Each such function that accesses the unsafe stack pointer first attempts to use +the single-threaded ``__safestack_unsafe_stack_ptr_init`` with type ``void*`` if +it is not null. If that variable is null, the function falls back to using +``__safestack_unsafe_stack_ptr`` wherever that is configured to be stored. + +It can be more efficient to store the unsafe stack pointer in the Thread Control +Block (TCB) rather than ordinary thread-local storage. The +``-mllvm -safe-stack-usp-storage=tcb`` flag selects this type of storage. The +``-mllvm -safe-stack-usp-tcb-offset=`` flag must also be used to specify +the byte offset within the TCB where the unsafe stack pointer should be stored. +This requires runtime support. + Supported Platforms -------------------