199 lines
		
	
	
		
			8.5 KiB
		
	
	
	
		
			ReStructuredText
		
	
	
	
			
		
		
	
	
			199 lines
		
	
	
		
			8.5 KiB
		
	
	
	
		
			ReStructuredText
		
	
	
	
| =========
 | |
| SafeStack
 | |
| =========
 | |
| 
 | |
| .. contents::
 | |
|    :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
 | |
| <http://dslab.epfl.ch/proj/cpi/>`_.
 | |
| 
 | |
| 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
 | |
| <http://dslab.epfl.ch/pubs/cpi.pdf>`__ 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 though
 | |
| 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
 | |
| <http://dslab.epfl.ch/proj/cpi/>`_, or a forward-edge control flow integrity
 | |
| mechanism that enforces correct calling conventions at indirect call sites,
 | |
| such as `IFCC <http://research.google.com/pubs/archive/42808.pdf>`_ 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 <http://dslab.epfl.ch/pubs/cpi.pdf>`_ 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, FreeBSD and MacOSX.
 | |
| 
 | |
| 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.
 | |
| 
 | |
| .. code-block:: c
 | |
| 
 | |
|     #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.
 | |
| 
 | |
| ``__builtin___get_unsafe_stack_ptr()``
 | |
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 | |
| 
 | |
| This builtin function returns current unsafe stack pointer of the current
 | |
| thread.
 | |
| 
 | |
| ``__builtin___get_unsafe_stack_start()``
 | |
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 | |
| 
 | |
| This builtin function returns a pointer to the start of the unsafe stack of the
 | |
| current thread.
 | |
| 
 | |
| Design
 | |
| ======
 | |
| 
 | |
| Please refer to the `Code-Pointer Integrity <http://dslab.epfl.ch/proj/cpi/>`__
 | |
| project page for more information about the design of the SafeStack and its
 | |
| related technologies.
 | |
| 
 | |
| setjmp and exception handling
 | |
| -----------------------------
 | |
| 
 | |
| The `OSDI'14 paper <http://dslab.epfl.ch/pubs/cpi.pdf>`_ 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 <http://dslab.epfl.ch/pubs/cpi.pdf>`__.
 | |
| Volodymyr Kuznetsov, Laszlo Szekeres, Mathias Payer, George Candea, R. Sekar, Dawn Song.
 | |
| USENIX Symposium on Operating Systems Design and Implementation
 | |
| (`OSDI <https://www.usenix.org/conference/osdi14>`_), Broomfield, CO, October 2014
 |