Index: compiler-rt/lib/safestack/CMakeLists.txt =================================================================== --- compiler-rt/lib/safestack/CMakeLists.txt +++ compiler-rt/lib/safestack/CMakeLists.txt @@ -12,8 +12,6 @@ ARCHS ${arch} SOURCES ${SAFESTACK_SOURCES} $ - $ - $ CFLAGS ${SAFESTACK_CFLAGS} PARENT_TARGET safestack) endforeach() Index: compiler-rt/lib/safestack/safestack.cc =================================================================== --- compiler-rt/lib/safestack/safestack.cc +++ compiler-rt/lib/safestack/safestack.cc @@ -14,21 +14,20 @@ // //===----------------------------------------------------------------------===// +#include "safestack_platform.h" + #include -#include #include -#include -#include -#include +#include #include +#include #include -#include -#if !defined(__NetBSD__) -#include -#endif #include "interception/interception.h" -#include "sanitizer_common/sanitizer_common.h" + +using namespace safestack; + +namespace { // TODO: The runtime library does not currently protect the safe stack beyond // relying on the system-enforced ASLR. The protection of the (safe) stack can @@ -74,7 +73,7 @@ const unsigned kDefaultUnsafeStackSize = 0x2800000; /// Runtime page size obtained through sysconf -static unsigned pageSize; +unsigned pageSize; // TODO: To make accessing the unsafe stack pointer faster, we plan to // eventually store it directly in the thread control block data structure on @@ -92,24 +91,38 @@ // Per-thread unsafe stack information. It's not frequently accessed, so there // it can be kept out of the tcb in normal thread-local variables. -static __thread void *unsafe_stack_start = nullptr; -static __thread size_t unsafe_stack_size = 0; -static __thread size_t unsafe_stack_guard = 0; - -using namespace __sanitizer; +__thread void *unsafe_stack_start = nullptr; +__thread size_t unsafe_stack_size = 0; +__thread size_t unsafe_stack_guard = 0; + +#define SFS_CHECK(a) \ + do { \ + if (!(a)) { \ + fprintf(stderr, "safestack CHECK failed: %s:%d %s\n", __FILE__, \ + __LINE__, #a); \ + abort(); \ + }; \ + } while (false) + +inline size_t RoundUpTo(size_t size, size_t boundary) { + SFS_CHECK((boundary & (boundary - 1)) == 0); + return (size + boundary - 1) & ~(boundary - 1); +} -static inline void *unsafe_stack_alloc(size_t size, size_t guard) { - CHECK_GE(size + guard, size); - void *addr = MmapOrDie(size + guard, "unsafe_stack_alloc"); - MprotectNoAccess((uptr)addr, (uptr)guard); +inline void *unsafe_stack_alloc(size_t size, size_t guard) { + SFS_CHECK(size + guard >= size); + void *addr = mmap(nullptr, RoundUpTo(size + guard, pageSize), + PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); + SFS_CHECK(MAP_FAILED != addr); + mprotect(addr, guard, PROT_NONE); return (char *)addr + guard; } -static inline void unsafe_stack_setup(void *start, size_t size, size_t guard) { - CHECK_GE((char *)start + size, (char *)start); - CHECK_GE((char *)start + guard, (char *)start); +inline void unsafe_stack_setup(void *start, size_t size, size_t guard) { + SFS_CHECK((char *)start + size >= (char *)start); + SFS_CHECK((char *)start + guard >= (char *)start); void *stack_ptr = (char *)start + size; - CHECK_EQ((((size_t)stack_ptr) & (kStackAlign - 1)), 0); + SFS_CHECK((((size_t)stack_ptr) & (kStackAlign - 1)) == 0); __safestack_unsafe_stack_ptr = stack_ptr; unsafe_stack_start = start; @@ -118,7 +131,7 @@ } /// Thread data for the cleanup handler -static pthread_key_t thread_cleanup_key; +pthread_key_t thread_cleanup_key; /// Safe stack per-thread information passed to the thread_start function struct tinfo { @@ -132,7 +145,7 @@ /// Wrap the thread function in order to deallocate the unsafe stack when the /// thread terminates by returning from its main function. -static void *thread_start(void *arg) { +void *thread_start(void *arg) { struct tinfo *tinfo = (struct tinfo *)arg; void *(*start_routine)(void *) = tinfo->start_routine; @@ -154,19 +167,19 @@ void *stack_base; size_t size; pid_t pid; - tid_t tid; + pid_t tid; }; /// Linked list of unsafe stacks for threads that are exiting. We delay /// unmapping them until the thread exits. -static thread_stack_ll *thread_stacks = nullptr; -static pthread_mutex_t thread_stacks_mutex = PTHREAD_MUTEX_INITIALIZER; +thread_stack_ll *thread_stacks = nullptr; +pthread_mutex_t thread_stacks_mutex = PTHREAD_MUTEX_INITIALIZER; /// Thread-specific data destructor. We want to free the unsafe stack only after /// this thread is terminated. libc can call functions in safestack-instrumented /// code (like free) after thread-specific data destructors have run. -static void thread_cleanup_handler(void *_iter) { - CHECK_NE(unsafe_stack_start, nullptr); +void thread_cleanup_handler(void *_iter) { + SFS_CHECK(unsafe_stack_start != nullptr); pthread_setspecific(thread_cleanup_key, NULL); pthread_mutex_lock(&thread_stacks_mutex); @@ -177,17 +190,15 @@ pthread_mutex_unlock(&thread_stacks_mutex); pid_t pid = getpid(); - tid_t tid = GetTid(); + pid_t tid = GetTid(); // Free stacks for dead threads thread_stack_ll **stackp = &temp_stacks; while (*stackp) { thread_stack_ll *stack = *stackp; - int error; if (stack->pid != pid || - (internal_iserror(TgKill(stack->pid, stack->tid, 0), &error) && - error == ESRCH)) { - UnmapOrDie(stack->stack_base, stack->size); + (-1 == TgKill(stack->pid, stack->tid, 0) && errno == ESRCH)) { + munmap(stack->stack_base, stack->size); *stackp = stack->next; free(stack); } else @@ -212,7 +223,7 @@ unsafe_stack_start = nullptr; } -static void EnsureInterceptorsInitialized(); +void EnsureInterceptorsInitialized(); /// Intercept thread creation operation to allocate and setup the unsafe stack INTERCEPTOR(int, pthread_create, pthread_t *thread, @@ -234,9 +245,9 @@ pthread_attr_destroy(&tmpattr); } - CHECK_NE(size, 0); - CHECK_EQ((size & (kStackAlign - 1)), 0); - CHECK_EQ((guard & (pageSize - 1)), 0); + SFS_CHECK(size); + SFS_CHECK((size & (kStackAlign - 1)) == 0); + SFS_CHECK((guard & (pageSize - 1)) == 0); void *addr = unsafe_stack_alloc(size, guard); struct tinfo *tinfo = @@ -250,12 +261,24 @@ return REAL(pthread_create)(thread, attr, thread_start, tinfo); } -static BlockingMutex interceptor_init_lock(LINKER_INITIALIZED); -static bool interceptors_inited = false; +pthread_mutex_t interceptor_init_mutex = PTHREAD_MUTEX_INITIALIZER; +bool interceptors_inited = false; + +class MutexLock { + public: + explicit MutexLock(pthread_mutex_t &mutex) : mutex_(&mutex) { + pthread_mutex_lock(mutex_); + } + ~MutexLock() { pthread_mutex_unlock(mutex_); } + + private: + pthread_mutex_t *mutex_ = nullptr; +}; -static void EnsureInterceptorsInitialized() { - BlockingMutexLock lock(&interceptor_init_lock); - if (interceptors_inited) return; +void EnsureInterceptorsInitialized() { + MutexLock lock(interceptor_init_mutex); + if (interceptors_inited) + return; // Initialize pthread interceptors for thread allocation INTERCEPT_FUNCTION(pthread_create); @@ -269,6 +292,8 @@ __attribute__((constructor(0))) #endif void __safestack_init() { + pageSize = sysconf(_SC_PAGESIZE); + // Determine the stack size for the main thread. size_t size = kDefaultUnsafeStackSize; size_t guard = 4096; @@ -281,7 +306,6 @@ void *addr = unsafe_stack_alloc(size, guard); unsafe_stack_setup(addr, size, guard); - pageSize = sysconf(_SC_PAGESIZE); // Setup the cleanup handler pthread_key_create(&thread_cleanup_key, thread_cleanup_handler); @@ -297,6 +321,8 @@ } #endif +} // namespace + extern "C" __attribute__((visibility("default"))) void *__get_unsafe_stack_bottom() { return unsafe_stack_start; Index: compiler-rt/lib/safestack/safestack_platform.h =================================================================== --- /dev/null +++ compiler-rt/lib/safestack/safestack_platform.h @@ -0,0 +1,61 @@ +//===-- safestack_platform.h +//------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements platform specific parts of SafeStack runtime. +// +//===----------------------------------------------------------------------===// + +#ifndef SAFESTACK_PLATFORM_H +#define SAFESTACK_PLATFORM_H + +#include "sanitizer_common/sanitizer_platform.h" + +#include +#include +#include + +namespace safestack { + +inline pid_t GetTid() { +#if SANITIZER_NETBSD + return _lwp_self(); +#elif SANITIZER_FREEBSD + long Tid; + thr_self(&Tid); + return Tid; +#elif SANITIZER_OPENBSD + return syscall(SYS_getthrid); +#elif SANITIZER_SOLARIS + return thr_self(); +#else + return syscall(SYS_gettid); +#endif +} + +inline int TgKill(pid_t pid, pid_t tid, int sig) { +#if SANITIZER_NETBSD + (void)pid; + return _lwp_kill(tid, sig); +#elif SANITIZER_LINUX + return syscall(SYS_tgkill, pid, tid, sig); +#elif SANITIZER_FREEBSD + return syscall(SYS_thr_kill2, pid, tid, sig); +#elif SANITIZER_OPENBSD + (void)pid; + return syscall(SYSCALL(thrkill), tid, sig, nullptr); +#elif SANITIZER_SOLARIS + (void)pid; + return thr_kill(tid, sig); +#endif +} + +} // namespace safestack + +#endif // SAFESTACK_PLATFORM_H