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