Home | History | Annotate | Download | only in asan
      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