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 <pthread.h> 18 # include <signal.h> 19 # include <stdlib.h> 20 # include <sys/resource.h> 21 # include <sys/time.h> 22 # include <unistd.h> 23 24 # include "asan_interceptors.h" 25 # include "asan_internal.h" 26 # include "asan_mapping.h" 27 # include "asan_poisoning.h" 28 # include "asan_report.h" 29 # include "asan_stack.h" 30 # include "lsan/lsan_common.h" 31 # include "sanitizer_common/sanitizer_libc.h" 32 # include "sanitizer_common/sanitizer_posix.h" 33 # include "sanitizer_common/sanitizer_procmaps.h" 34 35 namespace __asan { 36 37 void AsanOnDeadlySignal(int signo, void *siginfo, void *context) { 38 StartReportDeadlySignal(); 39 SignalContext sig(siginfo, context); 40 ReportDeadlySignal(sig); 41 } 42 43 bool PlatformUnpoisonStacks() { 44 stack_t signal_stack; 45 CHECK_EQ(0, sigaltstack(nullptr, &signal_stack)); 46 uptr sigalt_bottom = (uptr)signal_stack.ss_sp; 47 uptr sigalt_top = (uptr)((char *)signal_stack.ss_sp + signal_stack.ss_size); 48 // If we're executing on the signal alternate stack AND the Linux flag 49 // SS_AUTODISARM was used, then we cannot get the signal alternate stack 50 // bounds from sigaltstack -- sigaltstack's output looks just as if no 51 // alternate stack has ever been set up. 52 // We're always unpoisoning the signal alternate stack to support jumping 53 // between the default stack and signal alternate stack. 54 if (signal_stack.ss_flags != SS_DISABLE) 55 UnpoisonStack(sigalt_bottom, sigalt_top, "sigalt"); 56 57 if (signal_stack.ss_flags != SS_ONSTACK) 58 return false; 59 60 // Since we're on the signal alternate stack, we cannot find the DEFAULT 61 // stack bottom using a local variable. 62 uptr stack_begin, stack_end, tls_begin, tls_end; 63 GetThreadStackAndTls(/*main=*/false, &stack_begin, &stack_end, &tls_begin, 64 &tls_end); 65 UnpoisonStack(stack_begin, stack_end, "default"); 66 return true; 67 } 68 69 // ---------------------- TSD ---------------- {{{1 70 71 #if SANITIZER_NETBSD && !ASAN_DYNAMIC 72 // Thread Static Data cannot be used in early static ASan init on NetBSD. 73 // Reuse the Asan TSD API for compatibility with existing code 74 // with an alternative implementation. 75 76 static void (*tsd_destructor)(void *tsd) = nullptr; 77 78 struct tsd_key { 79 tsd_key() : key(nullptr) {} 80 ~tsd_key() { 81 CHECK(tsd_destructor); 82 if (key) 83 (*tsd_destructor)(key); 84 } 85 void *key; 86 }; 87 88 static thread_local struct tsd_key key; 89 90 void AsanTSDInit(void (*destructor)(void *tsd)) { 91 CHECK(!tsd_destructor); 92 tsd_destructor = destructor; 93 } 94 95 void *AsanTSDGet() { 96 CHECK(tsd_destructor); 97 return key.key; 98 } 99 100 void AsanTSDSet(void *tsd) { 101 CHECK(tsd_destructor); 102 CHECK(tsd); 103 CHECK(!key.key); 104 key.key = tsd; 105 } 106 107 void PlatformTSDDtor(void *tsd) { 108 CHECK(tsd_destructor); 109 CHECK_EQ(key.key, tsd); 110 key.key = nullptr; 111 // Make sure that signal handler can not see a stale current thread pointer. 112 atomic_signal_fence(memory_order_seq_cst); 113 AsanThread::TSDDtor(tsd); 114 } 115 #else 116 static pthread_key_t tsd_key; 117 static bool tsd_key_inited = false; 118 void AsanTSDInit(void (*destructor)(void *tsd)) { 119 CHECK(!tsd_key_inited); 120 tsd_key_inited = true; 121 CHECK_EQ(0, pthread_key_create(&tsd_key, destructor)); 122 } 123 124 void *AsanTSDGet() { 125 CHECK(tsd_key_inited); 126 return pthread_getspecific(tsd_key); 127 } 128 129 void AsanTSDSet(void *tsd) { 130 CHECK(tsd_key_inited); 131 pthread_setspecific(tsd_key, tsd); 132 } 133 134 void PlatformTSDDtor(void *tsd) { 135 AsanThreadContext *context = (AsanThreadContext *)tsd; 136 if (context->destructor_iterations > 1) { 137 context->destructor_iterations--; 138 CHECK_EQ(0, pthread_setspecific(tsd_key, tsd)); 139 return; 140 } 141 # if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \ 142 SANITIZER_SOLARIS 143 // After this point it's unsafe to execute signal handlers which may be 144 // instrumented. It's probably not just a Linux issue. 145 BlockSignals(); 146 # endif 147 AsanThread::TSDDtor(tsd); 148 } 149 # endif 150 151 static void BeforeFork() { 152 VReport(2, "BeforeFork tid: %llu\n", GetTid()); 153 if (CAN_SANITIZE_LEAKS) { 154 __lsan::LockGlobal(); 155 } 156 // `_lsan` functions defined regardless of `CAN_SANITIZE_LEAKS` and lock the 157 // stuff we need. 158 __lsan::LockThreads(); 159 __lsan::LockAllocator(); 160 StackDepotLockBeforeFork(); 161 } 162 163 static void AfterFork(bool fork_child) { 164 StackDepotUnlockAfterFork(fork_child); 165 // `_lsan` functions defined regardless of `CAN_SANITIZE_LEAKS` and unlock 166 // the stuff we need. 167 __lsan::UnlockAllocator(); 168 __lsan::UnlockThreads(); 169 if (CAN_SANITIZE_LEAKS) { 170 __lsan::UnlockGlobal(); 171 } 172 VReport(2, "AfterFork tid: %llu\n", GetTid()); 173 } 174 175 void InstallAtForkHandler() { 176 # if SANITIZER_SOLARIS || SANITIZER_NETBSD || SANITIZER_APPLE || \ 177 (SANITIZER_LINUX && SANITIZER_SPARC) 178 // While other Linux targets use clone in internal_fork which doesn't 179 // trigger pthread_atfork handlers, Linux/sparc64 uses __fork, causing a 180 // hang. 181 return; // FIXME: Implement FutexWait. 182 # endif 183 pthread_atfork( 184 &BeforeFork, []() { AfterFork(/* fork_child= */ false); }, 185 []() { AfterFork(/* fork_child= */ true); }); 186 } 187 188 void InstallAtExitCheckLeaks() { 189 if (CAN_SANITIZE_LEAKS) { 190 if (common_flags()->detect_leaks && common_flags()->leak_check_at_exit) { 191 if (flags()->halt_on_error) 192 Atexit(__lsan::DoLeakCheck); 193 else 194 Atexit(__lsan::DoRecoverableLeakCheckVoid); 195 } 196 } 197 } 198 199 } // namespace __asan 200 201 #endif // SANITIZER_POSIX 202