1 //===-- asan_linux.cc -----------------------------------------------------===// 2 // 3 // This file is distributed under the University of Illinois Open Source 4 // License. See LICENSE.TXT for details. 5 // 6 //===----------------------------------------------------------------------===// 7 // 8 // This file is a part of AddressSanitizer, an address sanity checker. 9 // 10 // Posix-specific details. 11 //===----------------------------------------------------------------------===// 12 #if defined(__linux__) || defined(__APPLE__) || defined(__NetBSD__) 13 14 #include "asan_internal.h" 15 #include "asan_interceptors.h" 16 #include "asan_mapping.h" 17 #include "asan_report.h" 18 #include "asan_stack.h" 19 #include "asan_thread_registry.h" 20 #include "sanitizer_common/sanitizer_libc.h" 21 #include "sanitizer_common/sanitizer_procmaps.h" 22 23 #include <pthread.h> 24 #include <signal.h> 25 #include <stdlib.h> 26 #include <sys/time.h> 27 #include <sys/resource.h> 28 #include <unistd.h> 29 30 static const uptr kAltStackSize = SIGSTKSZ * 4; // SIGSTKSZ is not enough. 31 32 namespace __asan { 33 34 static void MaybeInstallSigaction(int signum, 35 void (*handler)(int, siginfo_t *, void *)) { 36 if (!AsanInterceptsSignal(signum)) 37 return; 38 struct sigaction sigact; 39 REAL(memset)(&sigact, 0, sizeof(sigact)); 40 sigact.sa_sigaction = handler; 41 sigact.sa_flags = SA_SIGINFO; 42 if (flags()->use_sigaltstack) sigact.sa_flags |= SA_ONSTACK; 43 CHECK(0 == REAL(sigaction)(signum, &sigact, 0)); 44 if (flags()->verbosity >= 1) { 45 Report("Installed the sigaction for signal %d\n", signum); 46 } 47 } 48 49 static void ASAN_OnSIGSEGV(int, siginfo_t *siginfo, void *context) { 50 uptr addr = (uptr)siginfo->si_addr; 51 // Write the first message using the bullet-proof write. 52 if (13 != internal_write(2, "ASAN:SIGSEGV\n", 13)) Die(); 53 uptr pc, sp, bp; 54 GetPcSpBp(context, &pc, &sp, &bp); 55 ReportSIGSEGV(pc, sp, bp, addr); 56 } 57 58 void SetAlternateSignalStack() { 59 stack_t altstack, oldstack; 60 CHECK(0 == sigaltstack(0, &oldstack)); 61 // If the alternate stack is already in place, do nothing. 62 if ((oldstack.ss_flags & SS_DISABLE) == 0) return; 63 // TODO(glider): the mapped stack should have the MAP_STACK flag in the 64 // future. It is not required by man 2 sigaltstack now (they're using 65 // malloc()). 66 void* base = MmapOrDie(kAltStackSize, __FUNCTION__); 67 altstack.ss_sp = base; 68 altstack.ss_flags = 0; 69 altstack.ss_size = kAltStackSize; 70 CHECK(0 == sigaltstack(&altstack, 0)); 71 if (flags()->verbosity > 0) { 72 Report("Alternative stack for T%d set: [%p,%p)\n", 73 asanThreadRegistry().GetCurrentTidOrInvalid(), 74 altstack.ss_sp, (char*)altstack.ss_sp + altstack.ss_size); 75 } 76 } 77 78 void UnsetAlternateSignalStack() { 79 stack_t altstack, oldstack; 80 altstack.ss_sp = 0; 81 altstack.ss_flags = SS_DISABLE; 82 altstack.ss_size = 0; 83 CHECK(0 == sigaltstack(&altstack, &oldstack)); 84 UnmapOrDie(oldstack.ss_sp, oldstack.ss_size); 85 } 86 87 void InstallSignalHandlers() { 88 // Set the alternate signal stack for the main thread. 89 // This will cause SetAlternateSignalStack to be called twice, but the stack 90 // will be actually set only once. 91 if (flags()->use_sigaltstack) SetAlternateSignalStack(); 92 MaybeInstallSigaction(SIGSEGV, ASAN_OnSIGSEGV); 93 MaybeInstallSigaction(SIGBUS, ASAN_OnSIGSEGV); 94 } 95 96 // ---------------------- TSD ---------------- {{{1 97 98 static pthread_key_t tsd_key; 99 static bool tsd_key_inited = false; 100 void AsanTSDInit(void (*destructor)(void *tsd)) { 101 CHECK(!tsd_key_inited); 102 tsd_key_inited = true; 103 CHECK(0 == pthread_key_create(&tsd_key, destructor)); 104 } 105 106 void *AsanTSDGet() { 107 CHECK(tsd_key_inited); 108 return pthread_getspecific(tsd_key); 109 } 110 111 void AsanTSDSet(void *tsd) { 112 CHECK(tsd_key_inited); 113 pthread_setspecific(tsd_key, tsd); 114 } 115 116 } // namespace __asan 117 118 #endif // __linux__ || __APPLE_ || __NetBSD__ 119