1 //===-- asan_posix.cpp ----------------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file is a part of AddressSanitizer, an address sanity checker. 10 // 11 // Posix-specific details. 12 //===----------------------------------------------------------------------===// 13 14 #include "sanitizer_common/sanitizer_platform.h" 15 #if SANITIZER_POSIX 16 17 #include "asan_internal.h" 18 #include "asan_interceptors.h" 19 #include "asan_mapping.h" 20 #include "asan_poisoning.h" 21 #include "asan_report.h" 22 #include "asan_stack.h" 23 #include "sanitizer_common/sanitizer_libc.h" 24 #include "sanitizer_common/sanitizer_posix.h" 25 #include "sanitizer_common/sanitizer_procmaps.h" 26 27 #include <pthread.h> 28 #include <signal.h> 29 #include <stdlib.h> 30 #include <sys/time.h> 31 #include <sys/resource.h> 32 #include <unistd.h> 33 34 namespace __asan { 35 36 void AsanOnDeadlySignal(int signo, void *siginfo, void *context) { 37 StartReportDeadlySignal(); 38 SignalContext sig(siginfo, context); 39 ReportDeadlySignal(sig); 40 } 41 42 bool PlatformUnpoisonStacks() { 43 stack_t signal_stack; 44 CHECK_EQ(0, sigaltstack(nullptr, &signal_stack)); 45 uptr sigalt_bottom = (uptr)signal_stack.ss_sp; 46 uptr sigalt_top = (uptr)((char *)signal_stack.ss_sp + signal_stack.ss_size); 47 // If we're executing on the signal alternate stack AND the Linux flag 48 // SS_AUTODISARM was used, then we cannot get the signal alternate stack 49 // bounds from sigaltstack -- sigaltstack's output looks just as if no 50 // alternate stack has ever been set up. 51 // We're always unpoisoning the signal alternate stack to support jumping 52 // between the default stack and signal alternate stack. 53 if (signal_stack.ss_flags != SS_DISABLE) 54 UnpoisonStack(sigalt_bottom, sigalt_top, "sigalt"); 55 56 if (signal_stack.ss_flags != SS_ONSTACK) 57 return false; 58 59 // Since we're on the signal alternate stack, we cannot find the DEFAULT 60 // stack bottom using a local variable. 61 uptr default_bottom, tls_addr, tls_size, stack_size; 62 GetThreadStackAndTls(/*main=*/false, &default_bottom, &stack_size, &tls_addr, 63 &tls_size); 64 UnpoisonStack(default_bottom, default_bottom + stack_size, "default"); 65 return true; 66 } 67 68 // ---------------------- TSD ---------------- {{{1 69 70 #if SANITIZER_NETBSD && !ASAN_DYNAMIC 71 // Thread Static Data cannot be used in early static ASan init on NetBSD. 72 // Reuse the Asan TSD API for compatibility with existing code 73 // with an alternative implementation. 74 75 static void (*tsd_destructor)(void *tsd) = nullptr; 76 77 struct tsd_key { 78 tsd_key() : key(nullptr) {} 79 ~tsd_key() { 80 CHECK(tsd_destructor); 81 if (key) 82 (*tsd_destructor)(key); 83 } 84 void *key; 85 }; 86 87 static thread_local struct tsd_key key; 88 89 void AsanTSDInit(void (*destructor)(void *tsd)) { 90 CHECK(!tsd_destructor); 91 tsd_destructor = destructor; 92 } 93 94 void *AsanTSDGet() { 95 CHECK(tsd_destructor); 96 return key.key; 97 } 98 99 void AsanTSDSet(void *tsd) { 100 CHECK(tsd_destructor); 101 CHECK(tsd); 102 CHECK(!key.key); 103 key.key = tsd; 104 } 105 106 void PlatformTSDDtor(void *tsd) { 107 CHECK(tsd_destructor); 108 CHECK_EQ(key.key, tsd); 109 key.key = nullptr; 110 // Make sure that signal handler can not see a stale current thread pointer. 111 atomic_signal_fence(memory_order_seq_cst); 112 AsanThread::TSDDtor(tsd); 113 } 114 #else 115 static pthread_key_t tsd_key; 116 static bool tsd_key_inited = false; 117 void AsanTSDInit(void (*destructor)(void *tsd)) { 118 CHECK(!tsd_key_inited); 119 tsd_key_inited = true; 120 CHECK_EQ(0, pthread_key_create(&tsd_key, destructor)); 121 } 122 123 void *AsanTSDGet() { 124 CHECK(tsd_key_inited); 125 return pthread_getspecific(tsd_key); 126 } 127 128 void AsanTSDSet(void *tsd) { 129 CHECK(tsd_key_inited); 130 pthread_setspecific(tsd_key, tsd); 131 } 132 133 void PlatformTSDDtor(void *tsd) { 134 AsanThreadContext *context = (AsanThreadContext*)tsd; 135 if (context->destructor_iterations > 1) { 136 context->destructor_iterations--; 137 CHECK_EQ(0, pthread_setspecific(tsd_key, tsd)); 138 return; 139 } 140 AsanThread::TSDDtor(tsd); 141 } 142 #endif 143 } // namespace __asan 144 145 #endif // SANITIZER_POSIX 146