asan_linux.cc revision a25b3463477d2a825df4f656001fc07c594b35ac
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#include "sanitizer_common/sanitizer_libc.h" 22 23#include <sys/time.h> 24#include <sys/resource.h> 25#include <sys/mman.h> 26#include <sys/syscall.h> 27#include <sys/types.h> 28#include <fcntl.h> 29#include <pthread.h> 30#include <stdio.h> 31#include <unistd.h> 32#include <unwind.h> 33 34#ifndef ANDROID 35// FIXME: where to get ucontext on Android? 36#include <sys/ucontext.h> 37#endif 38 39extern "C" void* _DYNAMIC; 40 41namespace __asan { 42 43const uptr kMaxThreadStackSize = 256 * (1 << 20); // 256M 44 45void *AsanDoesNotSupportStaticLinkage() { 46 // This will fail to link with -static. 47 return &_DYNAMIC; // defined in link.h 48} 49 50void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) { 51#ifdef ANDROID 52 *pc = *sp = *bp = 0; 53#elif defined(__arm__) 54 ucontext_t *ucontext = (ucontext_t*)context; 55 *pc = ucontext->uc_mcontext.arm_pc; 56 *bp = ucontext->uc_mcontext.arm_fp; 57 *sp = ucontext->uc_mcontext.arm_sp; 58# elif defined(__x86_64__) 59 ucontext_t *ucontext = (ucontext_t*)context; 60 *pc = ucontext->uc_mcontext.gregs[REG_RIP]; 61 *bp = ucontext->uc_mcontext.gregs[REG_RBP]; 62 *sp = ucontext->uc_mcontext.gregs[REG_RSP]; 63# elif defined(__i386__) 64 ucontext_t *ucontext = (ucontext_t*)context; 65 *pc = ucontext->uc_mcontext.gregs[REG_EIP]; 66 *bp = ucontext->uc_mcontext.gregs[REG_EBP]; 67 *sp = ucontext->uc_mcontext.gregs[REG_ESP]; 68#else 69# error "Unsupported arch" 70#endif 71} 72 73bool AsanInterceptsSignal(int signum) { 74 return signum == SIGSEGV && FLAG_handle_segv; 75} 76 77void *AsanMmapFixedNoReserve(uptr fixed_addr, uptr size) { 78 return internal_mmap((void*)fixed_addr, size, 79 PROT_READ | PROT_WRITE, 80 MAP_PRIVATE | MAP_ANON | MAP_FIXED | MAP_NORESERVE, 81 0, 0); 82} 83 84void *AsanMprotect(uptr fixed_addr, uptr size) { 85 return internal_mmap((void*)fixed_addr, size, 86 PROT_NONE, 87 MAP_PRIVATE | MAP_ANON | MAP_FIXED | MAP_NORESERVE, 88 0, 0); 89} 90 91// Like getenv, but reads env directly from /proc and does not use libc. 92// This function should be called first inside __asan_init. 93const char* AsanGetEnv(const char* name) { 94 static char *environ; 95 static uptr len; 96 static bool inited; 97 if (!inited) { 98 inited = true; 99 uptr environ_size; 100 len = ReadFileToBuffer("/proc/self/environ", 101 &environ, &environ_size, 1 << 26); 102 } 103 if (!environ || len == 0) return 0; 104 uptr namelen = internal_strlen(name); 105 const char *p = environ; 106 while (*p != '\0') { // will happen at the \0\0 that terminates the buffer 107 // proc file has the format NAME=value\0NAME=value\0NAME=value\0... 108 const char* endp = 109 (char*)internal_memchr(p, '\0', len - (p - environ)); 110 if (endp == 0) // this entry isn't NUL terminated 111 return 0; 112 else if (!internal_memcmp(p, name, namelen) && p[namelen] == '=') // Match. 113 return p + namelen + 1; // point after = 114 p = endp + 1; 115 } 116 return 0; // Not found. 117} 118 119AsanProcMaps::AsanProcMaps() { 120 proc_self_maps_buff_len_ = 121 ReadFileToBuffer("/proc/self/maps", &proc_self_maps_buff_, 122 &proc_self_maps_buff_mmaped_size_, 1 << 26); 123 CHECK(proc_self_maps_buff_len_ > 0); 124 // internal_write(2, proc_self_maps_buff_, proc_self_maps_buff_len_); 125 Reset(); 126} 127 128AsanProcMaps::~AsanProcMaps() { 129 UnmapOrDie(proc_self_maps_buff_, proc_self_maps_buff_mmaped_size_); 130} 131 132void AsanProcMaps::Reset() { 133 current_ = proc_self_maps_buff_; 134} 135 136bool AsanProcMaps::Next(uptr *start, uptr *end, 137 uptr *offset, char filename[], 138 uptr filename_size) { 139 char *last = proc_self_maps_buff_ + proc_self_maps_buff_len_; 140 if (current_ >= last) return false; 141 int consumed = 0; 142 char flags[10]; 143 int major, minor; 144 uptr inode; 145 uptr dummy; 146 if (!start) start = &dummy; 147 if (!end) end = &dummy; 148 if (!offset) offset = &dummy; 149 char *next_line = (char*)internal_memchr(current_, '\n', last - current_); 150 if (next_line == 0) 151 next_line = last; 152 if (internal_sscanf(current_, 153 "%lx-%lx %4s %lx %x:%x %ld %n", 154 start, end, flags, offset, &major, &minor, 155 &inode, &consumed) != 7) 156 return false; 157 current_ += consumed; 158 // Skip spaces. 159 while (current_ < next_line && *current_ == ' ') 160 current_++; 161 // Fill in the filename. 162 uptr i = 0; 163 while (current_ < next_line) { 164 if (filename && i < filename_size - 1) 165 filename[i++] = *current_; 166 current_++; 167 } 168 if (filename && i < filename_size) 169 filename[i] = 0; 170 current_ = next_line + 1; 171 return true; 172} 173 174// Gets the object name and the offset by walking AsanProcMaps. 175bool AsanProcMaps::GetObjectNameAndOffset(uptr addr, uptr *offset, 176 char filename[], 177 uptr filename_size) { 178 return IterateForObjectNameAndOffset(addr, offset, filename, filename_size); 179} 180 181void AsanThread::SetThreadStackTopAndBottom() { 182 if (tid() == 0) { 183 // This is the main thread. Libpthread may not be initialized yet. 184 struct rlimit rl; 185 CHECK(getrlimit(RLIMIT_STACK, &rl) == 0); 186 187 // Find the mapping that contains a stack variable. 188 AsanProcMaps proc_maps; 189 uptr start, end, offset; 190 uptr prev_end = 0; 191 while (proc_maps.Next(&start, &end, &offset, 0, 0)) { 192 if ((uptr)&rl < end) 193 break; 194 prev_end = end; 195 } 196 CHECK((uptr)&rl >= start && (uptr)&rl < end); 197 198 // Get stacksize from rlimit, but clip it so that it does not overlap 199 // with other mappings. 200 uptr stacksize = rl.rlim_cur; 201 if (stacksize > end - prev_end) 202 stacksize = end - prev_end; 203 // When running with unlimited stack size, we still want to set some limit. 204 // The unlimited stack size is caused by 'ulimit -s unlimited'. 205 // Also, for some reason, GNU make spawns subprocesses with unlimited stack. 206 if (stacksize > kMaxThreadStackSize) 207 stacksize = kMaxThreadStackSize; 208 stack_top_ = end; 209 stack_bottom_ = end - stacksize; 210 CHECK(AddrIsInStack((uptr)&rl)); 211 return; 212 } 213 pthread_attr_t attr; 214 CHECK(pthread_getattr_np(pthread_self(), &attr) == 0); 215 uptr stacksize = 0; 216 void *stackaddr = 0; 217 pthread_attr_getstack(&attr, &stackaddr, (size_t*)&stacksize); 218 pthread_attr_destroy(&attr); 219 220 stack_top_ = (uptr)stackaddr + stacksize; 221 stack_bottom_ = (uptr)stackaddr; 222 CHECK(stacksize < kMaxThreadStackSize); // Sanity check. 223 CHECK(AddrIsInStack((uptr)&attr)); 224} 225 226AsanLock::AsanLock(LinkerInitialized) { 227 // We assume that pthread_mutex_t initialized to all zeroes is a valid 228 // unlocked mutex. We can not use PTHREAD_MUTEX_INITIALIZER as it triggers 229 // a gcc warning: 230 // extended initializer lists only available with -std=c++0x or -std=gnu++0x 231} 232 233void AsanLock::Lock() { 234 CHECK(sizeof(pthread_mutex_t) <= sizeof(opaque_storage_)); 235 pthread_mutex_lock((pthread_mutex_t*)&opaque_storage_); 236 CHECK(!owner_); 237 owner_ = (uptr)pthread_self(); 238} 239 240void AsanLock::Unlock() { 241 CHECK(owner_ == (uptr)pthread_self()); 242 owner_ = 0; 243 pthread_mutex_unlock((pthread_mutex_t*)&opaque_storage_); 244} 245 246#ifdef __arm__ 247#define UNWIND_STOP _URC_END_OF_STACK 248#define UNWIND_CONTINUE _URC_NO_REASON 249#else 250#define UNWIND_STOP _URC_NORMAL_STOP 251#define UNWIND_CONTINUE _URC_NO_REASON 252#endif 253 254uptr Unwind_GetIP(struct _Unwind_Context *ctx) { 255#ifdef __arm__ 256 uptr val; 257 _Unwind_VRS_Result res = _Unwind_VRS_Get(ctx, _UVRSC_CORE, 258 15 /* r15 = PC */, _UVRSD_UINT32, &val); 259 CHECK(res == _UVRSR_OK && "_Unwind_VRS_Get failed"); 260 // Clear the Thumb bit. 261 return val & ~(uptr)1; 262#else 263 return _Unwind_GetIP(ctx); 264#endif 265} 266 267_Unwind_Reason_Code Unwind_Trace(struct _Unwind_Context *ctx, 268 void *param) { 269 AsanStackTrace *b = (AsanStackTrace*)param; 270 CHECK(b->size < b->max_size); 271 uptr pc = Unwind_GetIP(ctx); 272 b->trace[b->size++] = pc; 273 if (b->size == b->max_size) return UNWIND_STOP; 274 return UNWIND_CONTINUE; 275} 276 277void AsanStackTrace::GetStackTrace(uptr max_s, uptr pc, uptr bp) { 278 size = 0; 279 trace[0] = pc; 280 if ((max_s) > 1) { 281 max_size = max_s; 282#ifdef __arm__ 283 _Unwind_Backtrace(Unwind_Trace, this); 284#else 285 FastUnwindStack(pc, bp); 286#endif 287 } 288} 289 290} // namespace __asan 291 292#endif // __linux__ 293