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 35namespace __asan { 36 37void AsanOnDeadlySignal(int signo, void *siginfo, void *context) { 38 StartReportDeadlySignal(); 39 SignalContext sig(siginfo, context); 40 ReportDeadlySignal(sig); 41} 42 43bool 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 76static void (*tsd_destructor)(void *tsd) = nullptr; 77 78struct 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 88static thread_local struct tsd_key key; 89 90void AsanTSDInit(void (*destructor)(void *tsd)) { 91 CHECK(!tsd_destructor); 92 tsd_destructor = destructor; 93} 94 95void *AsanTSDGet() { 96 CHECK(tsd_destructor); 97 return key.key; 98} 99 100void AsanTSDSet(void *tsd) { 101 CHECK(tsd_destructor); 102 CHECK(tsd); 103 CHECK(!key.key); 104 key.key = tsd; 105} 106 107void 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 116static pthread_key_t tsd_key; 117static bool tsd_key_inited = false; 118void 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 124void *AsanTSDGet() { 125 CHECK(tsd_key_inited); 126 return pthread_getspecific(tsd_key); 127} 128 129void AsanTSDSet(void *tsd) { 130 CHECK(tsd_key_inited); 131 pthread_setspecific(tsd_key, tsd); 132} 133 134void 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 151static 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 162static 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 173void 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 182void 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