211 lines · plain
1=========2SafeStack3=========4 5.. contents::6 :local:7 8Introduction9============10 11SafeStack is an instrumentation pass that protects programs against attacks12based on stack buffer overflows, without introducing any measurable performance13overhead. It works by separating the program stack into two distinct regions:14the safe stack and the unsafe stack. The safe stack stores return addresses,15register spills, and local variables that are always accessed in a safe way,16while the unsafe stack stores everything else. This separation ensures that17buffer overflows on the unsafe stack cannot be used to overwrite anything18on the safe stack.19 20SafeStack is a part of the `Code-Pointer Integrity (CPI) Project21<https://dslab.epfl.ch/research/cpi/>`_.22 23Performance24-----------25 26The performance overhead of the SafeStack instrumentation is less than 0.1% on27average across a variety of benchmarks (see the `Code-Pointer Integrity28<https://dslab.epfl.ch/pubs/cpi.pdf>`__ paper for details). This is mainly29because most small functions do not have any variables that require the unsafe30stack and, hence, do not need unsafe stack frames to be created. The cost of31creating unsafe stack frames for large functions is amortized by the cost of32executing the function.33 34In some cases, SafeStack actually improves the performance. Objects that end up35being moved to the unsafe stack are usually large arrays or variables that are36used through multiple stack frames. Moving such objects away from the safe37stack increases the locality of frequently accessed values on the stack, such38as register spills, return addresses, and small local variables.39 40Compatibility41-------------42 43Most programs, static libraries, or individual files can be compiled44with SafeStack as is. SafeStack requires basic runtime support, which, on most45platforms, is implemented as a compiler-rt library that is automatically linked46in when the program is compiled with SafeStack.47 48Linking a DSO with SafeStack is not currently supported.49 50Known compatibility limitations51~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~52 53Certain code that relies on low-level stack manipulations requires adaption to54work with SafeStack. One example is mark-and-sweep garbage collection55implementations for C/C++ (e.g., Oilpan in chromium/blink), which must be56changed to look for the live pointers on both safe and unsafe stacks.57 58SafeStack supports linking statically modules that are compiled with and59without SafeStack. An executable compiled with SafeStack can load dynamic60libraries that are not compiled with SafeStack. At the moment, compiling61dynamic libraries with SafeStack is not supported.62 63Signal handlers that use ``sigaltstack()`` must not use the unsafe stack (see64``__attribute__((no_sanitize("safe-stack")))`` below).65 66Programs that use APIs from ``ucontext.h`` are not supported yet.67 68Security69--------70 71SafeStack protects return addresses, spilled registers and local variables that72are always accessed in a safe way by separating them in a dedicated safe stack73region. The safe stack is automatically protected against stack-based buffer74overflows, since it is disjoint from the unsafe stack in memory, and it itself75is always accessed in a safe way. In the current implementation, the safe stack76is protected against arbitrary memory write vulnerabilities through77randomization and information hiding: the safe stack is allocated at a random78address and the instrumentation ensures that no pointers to the safe stack are79ever stored outside of the safe stack itself (see limitations below).80 81Known security limitations82~~~~~~~~~~~~~~~~~~~~~~~~~~83 84A complete protection against control-flow hijack attacks requires combining85SafeStack with another mechanism that enforces the integrity of code pointers86that are stored on the heap or the unsafe stack, such as `CPI87<https://dslab.epfl.ch/research/cpi/>`_, or a forward-edge control flow integrity88mechanism that enforces correct calling conventions at indirect call sites,89such as `IFCC <https://research.google.com/pubs/archive/42808.pdf>`_ with arity90checks. Clang has control-flow integrity protection scheme for :doc:`C++ virtual91calls <ControlFlowIntegrity>`, but not non-virtual indirect calls. With92SafeStack alone, an attacker can overwrite a function pointer on the heap or93the unsafe stack and cause a program to call arbitrary location, which in turn94might enable stack pivoting and return-oriented programming.95 96In its current implementation, SafeStack provides precise protection against97stack-based buffer overflows, but protection against arbitrary memory write98vulnerabilities is probabilistic and relies on randomization and information99hiding. The randomization is currently based on system-enforced ASLR and shares100its known security limitations. The safe stack pointer hiding is not perfect101yet either: system library functions such as ``swapcontext``, exception102handling mechanisms, intrinsics such as ``__builtin_frame_address``, or103low-level bugs in runtime support could leak the safe stack pointer. In the104future, such leaks could be detected by static or dynamic analysis tools and105prevented by adjusting such functions to either encrypt the stack pointer when106storing it in the heap (as already done e.g., by ``setjmp``/``longjmp``107implementation in glibc), or store it in a safe region instead.108 109The `CPI paper <https://dslab.epfl.ch/pubs/cpi.pdf>`_ describes two alternative,110stronger safe stack protection mechanisms, that rely on software fault111isolation, or hardware segmentation (as available on x86-32 and some x86-64112CPUs).113 114At the moment, SafeStack assumes that the compiler's implementation is correct.115This has not been verified except through manual code inspection, and could116always regress in the future. It's therefore desirable to have a separate117static or dynamic binary verification tool that would check the correctness of118the SafeStack instrumentation in final binaries.119 120Usage121=====122 123To enable SafeStack, just pass ``-fsanitize=safe-stack`` flag to both compile124and link command lines.125 126Supported Platforms127-------------------128 129SafeStack was tested on Linux, NetBSD, FreeBSD and macOS.130 131Low-level API132-------------133 134``__has_feature(safe_stack)``135~~~~~~~~~~~~~~~~~~~~~~~~~~~~~136 137In some rare cases one may need to execute different code depending on138whether SafeStack is enabled. The macro ``__has_feature(safe_stack)`` can139be used for this purpose.140 141.. code-block:: c142 143 #if __has_feature(safe_stack)144 // code that builds only under SafeStack145 #endif146 147``__attribute__((no_sanitize("safe-stack")))``148~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~149 150Use ``__attribute__((no_sanitize("safe-stack")))`` on a function declaration151to specify that the safe stack instrumentation should not be applied to that152function, even if enabled globally (see ``-fsanitize=safe-stack`` flag). This153attribute may be required for functions that make assumptions about the154exact layout of their stack frames.155 156All local variables in functions with this attribute will be stored on the safe157stack. The safe stack remains unprotected against memory errors when accessing158these variables, so extra care must be taken to manually ensure that all such159accesses are safe. Furthermore, the addresses of such local variables should160never be stored on the heap, as it would leak the location of the SafeStack.161 162``__builtin___get_unsafe_stack_ptr()``163~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~164 165This builtin function returns current unsafe stack pointer of the current166thread.167 168``__builtin___get_unsafe_stack_bottom()``169~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~170 171This builtin function returns a pointer to the bottom of the unsafe stack of the172current thread.173 174``__builtin___get_unsafe_stack_top()``175~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~176 177This builtin function returns a pointer to the top of the unsafe stack of the178current thread.179 180``__builtin___get_unsafe_stack_start()``181~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~182 183Deprecated: This builtin function is an alias for184``__builtin___get_unsafe_stack_bottom()``.185 186Design187======188 189Please refer to the `Code-Pointer Integrity <https://dslab.epfl.ch/research/cpi/>`__190project page for more information about the design of the SafeStack and its191related technologies.192 193setjmp and exception handling194-----------------------------195 196The `OSDI'14 paper <https://dslab.epfl.ch/pubs/cpi.pdf>`_ mentions that197on Linux the instrumentation pass finds calls to setjmp or functions that198may throw an exception, and inserts required instrumentation at their call199sites. Specifically, the instrumentation pass saves the shadow stack pointer200on the safe stack before the call site, and restores it either after the201call to setjmp or after an exception has been caught. This is implemented202in the function ``SafeStack::createStackRestorePoints``.203 204Publications205------------206 207`Code-Pointer Integrity <https://dslab.epfl.ch/pubs/cpi.pdf>`__.208Volodymyr Kuznetsov, Laszlo Szekeres, Mathias Payer, George Candea, R. Sekar, Dawn Song.209USENIX Symposium on Operating Systems Design and Implementation210(`OSDI <https://www.usenix.org/conference/osdi14>`_), Broomfield, CO, October 2014211