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