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