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