• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1=========
2SafeStack
3=========
4
5.. contents::
6   :local:
7
8Introduction
9============
10
11SafeStack is an instrumentation pass that protects programs against attacks
12based on stack buffer overflows, without introducing any measurable performance
13overhead. 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 that
17buffer overflows on the unsafe stack cannot be used to overwrite anything
18on the safe stack.
19
20SafeStack is a part of the `Code-Pointer Integrity (CPI) Project
21<https://dslab.epfl.ch/proj/cpi/>`_.
22
23Performance
24-----------
25
26The performance overhead of the SafeStack instrumentation is less than 0.1% on
27average across a variety of benchmarks (see the `Code-Pointer Integrity
28<https://dslab.epfl.ch/pubs/cpi.pdf>`__ paper for details). This is mainly
29because most small functions do not have any variables that require the unsafe
30stack and, hence, do not need unsafe stack frames to be created. The cost of
31creating unsafe stack frames for large functions is amortized by the cost of
32executing the function.
33
34In some cases, SafeStack actually improves the performance. Objects that end up
35being moved to the unsafe stack are usually large arrays or variables that are
36used through multiple stack frames. Moving such objects away from the safe
37stack increases the locality of frequently accessed values on the stack, such
38as register spills, return addresses, and small local variables.
39
40Compatibility
41-------------
42
43Most programs, static libraries, or individual files can be compiled
44with SafeStack as is. SafeStack requires basic runtime support, which, on most
45platforms, is implemented as a compiler-rt library that is automatically linked
46in when the program is compiled with SafeStack.
47
48Linking a DSO with SafeStack is not currently supported.
49
50Known compatibility limitations
51~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
52
53Certain code that relies on low-level stack manipulations requires adaption to
54work with SafeStack. One example is mark-and-sweep garbage collection
55implementations for C/C++ (e.g., Oilpan in chromium/blink), which must be
56changed to look for the live pointers on both safe and unsafe stacks.
57
58SafeStack supports linking statically modules that are compiled with and
59without SafeStack. An executable compiled with SafeStack can load dynamic
60libraries that are not compiled with SafeStack. At the moment, compiling
61dynamic libraries with SafeStack is not supported.
62
63Signal handlers that use ``sigaltstack()`` must not use the unsafe stack (see
64``__attribute__((no_sanitize("safe-stack")))`` below).
65
66Programs that use APIs from ``ucontext.h`` are not supported yet.
67
68Security
69--------
70
71SafeStack protects return addresses, spilled registers and local variables that
72are always accessed in a safe way by separating them in a dedicated safe stack
73region. The safe stack is automatically protected against stack-based buffer
74overflows, since it is disjoint from the unsafe stack in memory, and it itself
75is always accessed in a safe way. In the current implementation, the safe stack
76is protected against arbitrary memory write vulnerabilities though
77randomization and information hiding: the safe stack is allocated at a random
78address and the instrumentation ensures that no pointers to the safe stack are
79ever stored outside of the safe stack itself (see limitations below).
80
81Known security limitations
82~~~~~~~~~~~~~~~~~~~~~~~~~~
83
84A complete protection against control-flow hijack attacks requires combining
85SafeStack with another mechanism that enforces the integrity of code pointers
86that are stored on the heap or the unsafe stack, such as `CPI
87<https://dslab.epfl.ch/proj/cpi/>`_, or a forward-edge control flow integrity
88mechanism that enforces correct calling conventions at indirect call sites,
89such as `IFCC <https://research.google.com/pubs/archive/42808.pdf>`_ with arity
90checks. Clang has control-flow integrity protection scheme for :doc:`C++ virtual
91calls <ControlFlowIntegrity>`, but not non-virtual indirect calls. With
92SafeStack alone, an attacker can overwrite a function pointer on the heap or
93the unsafe stack and cause a program to call arbitrary location, which in turn
94might enable stack pivoting and return-oriented programming.
95
96In its current implementation, SafeStack provides precise protection against
97stack-based buffer overflows, but protection against arbitrary memory write
98vulnerabilities is probabilistic and relies on randomization and information
99hiding. The randomization is currently based on system-enforced ASLR and shares
100its known security limitations. The safe stack pointer hiding is not perfect
101yet either: system library functions such as ``swapcontext``, exception
102handling mechanisms, intrinsics such as ``__builtin_frame_address``, or
103low-level bugs in runtime support could leak the safe stack pointer. In the
104future, such leaks could be detected by static or dynamic analysis tools and
105prevented by adjusting such functions to either encrypt the stack pointer when
106storing 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 fault
111isolation, or hardware segmentation (as available on x86-32 and some x86-64
112CPUs).
113
114At the moment, SafeStack assumes that the compiler's implementation is correct.
115This has not been verified except through manual code inspection, and could
116always regress in the future. It's therefore desirable to have a separate
117static or dynamic binary verification tool that would check the correctness of
118the SafeStack instrumentation in final binaries.
119
120Usage
121=====
122
123To enable SafeStack, just pass ``-fsanitize=safe-stack`` flag to both compile
124and link command lines.
125
126Supported Platforms
127-------------------
128
129SafeStack was tested on Linux, NetBSD, FreeBSD and macOS.
130
131Low-level API
132-------------
133
134``__has_feature(safe_stack)``
135~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
136
137In some rare cases one may need to execute different code depending on
138whether SafeStack is enabled. The macro ``__has_feature(safe_stack)`` can
139be used for this purpose.
140
141.. code-block:: c
142
143    #if __has_feature(safe_stack)
144    // code that builds only under SafeStack
145    #endif
146
147``__attribute__((no_sanitize("safe-stack")))``
148~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
149
150Use ``__attribute__((no_sanitize("safe-stack")))`` on a function declaration
151to specify that the safe stack instrumentation should not be applied to that
152function, even if enabled globally (see ``-fsanitize=safe-stack`` flag). This
153attribute may be required for functions that make assumptions about the
154exact layout of their stack frames.
155
156All local variables in functions with this attribute will be stored on the safe
157stack. The safe stack remains unprotected against memory errors when accessing
158these variables, so extra care must be taken to manually ensure that all such
159accesses are safe. Furthermore, the addresses of such local variables should
160never 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 current
166thread.
167
168``__builtin___get_unsafe_stack_bottom()``
169~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
170
171This builtin function returns a pointer to the bottom of the unsafe stack of the
172current thread.
173
174``__builtin___get_unsafe_stack_top()``
175~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
176
177This builtin function returns a pointer to the top of the unsafe stack of the
178current thread.
179
180``__builtin___get_unsafe_stack_start()``
181~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
182
183Deprecated: This builtin function is an alias for
184``__builtin___get_unsafe_stack_bottom()``.
185
186Design
187======
188
189Please refer to the `Code-Pointer Integrity <https://dslab.epfl.ch/proj/cpi/>`__
190project page for more information about the design of the SafeStack and its
191related technologies.
192
193setjmp and exception handling
194-----------------------------
195
196The `OSDI'14 paper <https://dslab.epfl.ch/pubs/cpi.pdf>`_ mentions that
197on Linux the instrumentation pass finds calls to setjmp or functions that
198may throw an exception, and inserts required instrumentation at their call
199sites. Specifically, the instrumentation pass saves the shadow stack pointer
200on the safe stack before the call site, and restores it either after the
201call to setjmp or after an exception has been caught. This is implemented
202in the function ``SafeStack::createStackRestorePoints``.
203
204Publications
205------------
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 Implementation
210(`OSDI <https://www.usenix.org/conference/osdi14>`_), Broomfield, CO, October 2014
211