1# SafeStack in Zircon & Fuchsia 2 3## Introduction 4 5LLVM's [safe-stack feature](https://clang.llvm.org/docs/SafeStack.html) 6is a compiler mode intended to harden the generated code against 7stack-smashing attacks such as exploits of buffer overrun bugs. 8 9The Clang/LLVM documentation page linked above describes the general 10scheme. The capsule summary is that that each thread has two stacks 11instead of the usual one: a "safe stack" and an "unsafe stack". The 12unsafe stack is used for all purposes where a pointer into the stack 13memory might be used, while the safe stack is used only for purposes 14where no code should ever see a pointer into the stack memory. So, the 15unsafe stack is used for arrays or variables that are passed by 16reference to another function or have their addresses stored in the 17heap--memory that could be subject to buffer overrun or use-after-free 18bugs and their exploits. The safe stack is used for the compiler's 19register spills, and for the return address of a function call. Thus, 20for example, a simple buffer overrun bug cannot be exploited to 21overwrite the return address of the containing function, which is the 22basis of exploits and attacks using the so-called *ROP* 23("return-oriented programming") technique. 24 25The **Compatibility** section of that page does not apply to Zircon (or 26Fuchsia). In Zircon user-mode code (including all of Fuchsia), the 27runtime support for SafeStack is included directly in the standard C 28runtime library, and everything works fine in shared libraries (DSOs). 29 30## Interoperation and ABI Effects 31 32In general, safe-stack does not affect the ABI. The machine-specific 33calling conventions are unchanged. It works fine to have some 34functions in a program built with safe-stack and some not. It doesn't 35matter if combining the two comes from directly compiled `.o` files, 36from archive libraries (`.a` files), or from shared libraries (`.so` 37files), in any combination. 38 39While there is some additional per-thread state (the *unsafe stack 40pointer*, see below under *Implementation details*), code not using 41safe-stack does not need to do anything about this state to keep it 42correct when calling, or being called by, code that does use 43safe-stack. The only potential exceptions to this are for code that 44is implementing its own kinds of non-local exits or context-switching 45(e.g. coroutines). The Zircon C library's `setjmp`/`longjmp` code 46saves and restores this additional state automatically, so anything 47that is based on `longjmp` already handles everything correctly even 48if the code calling `setjmp` and `longjmp` doesn't know about 49safe-stack. 50 51## Use in Zircon & Fuchsia 52 53This is enabled in the Clang compiler by the `-fsanitize=safe-stack` 54command-line option. In the near future, this will be the default mode 55of the compiler for `*-fuchsia` targets, and to disable it for a 56specific compilation will require the `-fno-sanitize=safe-stack` option. 57 58Zircon supports safe-stack for both user-mode and kernel code. 59In the Zircon build, safe-stack is always enabled when building 60with Clang (pass `USE_CLANG=true` to `make`). 61 62## Implementation details 63 64The essential addition to support safe-stack code is the *unsafe stack 65pointer*. In the abstract, this can be thought of as an additional 66register just like the machine's normal stack pointer register. The 67machine's stack pointer register is used for the safe stack, just as it 68always has been. The unsafe stack pointer is used as if it were another 69register with a fixed purpose in the ABI, but of course the machines 70don't actually have a new register, and for compatibility safe-stack 71does not change the basic machine-specific calling conventions that 72assign uses to all the machine registers. 73 74The C and C++ ABI for Zircon and Fuchsia stores the unsafe stack 75pointer in memory that's at a fixed offset from the thread pointer. 76The [`<zircon/tls.h>`](../system/public/zircon/tls.h) header defines 77the offset for each machine. 78 79For x86 user-mode, the thread pointer is the `fsbase`, meaning access 80in assembly code looks like `%fs:ZX_TLS_UNSAFE_SP_OFFSET`. 81For the x86 kernel, the thread pointer is the `gsbase`, meaning access 82in assembly code looks like `%gs:ZX_TLS_UNSAFE_SP_OFFSET`. 83 84For Aarch64 (ARM64), in C or C++ code, `__builtin_thread_pointer()` 85returns the thread pointer. In user-mode, the thread pointer is in the 86`TPIDR_EL0` special register and must be fetched into a normal register 87(with `mrs *reg*, TPIDR_EL0`) to access the memory, so it's not a single 88instruction in assembly code. In the kernel, it's just the same but 89using the `TPIDR_EL1` special register instead. 90 91### Notes for low-level and assembly code 92 93Most code, even in assembly, does not need to think about safe-stack 94issues at all. The calling conventions are not changed. Using the 95stack for saving registers, finding return addresses, etc. is all the 96same with or without safe-stack. The main exception is code that is 97implementing something like a non-local exit or context switch. Such 98code may need to save or restore the unsafe stack pointer. Both the 99`longjmp` function and C++ `throw` already handle this directly, so 100C or C++ code using those constructs does not need to do anything new. 101 102The context-switch code in the kernel handles switching the unsafe stack 103pointer. On x86, this is explicit in the code: `%gs` points to the 104`struct x86_percpu`, which has a member `kernel_unsafe_sp` at 105`ZX_TLS_UNSAFE_SP_OFFSET`; `arch_context_switch` copies this into the 106`unsafe_sp` field of the old thread's `struct arch_thread` and then 107copies the new thread's `unsafe_sp` into `kernel_unsafe_sp`. On ARM64, 108this is implicitly done by `set_current_thread`, because that changes 109the `TPIDR_EL1` special register, which points directly into the 110per-thread `struct thread` rather than a per-CPU structure like on x86. 111 112New code implementing some new kind of non-local exit or context switch 113will need to handle the unsafe stack pointer similarly to how it handles 114the traditional machine stack pointer register. Any such code should 115use `#if __has_feature(safe_stack)` to test at compile time whether 116safe-stack is being used in the particular build. That preprocessor 117construct can be used in C, C++, or assembly (`.S`) source files. 118