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 // Linux-specific details.
     13 //===----------------------------------------------------------------------===//
     14 #ifdef __linux__
     15 
     16 #include "asan_interceptors.h"
     17 #include "asan_internal.h"
     18 #include "asan_lock.h"
     19 #include "asan_procmaps.h"
     20 #include "asan_thread.h"
     21 
     22 #include <sys/time.h>
     23 #include <sys/resource.h>
     24 #include <sys/mman.h>
     25 #include <sys/syscall.h>
     26 #include <sys/types.h>
     27 #include <fcntl.h>
     28 #include <pthread.h>
     29 #include <stdio.h>
     30 #include <unistd.h>
     31 #include <unwind.h>
     32 
     33 #ifndef ANDROID
     34 // FIXME: where to get ucontext on Android?
     35 #include <sys/ucontext.h>
     36 #endif
     37 
     38 extern "C" void* _DYNAMIC;
     39 
     40 namespace __asan {
     41 
     42 void *AsanDoesNotSupportStaticLinkage() {
     43   // This will fail to link with -static.
     44   return &_DYNAMIC;  // defined in link.h
     45 }
     46 
     47 bool AsanShadowRangeIsAvailable() {
     48   // FIXME: shall we need anything here on Linux?
     49   return true;
     50 }
     51 
     52 void GetPcSpBp(void *context, uintptr_t *pc, uintptr_t *sp, uintptr_t *bp) {
     53 #ifdef ANDROID
     54   *pc = *sp = *bp = 0;
     55 #elif defined(__arm__)
     56   ucontext_t *ucontext = (ucontext_t*)context;
     57   *pc = ucontext->uc_mcontext.arm_pc;
     58   *bp = ucontext->uc_mcontext.arm_fp;
     59   *sp = ucontext->uc_mcontext.arm_sp;
     60 # elif defined(__x86_64__)
     61   ucontext_t *ucontext = (ucontext_t*)context;
     62   *pc = ucontext->uc_mcontext.gregs[REG_RIP];
     63   *bp = ucontext->uc_mcontext.gregs[REG_RBP];
     64   *sp = ucontext->uc_mcontext.gregs[REG_RSP];
     65 # elif defined(__i386__)
     66   ucontext_t *ucontext = (ucontext_t*)context;
     67   *pc = ucontext->uc_mcontext.gregs[REG_EIP];
     68   *bp = ucontext->uc_mcontext.gregs[REG_EBP];
     69   *sp = ucontext->uc_mcontext.gregs[REG_ESP];
     70 #else
     71 # error "Unsupported arch"
     72 #endif
     73 }
     74 
     75 bool AsanInterceptsSignal(int signum) {
     76   return signum == SIGSEGV && FLAG_handle_segv;
     77 }
     78 
     79 static void *asan_mmap(void *addr, size_t length, int prot, int flags,
     80                 int fd, uint64_t offset) {
     81 # if __WORDSIZE == 64
     82   return (void *)syscall(__NR_mmap, addr, length, prot, flags, fd, offset);
     83 # else
     84   return (void *)syscall(__NR_mmap2, addr, length, prot, flags, fd, offset);
     85 # endif
     86 }
     87 
     88 void *AsanMmapSomewhereOrDie(size_t size, const char *mem_type) {
     89   size = RoundUpTo(size, kPageSize);
     90   void *res = asan_mmap(0, size,
     91                         PROT_READ | PROT_WRITE,
     92                         MAP_PRIVATE | MAP_ANON, -1, 0);
     93   if (res == (void*)-1) {
     94     OutOfMemoryMessageAndDie(mem_type, size);
     95   }
     96   return res;
     97 }
     98 
     99 void *AsanMmapFixedNoReserve(uintptr_t fixed_addr, size_t size) {
    100   return asan_mmap((void*)fixed_addr, size,
    101                    PROT_READ | PROT_WRITE,
    102                    MAP_PRIVATE | MAP_ANON | MAP_FIXED | MAP_NORESERVE,
    103                    0, 0);
    104 }
    105 
    106 void *AsanMprotect(uintptr_t fixed_addr, size_t size) {
    107   return asan_mmap((void*)fixed_addr, size,
    108                    PROT_NONE,
    109                    MAP_PRIVATE | MAP_ANON | MAP_FIXED | MAP_NORESERVE,
    110                    0, 0);
    111 }
    112 
    113 void AsanUnmapOrDie(void *addr, size_t size) {
    114   if (!addr || !size) return;
    115   int res = syscall(__NR_munmap, addr, size);
    116   if (res != 0) {
    117     Report("Failed to unmap\n");
    118     AsanDie();
    119   }
    120 }
    121 
    122 size_t AsanWrite(int fd, const void *buf, size_t count) {
    123   return (size_t)syscall(__NR_write, fd, buf, count);
    124 }
    125 
    126 int AsanOpenReadonly(const char* filename) {
    127   return syscall(__NR_open, filename, O_RDONLY);
    128 }
    129 
    130 // Like getenv, but reads env directly from /proc and does not use libc.
    131 // This function should be called first inside __asan_init.
    132 const char* AsanGetEnv(const char* name) {
    133   static char *environ;
    134   static size_t len;
    135   static bool inited;
    136   if (!inited) {
    137     inited = true;
    138     size_t environ_size;
    139     len = ReadFileToBuffer("/proc/self/environ",
    140                            &environ, &environ_size, 1 << 26);
    141   }
    142   if (!environ || len == 0) return NULL;
    143   size_t namelen = internal_strlen(name);
    144   const char *p = environ;
    145   while (*p != '\0') {  // will happen at the \0\0 that terminates the buffer
    146     // proc file has the format NAME=value\0NAME=value\0NAME=value\0...
    147     const char* endp =
    148         (char*)internal_memchr(p, '\0', len - (p - environ));
    149     if (endp == NULL)  // this entry isn't NUL terminated
    150       return NULL;
    151     else if (!internal_memcmp(p, name, namelen) && p[namelen] == '=')  // Match.
    152       return p + namelen + 1;  // point after =
    153     p = endp + 1;
    154   }
    155   return NULL;  // Not found.
    156 }
    157 
    158 size_t AsanRead(int fd, void *buf, size_t count) {
    159   return (size_t)syscall(__NR_read, fd, buf, count);
    160 }
    161 
    162 int AsanClose(int fd) {
    163   return syscall(__NR_close, fd);
    164 }
    165 
    166 AsanProcMaps::AsanProcMaps() {
    167   proc_self_maps_buff_len_ =
    168       ReadFileToBuffer("/proc/self/maps", &proc_self_maps_buff_,
    169                        &proc_self_maps_buff_mmaped_size_, 1 << 26);
    170   CHECK(proc_self_maps_buff_len_ > 0);
    171   // AsanWrite(2, proc_self_maps_buff_, proc_self_maps_buff_len_);
    172   Reset();
    173 }
    174 
    175 AsanProcMaps::~AsanProcMaps() {
    176   AsanUnmapOrDie(proc_self_maps_buff_, proc_self_maps_buff_mmaped_size_);
    177 }
    178 
    179 void AsanProcMaps::Reset() {
    180   current_ = proc_self_maps_buff_;
    181 }
    182 
    183 bool AsanProcMaps::Next(uintptr_t *start, uintptr_t *end,
    184                         uintptr_t *offset, char filename[],
    185                         size_t filename_size) {
    186   char *last = proc_self_maps_buff_ + proc_self_maps_buff_len_;
    187   if (current_ >= last) return false;
    188   int consumed = 0;
    189   char flags[10];
    190   int major, minor;
    191   uintptr_t inode;
    192   char *next_line = (char*)internal_memchr(current_, '\n', last - current_);
    193   if (next_line == NULL)
    194     next_line = last;
    195   if (SScanf(current_,
    196              "%lx-%lx %4s %lx %x:%x %ld %n",
    197              start, end, flags, offset, &major, &minor,
    198              &inode, &consumed) != 7)
    199     return false;
    200   current_ += consumed;
    201   // Skip spaces.
    202   while (current_ < next_line && *current_ == ' ')
    203     current_++;
    204   // Fill in the filename.
    205   size_t i = 0;
    206   while (current_ < next_line) {
    207     if (filename && i < filename_size - 1)
    208       filename[i++] = *current_;
    209     current_++;
    210   }
    211   if (filename && i < filename_size)
    212     filename[i] = 0;
    213   current_ = next_line + 1;
    214   return true;
    215 }
    216 
    217 #if 1
    218 
    219 // Gets the object name and the offset by walking AsanProcMaps.
    220 bool AsanProcMaps::GetObjectNameAndOffset(uintptr_t addr, uintptr_t *offset,
    221                                           char filename[],
    222                                           size_t filename_size) {
    223   return IterateForObjectNameAndOffset(addr, offset, filename, filename_size);
    224 }
    225 
    226 #else
    227 // dl_iterate_phdr machinery is not working well for us.
    228 // We either need to fix it or get rid of it.
    229 struct DlIterateData {
    230   int count;
    231   uintptr_t addr;
    232   uintptr_t offset;
    233   char *filename;
    234   size_t filename_size;
    235 };
    236 
    237 static int dl_iterate_phdr_callback(struct dl_phdr_info *info,
    238                                     size_t size, void *raw_data) {
    239   DlIterateData *data = (DlIterateData*)raw_data;
    240   int count = data->count++;
    241   if (info->dlpi_addr > data->addr)
    242     return 0;
    243   if (count == 0) {
    244     // The first item (the main executable) does not have a so name,
    245     // but we can just read it from /proc/self/exe.
    246     size_t path_len = readlink("/proc/self/exe",
    247                                data->filename, data->filename_size - 1);
    248     data->filename[path_len] = 0;
    249   } else {
    250     CHECK(info->dlpi_name);
    251     REAL(strncpy)(data->filename, info->dlpi_name, data->filename_size);
    252   }
    253   data->offset = data->addr - info->dlpi_addr;
    254   return 1;
    255 }
    256 
    257 // Gets the object name and the offset using dl_iterate_phdr.
    258 bool AsanProcMaps::GetObjectNameAndOffset(uintptr_t addr, uintptr_t *offset,
    259                                           char filename[],
    260                                           size_t filename_size) {
    261   DlIterateData data;
    262   data.count = 0;
    263   data.addr = addr;
    264   data.filename = filename;
    265   data.filename_size = filename_size;
    266   if (dl_iterate_phdr(dl_iterate_phdr_callback, &data)) {
    267     *offset = data.offset;
    268     return true;
    269   }
    270   return false;
    271 }
    272 
    273 #endif  // __arm__
    274 
    275 void AsanThread::SetThreadStackTopAndBottom() {
    276   if (tid() == 0) {
    277     // This is the main thread. Libpthread may not be initialized yet.
    278     struct rlimit rl;
    279     CHECK(getrlimit(RLIMIT_STACK, &rl) == 0);
    280 
    281     // Find the mapping that contains a stack variable.
    282     AsanProcMaps proc_maps;
    283     uintptr_t start, end, offset;
    284     uintptr_t prev_end = 0;
    285     while (proc_maps.Next(&start, &end, &offset, NULL, 0)) {
    286       if ((uintptr_t)&rl < end)
    287         break;
    288       prev_end = end;
    289     }
    290     CHECK((uintptr_t)&rl >= start && (uintptr_t)&rl < end);
    291 
    292     // Get stacksize from rlimit, but clip it so that it does not overlap
    293     // with other mappings.
    294     size_t stacksize = rl.rlim_cur;
    295     if (stacksize > end - prev_end)
    296       stacksize = end - prev_end;
    297     if (stacksize > kMaxThreadStackSize)
    298       stacksize = kMaxThreadStackSize;
    299     stack_top_ = end;
    300     stack_bottom_ = end - stacksize;
    301     CHECK(AddrIsInStack((uintptr_t)&rl));
    302     return;
    303   }
    304   pthread_attr_t attr;
    305   CHECK(pthread_getattr_np(pthread_self(), &attr) == 0);
    306   size_t stacksize = 0;
    307   void *stackaddr = NULL;
    308   pthread_attr_getstack(&attr, &stackaddr, &stacksize);
    309   pthread_attr_destroy(&attr);
    310 
    311   stack_top_ = (uintptr_t)stackaddr + stacksize;
    312   stack_bottom_ = (uintptr_t)stackaddr;
    313   // When running with unlimited stack size, we still want to set some limit.
    314   // The unlimited stack size is caused by 'ulimit -s unlimited'.
    315   // Also, for some reason, GNU make spawns subrocesses with unlimited stack.
    316   if (stacksize > kMaxThreadStackSize) {
    317     stack_bottom_ = stack_top_ - kMaxThreadStackSize;
    318   }
    319   CHECK(AddrIsInStack((uintptr_t)&attr));
    320 }
    321 
    322 AsanLock::AsanLock(LinkerInitialized) {
    323   // We assume that pthread_mutex_t initialized to all zeroes is a valid
    324   // unlocked mutex. We can not use PTHREAD_MUTEX_INITIALIZER as it triggers
    325   // a gcc warning:
    326   // extended initializer lists only available with -std=c++0x or -std=gnu++0x
    327 }
    328 
    329 void AsanLock::Lock() {
    330   CHECK(sizeof(pthread_mutex_t) <= sizeof(opaque_storage_));
    331   pthread_mutex_lock((pthread_mutex_t*)&opaque_storage_);
    332   CHECK(!owner_);
    333   owner_ = (uintptr_t)pthread_self();
    334 }
    335 
    336 void AsanLock::Unlock() {
    337   CHECK(owner_ == (uintptr_t)pthread_self());
    338   owner_ = 0;
    339   pthread_mutex_unlock((pthread_mutex_t*)&opaque_storage_);
    340 }
    341 
    342 #ifdef __arm__
    343 #define UNWIND_STOP _URC_END_OF_STACK
    344 #define UNWIND_CONTINUE _URC_NO_REASON
    345 #else
    346 #define UNWIND_STOP _URC_NORMAL_STOP
    347 #define UNWIND_CONTINUE _URC_NO_REASON
    348 #endif
    349 
    350 uintptr_t Unwind_GetIP(struct _Unwind_Context *ctx) {
    351 #ifdef __arm__
    352   uintptr_t val;
    353   _Unwind_VRS_Result res = _Unwind_VRS_Get(ctx, _UVRSC_CORE,
    354       15 /* r15 = PC */, _UVRSD_UINT32, &val);
    355   CHECK(res == _UVRSR_OK && "_Unwind_VRS_Get failed");
    356   // Clear the Thumb bit.
    357   return val & ~(uintptr_t)1;
    358 #else
    359   return _Unwind_GetIP(ctx);
    360 #endif
    361 }
    362 
    363 _Unwind_Reason_Code Unwind_Trace(struct _Unwind_Context *ctx,
    364     void *param) {
    365   AsanStackTrace *b = (AsanStackTrace*)param;
    366   CHECK(b->size < b->max_size);
    367   uintptr_t pc = Unwind_GetIP(ctx);
    368   b->trace[b->size++] = pc;
    369   if (b->size == b->max_size) return UNWIND_STOP;
    370   return UNWIND_CONTINUE;
    371 }
    372 
    373 void AsanStackTrace::GetStackTrace(size_t max_s, uintptr_t pc, uintptr_t bp) {
    374   size = 0;
    375   trace[0] = pc;
    376   if ((max_s) > 1) {
    377     max_size = max_s;
    378 #ifdef __arm__
    379     _Unwind_Backtrace(Unwind_Trace, this);
    380 #else
    381      FastUnwindStack(pc, bp);
    382 #endif
    383   }
    384 }
    385 
    386 }  // namespace __asan
    387 
    388 #endif  // __linux__
    389