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" { 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 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 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 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 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. 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. 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 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 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 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" 32968d75effSDimitry Andric __attribute__((visibility("default"))) void *__get_unsafe_stack_bottom() { 33068d75effSDimitry Andric return unsafe_stack_start; 33168d75effSDimitry Andric } 33268d75effSDimitry Andric 33368d75effSDimitry Andric extern "C" 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" 33968d75effSDimitry Andric __attribute__((visibility("default"))) void *__get_unsafe_stack_start() { 34068d75effSDimitry Andric return unsafe_stack_start; 34168d75effSDimitry Andric } 34268d75effSDimitry Andric 34368d75effSDimitry Andric extern "C" 34468d75effSDimitry Andric __attribute__((visibility("default"))) void *__get_unsafe_stack_ptr() { 34568d75effSDimitry Andric return __safestack_unsafe_stack_ptr; 34668d75effSDimitry Andric } 347