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 default_bottom, tls_addr, tls_size, stack_size; 63 GetThreadStackAndTls(/*main=*/false, &default_bottom, &stack_size, &tls_addr, 64 &tls_size); 65 UnpoisonStack(default_bottom, default_bottom + stack_size, "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 if (CAN_SANITIZE_LEAKS) { 153 __lsan::LockGlobal(); 154 } 155 // `_lsan` functions defined regardless of `CAN_SANITIZE_LEAKS` and lock the 156 // stuff we need. 157 __lsan::LockThreads(); 158 __lsan::LockAllocator(); 159 StackDepotLockBeforeFork(); 160 } 161 162 static void AfterFork(bool fork_child) { 163 StackDepotUnlockAfterFork(fork_child); 164 // `_lsan` functions defined regardless of `CAN_SANITIZE_LEAKS` and unlock 165 // the stuff we need. 166 __lsan::UnlockAllocator(); 167 __lsan::UnlockThreads(); 168 if (CAN_SANITIZE_LEAKS) { 169 __lsan::UnlockGlobal(); 170 } 171 } 172 173 void InstallAtForkHandler() { 174 # if SANITIZER_SOLARIS || SANITIZER_NETBSD || SANITIZER_APPLE 175 return; // FIXME: Implement FutexWait. 176 # endif 177 pthread_atfork( 178 &BeforeFork, []() { AfterFork(/* fork_child= */ false); }, 179 []() { AfterFork(/* fork_child= */ true); }); 180 } 181 182 void InstallAtExitCheckLeaks() { 183 if (CAN_SANITIZE_LEAKS) { 184 if (common_flags()->detect_leaks && common_flags()->leak_check_at_exit) { 185 if (flags()->halt_on_error) 186 Atexit(__lsan::DoLeakCheck); 187 else 188 Atexit(__lsan::DoRecoverableLeakCheckVoid); 189 } 190 } 191 } 192 193 } // namespace __asan 194 195 #endif // SANITIZER_POSIX 196