208 lines · cpp
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-exception6//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_POSIX16 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 flag49 // SS_AUTODISARM was used, then we cannot get the signal alternate stack50 // bounds from sigaltstack -- sigaltstack's output looks just as if no51 // alternate stack has ever been set up.52 // We're always unpoisoning the signal alternate stack to support jumping53 // 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 DEFAULT61 // 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 ---------------- {{{170 71#if SANITIZER_NETBSD && !ASAN_DYNAMIC72// Thread Static Data cannot be used in early static ASan init on NetBSD.73// Reuse the Asan TSD API for compatibility with existing code74// 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#else116static 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_SOLARIS143 // After this point it's unsafe to execute signal handlers which may be144 // instrumented. It's probably not just a Linux issue.145 BlockSignals();146# endif147 AsanThread::TSDDtor(tsd);148}149# endif150 151static 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 the157 // stuff we need.158 __lsan::LockThreads();159 __lsan::LockAllocator();160 161 AcquirePoisonRecords();162 163 StackDepotLockBeforeFork();164}165 166static void AfterFork(bool fork_child) {167 StackDepotUnlockAfterFork(fork_child);168 169 ReleasePoisonRecords();170 171 // `_lsan` functions defined regardless of `CAN_SANITIZE_LEAKS` and unlock172 // the stuff we need.173 __lsan::UnlockAllocator();174 __lsan::UnlockThreads();175 if (CAN_SANITIZE_LEAKS) {176 __lsan::UnlockGlobal();177 }178 VReport(2, "AfterFork tid: %llu\n", GetTid());179}180 181void InstallAtForkHandler() {182# if SANITIZER_SOLARIS || SANITIZER_NETBSD || SANITIZER_APPLE || \183 (SANITIZER_LINUX && SANITIZER_SPARC) || SANITIZER_HAIKU || SANITIZER_AIX184 // While other Linux targets use clone in internal_fork which doesn't185 // trigger pthread_atfork handlers, Linux/sparc64 uses __fork, causing a186 // hang.187 return; // FIXME: Implement FutexWait.188# endif189 pthread_atfork(190 &BeforeFork, []() { AfterFork(/* fork_child= */ false); },191 []() { AfterFork(/* fork_child= */ true); });192}193 194void InstallAtExitCheckLeaks() {195 if (CAN_SANITIZE_LEAKS) {196 if (common_flags()->detect_leaks && common_flags()->leak_check_at_exit) {197 if (flags()->halt_on_error)198 Atexit(__lsan::DoLeakCheck);199 else200 Atexit(__lsan::DoRecoverableLeakCheckVoid);201 }202 }203}204 205} // namespace __asan206 207#endif // SANITIZER_POSIX208