168d75effSDimitry Andric //===-- safestack.cpp -----------------------------------------------------===//
268d75effSDimitry Andric //
368d75effSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
468d75effSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
568d75effSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
668d75effSDimitry Andric //
768d75effSDimitry Andric //===----------------------------------------------------------------------===//
868d75effSDimitry Andric //
968d75effSDimitry Andric // This file implements the runtime support for the safe stack protection
1068d75effSDimitry Andric // mechanism. The runtime manages allocation/deallocation of the unsafe stack
1168d75effSDimitry Andric // for the main thread, as well as all pthreads that are created/destroyed
1268d75effSDimitry Andric // during program execution.
1368d75effSDimitry Andric //
1468d75effSDimitry Andric //===----------------------------------------------------------------------===//
1568d75effSDimitry Andric
16*0fca6ea1SDimitry Andric #define SANITIZER_COMMON_NO_REDEFINE_BUILTINS
17*0fca6ea1SDimitry Andric
1868d75effSDimitry Andric #include "safestack_platform.h"
1968d75effSDimitry Andric #include "safestack_util.h"
20*0fca6ea1SDimitry Andric #include "sanitizer_common/sanitizer_internal_defs.h"
2168d75effSDimitry Andric
2268d75effSDimitry Andric #include <errno.h>
23*0fca6ea1SDimitry Andric #include <string.h>
2468d75effSDimitry Andric #include <sys/resource.h>
2568d75effSDimitry Andric
2668d75effSDimitry Andric #include "interception/interception.h"
2768d75effSDimitry Andric
28*0fca6ea1SDimitry Andric // interception.h drags in sanitizer_redefine_builtins.h, which in turn
29*0fca6ea1SDimitry Andric // creates references to __sanitizer_internal_memcpy etc. The interceptors
30*0fca6ea1SDimitry Andric // aren't needed here, so just forward to libc.
31*0fca6ea1SDimitry Andric extern "C" {
__sanitizer_internal_memcpy(void * dest,const void * src,size_t n)32*0fca6ea1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE void *__sanitizer_internal_memcpy(void *dest,
33*0fca6ea1SDimitry Andric const void *src,
34*0fca6ea1SDimitry Andric size_t n) {
35*0fca6ea1SDimitry Andric return memcpy(dest, src, n);
36*0fca6ea1SDimitry Andric }
37*0fca6ea1SDimitry Andric
__sanitizer_internal_memmove(void * dest,const void * src,size_t n)38*0fca6ea1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE void *__sanitizer_internal_memmove(
39*0fca6ea1SDimitry Andric void *dest, const void *src, size_t n) {
40*0fca6ea1SDimitry Andric return memmove(dest, src, n);
41*0fca6ea1SDimitry Andric }
42*0fca6ea1SDimitry Andric
__sanitizer_internal_memset(void * s,int c,size_t n)43*0fca6ea1SDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE void *__sanitizer_internal_memset(void *s, int c,
44*0fca6ea1SDimitry Andric size_t n) {
45*0fca6ea1SDimitry Andric return memset(s, c, n);
46*0fca6ea1SDimitry Andric }
47*0fca6ea1SDimitry Andric } // extern "C"
48*0fca6ea1SDimitry Andric
4968d75effSDimitry Andric using namespace safestack;
5068d75effSDimitry Andric
5168d75effSDimitry Andric // TODO: To make accessing the unsafe stack pointer faster, we plan to
5268d75effSDimitry Andric // eventually store it directly in the thread control block data structure on
5368d75effSDimitry Andric // platforms where this structure is pointed to by %fs or %gs. This is exactly
5468d75effSDimitry Andric // the same mechanism as currently being used by the traditional stack
5568d75effSDimitry Andric // protector pass to store the stack guard (see getStackCookieLocation()
5668d75effSDimitry Andric // function above). Doing so requires changing the tcbhead_t struct in glibc
5768d75effSDimitry Andric // on Linux and tcb struct in libc on FreeBSD.
5868d75effSDimitry Andric //
5968d75effSDimitry Andric // For now, store it in a thread-local variable.
6068d75effSDimitry Andric extern "C" {
6168d75effSDimitry Andric __attribute__((visibility(
6268d75effSDimitry Andric "default"))) __thread void *__safestack_unsafe_stack_ptr = nullptr;
6368d75effSDimitry Andric }
6468d75effSDimitry Andric
6568d75effSDimitry Andric namespace {
6668d75effSDimitry Andric
6768d75effSDimitry Andric // TODO: The runtime library does not currently protect the safe stack beyond
6868d75effSDimitry Andric // relying on the system-enforced ASLR. The protection of the (safe) stack can
6968d75effSDimitry Andric // be provided by three alternative features:
7068d75effSDimitry Andric //
7168d75effSDimitry Andric // 1) Protection via hardware segmentation on x86-32 and some x86-64
7268d75effSDimitry Andric // architectures: the (safe) stack segment (implicitly accessed via the %ss
7368d75effSDimitry Andric // segment register) can be separated from the data segment (implicitly
7468d75effSDimitry Andric // accessed via the %ds segment register). Dereferencing a pointer to the safe
7568d75effSDimitry Andric // segment would result in a segmentation fault.
7668d75effSDimitry Andric //
7768d75effSDimitry Andric // 2) Protection via software fault isolation: memory writes that are not meant
7868d75effSDimitry Andric // to access the safe stack can be prevented from doing so through runtime
7968d75effSDimitry Andric // instrumentation. One way to do it is to allocate the safe stack(s) in the
8068d75effSDimitry Andric // upper half of the userspace and bitmask the corresponding upper bit of the
8168d75effSDimitry Andric // memory addresses of memory writes that are not meant to access the safe
8268d75effSDimitry Andric // stack.
8368d75effSDimitry Andric //
8468d75effSDimitry Andric // 3) Protection via information hiding on 64 bit architectures: the location
8568d75effSDimitry Andric // of the safe stack(s) can be randomized through secure mechanisms, and the
8668d75effSDimitry Andric // leakage of the stack pointer can be prevented. Currently, libc can leak the
8768d75effSDimitry Andric // stack pointer in several ways (e.g. in longjmp, signal handling, user-level
8868d75effSDimitry Andric // context switching related functions, etc.). These can be fixed in libc and
8968d75effSDimitry Andric // in other low-level libraries, by either eliminating the escaping/dumping of
9068d75effSDimitry Andric // the stack pointer (i.e., %rsp) when that's possible, or by using
9168d75effSDimitry Andric // encryption/PTR_MANGLE (XOR-ing the dumped stack pointer with another secret
9268d75effSDimitry Andric // we control and protect better, as is already done for setjmp in glibc.)
9368d75effSDimitry Andric // Furthermore, a static machine code level verifier can be ran after code
9468d75effSDimitry Andric // generation to make sure that the stack pointer is never written to memory,
9568d75effSDimitry Andric // or if it is, its written on the safe stack.
9668d75effSDimitry Andric //
9768d75effSDimitry Andric // Finally, while the Unsafe Stack pointer is currently stored in a thread
9868d75effSDimitry Andric // local variable, with libc support it could be stored in the TCB (thread
9968d75effSDimitry Andric // control block) as well, eliminating another level of indirection and making
10068d75effSDimitry Andric // such accesses faster. Alternatively, dedicating a separate register for
10168d75effSDimitry Andric // storing it would also be possible.
10268d75effSDimitry Andric
10368d75effSDimitry Andric /// Minimum stack alignment for the unsafe stack.
10468d75effSDimitry Andric const unsigned kStackAlign = 16;
10568d75effSDimitry Andric
10668d75effSDimitry Andric /// Default size of the unsafe stack. This value is only used if the stack
10768d75effSDimitry Andric /// size rlimit is set to infinity.
10868d75effSDimitry Andric const unsigned kDefaultUnsafeStackSize = 0x2800000;
10968d75effSDimitry Andric
11068d75effSDimitry Andric // Per-thread unsafe stack information. It's not frequently accessed, so there
11168d75effSDimitry Andric // it can be kept out of the tcb in normal thread-local variables.
11268d75effSDimitry Andric __thread void *unsafe_stack_start = nullptr;
11368d75effSDimitry Andric __thread size_t unsafe_stack_size = 0;
11468d75effSDimitry Andric __thread size_t unsafe_stack_guard = 0;
11568d75effSDimitry Andric
unsafe_stack_alloc(size_t size,size_t guard)11668d75effSDimitry Andric inline void *unsafe_stack_alloc(size_t size, size_t guard) {
11768d75effSDimitry Andric SFS_CHECK(size + guard >= size);
11868d75effSDimitry Andric void *addr = Mmap(nullptr, size + guard, PROT_READ | PROT_WRITE,
11968d75effSDimitry Andric MAP_PRIVATE | MAP_ANON, -1, 0);
12068d75effSDimitry Andric SFS_CHECK(MAP_FAILED != addr);
12168d75effSDimitry Andric Mprotect(addr, guard, PROT_NONE);
12268d75effSDimitry Andric return (char *)addr + guard;
12368d75effSDimitry Andric }
12468d75effSDimitry Andric
unsafe_stack_setup(void * start,size_t size,size_t guard)12568d75effSDimitry Andric inline void unsafe_stack_setup(void *start, size_t size, size_t guard) {
12668d75effSDimitry Andric SFS_CHECK((char *)start + size >= (char *)start);
12768d75effSDimitry Andric SFS_CHECK((char *)start + guard >= (char *)start);
12868d75effSDimitry Andric void *stack_ptr = (char *)start + size;
12968d75effSDimitry Andric SFS_CHECK((((size_t)stack_ptr) & (kStackAlign - 1)) == 0);
13068d75effSDimitry Andric
13168d75effSDimitry Andric __safestack_unsafe_stack_ptr = stack_ptr;
13268d75effSDimitry Andric unsafe_stack_start = start;
13368d75effSDimitry Andric unsafe_stack_size = size;
13468d75effSDimitry Andric unsafe_stack_guard = guard;
13568d75effSDimitry Andric }
13668d75effSDimitry Andric
13768d75effSDimitry Andric /// Thread data for the cleanup handler
13868d75effSDimitry Andric pthread_key_t thread_cleanup_key;
13968d75effSDimitry Andric
14068d75effSDimitry Andric /// Safe stack per-thread information passed to the thread_start function
14168d75effSDimitry Andric struct tinfo {
14268d75effSDimitry Andric void *(*start_routine)(void *);
14368d75effSDimitry Andric void *start_routine_arg;
14468d75effSDimitry Andric
14568d75effSDimitry Andric void *unsafe_stack_start;
14668d75effSDimitry Andric size_t unsafe_stack_size;
14768d75effSDimitry Andric size_t unsafe_stack_guard;
14868d75effSDimitry Andric };
14968d75effSDimitry Andric
15068d75effSDimitry Andric /// Wrap the thread function in order to deallocate the unsafe stack when the
15168d75effSDimitry Andric /// thread terminates by returning from its main function.
thread_start(void * arg)15268d75effSDimitry Andric void *thread_start(void *arg) {
15368d75effSDimitry Andric struct tinfo *tinfo = (struct tinfo *)arg;
15468d75effSDimitry Andric
15568d75effSDimitry Andric void *(*start_routine)(void *) = tinfo->start_routine;
15668d75effSDimitry Andric void *start_routine_arg = tinfo->start_routine_arg;
15768d75effSDimitry Andric
15868d75effSDimitry Andric // Setup the unsafe stack; this will destroy tinfo content
15968d75effSDimitry Andric unsafe_stack_setup(tinfo->unsafe_stack_start, tinfo->unsafe_stack_size,
16068d75effSDimitry Andric tinfo->unsafe_stack_guard);
16168d75effSDimitry Andric
16268d75effSDimitry Andric // Make sure out thread-specific destructor will be called
16368d75effSDimitry Andric pthread_setspecific(thread_cleanup_key, (void *)1);
16468d75effSDimitry Andric
16568d75effSDimitry Andric return start_routine(start_routine_arg);
16668d75effSDimitry Andric }
16768d75effSDimitry Andric
16868d75effSDimitry Andric /// Linked list used to store exiting threads stack/thread information.
16968d75effSDimitry Andric struct thread_stack_ll {
17068d75effSDimitry Andric struct thread_stack_ll *next;
17168d75effSDimitry Andric void *stack_base;
17268d75effSDimitry Andric size_t size;
17368d75effSDimitry Andric pid_t pid;
17468d75effSDimitry Andric ThreadId tid;
17568d75effSDimitry Andric };
17668d75effSDimitry Andric
17768d75effSDimitry Andric /// Linked list of unsafe stacks for threads that are exiting. We delay
17868d75effSDimitry Andric /// unmapping them until the thread exits.
17968d75effSDimitry Andric thread_stack_ll *thread_stacks = nullptr;
18068d75effSDimitry Andric pthread_mutex_t thread_stacks_mutex = PTHREAD_MUTEX_INITIALIZER;
18168d75effSDimitry Andric
18268d75effSDimitry Andric /// Thread-specific data destructor. We want to free the unsafe stack only after
18368d75effSDimitry Andric /// this thread is terminated. libc can call functions in safestack-instrumented
18468d75effSDimitry Andric /// code (like free) after thread-specific data destructors have run.
thread_cleanup_handler(void * _iter)18568d75effSDimitry Andric void thread_cleanup_handler(void *_iter) {
18668d75effSDimitry Andric SFS_CHECK(unsafe_stack_start != nullptr);
18768d75effSDimitry Andric pthread_setspecific(thread_cleanup_key, NULL);
18868d75effSDimitry Andric
18968d75effSDimitry Andric pthread_mutex_lock(&thread_stacks_mutex);
19068d75effSDimitry Andric // Temporary list to hold the previous threads stacks so we don't hold the
19168d75effSDimitry Andric // thread_stacks_mutex for long.
19268d75effSDimitry Andric thread_stack_ll *temp_stacks = thread_stacks;
19368d75effSDimitry Andric thread_stacks = nullptr;
19468d75effSDimitry Andric pthread_mutex_unlock(&thread_stacks_mutex);
19568d75effSDimitry Andric
19668d75effSDimitry Andric pid_t pid = getpid();
19768d75effSDimitry Andric ThreadId tid = GetTid();
19868d75effSDimitry Andric
19968d75effSDimitry Andric // Free stacks for dead threads
20068d75effSDimitry Andric thread_stack_ll **stackp = &temp_stacks;
20168d75effSDimitry Andric while (*stackp) {
20268d75effSDimitry Andric thread_stack_ll *stack = *stackp;
20368d75effSDimitry Andric if (stack->pid != pid ||
20468d75effSDimitry Andric (-1 == TgKill(stack->pid, stack->tid, 0) && errno == ESRCH)) {
20568d75effSDimitry Andric Munmap(stack->stack_base, stack->size);
20668d75effSDimitry Andric *stackp = stack->next;
20768d75effSDimitry Andric free(stack);
20868d75effSDimitry Andric } else
20968d75effSDimitry Andric stackp = &stack->next;
21068d75effSDimitry Andric }
21168d75effSDimitry Andric
21268d75effSDimitry Andric thread_stack_ll *cur_stack =
21368d75effSDimitry Andric (thread_stack_ll *)malloc(sizeof(thread_stack_ll));
21468d75effSDimitry Andric cur_stack->stack_base = (char *)unsafe_stack_start - unsafe_stack_guard;
21568d75effSDimitry Andric cur_stack->size = unsafe_stack_size + unsafe_stack_guard;
21668d75effSDimitry Andric cur_stack->pid = pid;
21768d75effSDimitry Andric cur_stack->tid = tid;
21868d75effSDimitry Andric
21968d75effSDimitry Andric pthread_mutex_lock(&thread_stacks_mutex);
22068d75effSDimitry Andric // Merge thread_stacks with the current thread's stack and any remaining
22168d75effSDimitry Andric // temp_stacks
22268d75effSDimitry Andric *stackp = thread_stacks;
22368d75effSDimitry Andric cur_stack->next = temp_stacks;
22468d75effSDimitry Andric thread_stacks = cur_stack;
22568d75effSDimitry Andric pthread_mutex_unlock(&thread_stacks_mutex);
22668d75effSDimitry Andric
22768d75effSDimitry Andric unsafe_stack_start = nullptr;
22868d75effSDimitry Andric }
22968d75effSDimitry Andric
23068d75effSDimitry Andric void EnsureInterceptorsInitialized();
23168d75effSDimitry Andric
23268d75effSDimitry Andric /// Intercept thread creation operation to allocate and setup the unsafe stack
INTERCEPTOR(int,pthread_create,pthread_t * thread,const pthread_attr_t * attr,void * (* start_routine)(void *),void * arg)23368d75effSDimitry Andric INTERCEPTOR(int, pthread_create, pthread_t *thread,
23468d75effSDimitry Andric const pthread_attr_t *attr,
23568d75effSDimitry Andric void *(*start_routine)(void*), void *arg) {
23668d75effSDimitry Andric EnsureInterceptorsInitialized();
23768d75effSDimitry Andric size_t size = 0;
23868d75effSDimitry Andric size_t guard = 0;
23968d75effSDimitry Andric
24068d75effSDimitry Andric if (attr) {
24168d75effSDimitry Andric pthread_attr_getstacksize(attr, &size);
24268d75effSDimitry Andric pthread_attr_getguardsize(attr, &guard);
24368d75effSDimitry Andric } else {
24468d75effSDimitry Andric // get pthread default stack size
24568d75effSDimitry Andric pthread_attr_t tmpattr;
24668d75effSDimitry Andric pthread_attr_init(&tmpattr);
24768d75effSDimitry Andric pthread_attr_getstacksize(&tmpattr, &size);
24868d75effSDimitry Andric pthread_attr_getguardsize(&tmpattr, &guard);
24968d75effSDimitry Andric pthread_attr_destroy(&tmpattr);
25068d75effSDimitry Andric }
25168d75effSDimitry Andric
252*0fca6ea1SDimitry Andric #if SANITIZER_SOLARIS
253*0fca6ea1SDimitry Andric // Solaris pthread_attr_init initializes stacksize to 0 (the default), so
254*0fca6ea1SDimitry Andric // hardcode the actual values as documented in pthread_create(3C).
255*0fca6ea1SDimitry Andric if (size == 0)
256*0fca6ea1SDimitry Andric # if defined(_LP64)
257*0fca6ea1SDimitry Andric size = 2 * 1024 * 1024;
258*0fca6ea1SDimitry Andric # else
259*0fca6ea1SDimitry Andric size = 1024 * 1024;
260*0fca6ea1SDimitry Andric # endif
261*0fca6ea1SDimitry Andric #endif
262*0fca6ea1SDimitry Andric
26368d75effSDimitry Andric SFS_CHECK(size);
26468d75effSDimitry Andric size = RoundUpTo(size, kStackAlign);
26568d75effSDimitry Andric
26668d75effSDimitry Andric void *addr = unsafe_stack_alloc(size, guard);
26768d75effSDimitry Andric // Put tinfo at the end of the buffer. guard may be not page aligned.
26868d75effSDimitry Andric // If that is so then some bytes after addr can be mprotected.
26968d75effSDimitry Andric struct tinfo *tinfo =
27068d75effSDimitry Andric (struct tinfo *)(((char *)addr) + size - sizeof(struct tinfo));
27168d75effSDimitry Andric tinfo->start_routine = start_routine;
27268d75effSDimitry Andric tinfo->start_routine_arg = arg;
27368d75effSDimitry Andric tinfo->unsafe_stack_start = addr;
27468d75effSDimitry Andric tinfo->unsafe_stack_size = size;
27568d75effSDimitry Andric tinfo->unsafe_stack_guard = guard;
27668d75effSDimitry Andric
27768d75effSDimitry Andric return REAL(pthread_create)(thread, attr, thread_start, tinfo);
27868d75effSDimitry Andric }
27968d75effSDimitry Andric
28068d75effSDimitry Andric pthread_mutex_t interceptor_init_mutex = PTHREAD_MUTEX_INITIALIZER;
28168d75effSDimitry Andric bool interceptors_inited = false;
28268d75effSDimitry Andric
EnsureInterceptorsInitialized()28368d75effSDimitry Andric void EnsureInterceptorsInitialized() {
28468d75effSDimitry Andric MutexLock lock(interceptor_init_mutex);
28568d75effSDimitry Andric if (interceptors_inited)
28668d75effSDimitry Andric return;
28768d75effSDimitry Andric
28868d75effSDimitry Andric // Initialize pthread interceptors for thread allocation
28968d75effSDimitry Andric INTERCEPT_FUNCTION(pthread_create);
29068d75effSDimitry Andric
29168d75effSDimitry Andric interceptors_inited = true;
29268d75effSDimitry Andric }
29368d75effSDimitry Andric
29468d75effSDimitry Andric } // namespace
29568d75effSDimitry Andric
29668d75effSDimitry Andric extern "C" __attribute__((visibility("default")))
29768d75effSDimitry Andric #if !SANITIZER_CAN_USE_PREINIT_ARRAY
29868d75effSDimitry Andric // On ELF platforms, the constructor is invoked using .preinit_array (see below)
29968d75effSDimitry Andric __attribute__((constructor(0)))
30068d75effSDimitry Andric #endif
__safestack_init()30168d75effSDimitry Andric void __safestack_init() {
30268d75effSDimitry Andric // Determine the stack size for the main thread.
30368d75effSDimitry Andric size_t size = kDefaultUnsafeStackSize;
30468d75effSDimitry Andric size_t guard = 4096;
30568d75effSDimitry Andric
30668d75effSDimitry Andric struct rlimit limit;
30768d75effSDimitry Andric if (getrlimit(RLIMIT_STACK, &limit) == 0 && limit.rlim_cur != RLIM_INFINITY)
30868d75effSDimitry Andric size = limit.rlim_cur;
30968d75effSDimitry Andric
31068d75effSDimitry Andric // Allocate unsafe stack for main thread
31168d75effSDimitry Andric void *addr = unsafe_stack_alloc(size, guard);
31268d75effSDimitry Andric unsafe_stack_setup(addr, size, guard);
31368d75effSDimitry Andric
31468d75effSDimitry Andric // Setup the cleanup handler
31568d75effSDimitry Andric pthread_key_create(&thread_cleanup_key, thread_cleanup_handler);
31668d75effSDimitry Andric }
31768d75effSDimitry Andric
31868d75effSDimitry Andric #if SANITIZER_CAN_USE_PREINIT_ARRAY
31968d75effSDimitry Andric // On ELF platforms, run safestack initialization before any other constructors.
32068d75effSDimitry Andric // On other platforms we use the constructor attribute to arrange to run our
32168d75effSDimitry Andric // initialization early.
32268d75effSDimitry Andric extern "C" {
32368d75effSDimitry Andric __attribute__((section(".preinit_array"),
32468d75effSDimitry Andric used)) void (*__safestack_preinit)(void) = __safestack_init;
32568d75effSDimitry Andric }
32668d75effSDimitry Andric #endif
32768d75effSDimitry Andric
32868d75effSDimitry Andric extern "C"
__get_unsafe_stack_bottom()32968d75effSDimitry Andric __attribute__((visibility("default"))) void *__get_unsafe_stack_bottom() {
33068d75effSDimitry Andric return unsafe_stack_start;
33168d75effSDimitry Andric }
33268d75effSDimitry Andric
33368d75effSDimitry Andric extern "C"
__get_unsafe_stack_top()33468d75effSDimitry Andric __attribute__((visibility("default"))) void *__get_unsafe_stack_top() {
33568d75effSDimitry Andric return (char*)unsafe_stack_start + unsafe_stack_size;
33668d75effSDimitry Andric }
33768d75effSDimitry Andric
33868d75effSDimitry Andric extern "C"
__get_unsafe_stack_start()33968d75effSDimitry Andric __attribute__((visibility("default"))) void *__get_unsafe_stack_start() {
34068d75effSDimitry Andric return unsafe_stack_start;
34168d75effSDimitry Andric }
34268d75effSDimitry Andric
34368d75effSDimitry Andric extern "C"
__get_unsafe_stack_ptr()34468d75effSDimitry Andric __attribute__((visibility("default"))) void *__get_unsafe_stack_ptr() {
34568d75effSDimitry Andric return __safestack_unsafe_stack_ptr;
34668d75effSDimitry Andric }
347