asan_linux.cc revision 47657ce6cbac2fa93d0fd765c5d2872443b50e87
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 *AsanMmapSomewhereOrDie(uptr size, const char *mem_type) { 78 size = RoundUpTo(size, kPageSize); 79 void *res = internal_mmap(0, size, 80 PROT_READ | PROT_WRITE, 81 MAP_PRIVATE | MAP_ANON, -1, 0); 82 if (res == (void*)-1) { 83 OutOfMemoryMessageAndDie(mem_type, size); 84 } 85 return res; 86} 87 88void *AsanMmapFixedNoReserve(uptr fixed_addr, uptr size) { 89 return internal_mmap((void*)fixed_addr, size, 90 PROT_READ | PROT_WRITE, 91 MAP_PRIVATE | MAP_ANON | MAP_FIXED | MAP_NORESERVE, 92 0, 0); 93} 94 95void *AsanMprotect(uptr fixed_addr, uptr size) { 96 return internal_mmap((void*)fixed_addr, size, 97 PROT_NONE, 98 MAP_PRIVATE | MAP_ANON | MAP_FIXED | MAP_NORESERVE, 99 0, 0); 100} 101 102void AsanUnmapOrDie(void *addr, uptr size) { 103 if (!addr || !size) return; 104 int res = internal_munmap(addr, size); 105 if (res != 0) { 106 Report("Failed to unmap\n"); 107 Die(); 108 } 109} 110 111// Like getenv, but reads env directly from /proc and does not use libc. 112// This function should be called first inside __asan_init. 113const char* AsanGetEnv(const char* name) { 114 static char *environ; 115 static uptr len; 116 static bool inited; 117 if (!inited) { 118 inited = true; 119 uptr environ_size; 120 len = ReadFileToBuffer("/proc/self/environ", 121 &environ, &environ_size, 1 << 26); 122 } 123 if (!environ || len == 0) return 0; 124 uptr namelen = internal_strlen(name); 125 const char *p = environ; 126 while (*p != '\0') { // will happen at the \0\0 that terminates the buffer 127 // proc file has the format NAME=value\0NAME=value\0NAME=value\0... 128 const char* endp = 129 (char*)internal_memchr(p, '\0', len - (p - environ)); 130 if (endp == 0) // this entry isn't NUL terminated 131 return 0; 132 else if (!internal_memcmp(p, name, namelen) && p[namelen] == '=') // Match. 133 return p + namelen + 1; // point after = 134 p = endp + 1; 135 } 136 return 0; // Not found. 137} 138 139AsanProcMaps::AsanProcMaps() { 140 proc_self_maps_buff_len_ = 141 ReadFileToBuffer("/proc/self/maps", &proc_self_maps_buff_, 142 &proc_self_maps_buff_mmaped_size_, 1 << 26); 143 CHECK(proc_self_maps_buff_len_ > 0); 144 // internal_write(2, proc_self_maps_buff_, proc_self_maps_buff_len_); 145 Reset(); 146} 147 148AsanProcMaps::~AsanProcMaps() { 149 AsanUnmapOrDie(proc_self_maps_buff_, proc_self_maps_buff_mmaped_size_); 150} 151 152void AsanProcMaps::Reset() { 153 current_ = proc_self_maps_buff_; 154} 155 156bool AsanProcMaps::Next(uptr *start, uptr *end, 157 uptr *offset, char filename[], 158 uptr filename_size) { 159 char *last = proc_self_maps_buff_ + proc_self_maps_buff_len_; 160 if (current_ >= last) return false; 161 int consumed = 0; 162 char flags[10]; 163 int major, minor; 164 uptr inode; 165 uptr dummy; 166 if (!start) start = &dummy; 167 if (!end) end = &dummy; 168 if (!offset) offset = &dummy; 169 char *next_line = (char*)internal_memchr(current_, '\n', last - current_); 170 if (next_line == 0) 171 next_line = last; 172 if (internal_sscanf(current_, 173 "%lx-%lx %4s %lx %x:%x %ld %n", 174 start, end, flags, offset, &major, &minor, 175 &inode, &consumed) != 7) 176 return false; 177 current_ += consumed; 178 // Skip spaces. 179 while (current_ < next_line && *current_ == ' ') 180 current_++; 181 // Fill in the filename. 182 uptr i = 0; 183 while (current_ < next_line) { 184 if (filename && i < filename_size - 1) 185 filename[i++] = *current_; 186 current_++; 187 } 188 if (filename && i < filename_size) 189 filename[i] = 0; 190 current_ = next_line + 1; 191 return true; 192} 193 194// Gets the object name and the offset by walking AsanProcMaps. 195bool AsanProcMaps::GetObjectNameAndOffset(uptr addr, uptr *offset, 196 char filename[], 197 uptr filename_size) { 198 return IterateForObjectNameAndOffset(addr, offset, filename, filename_size); 199} 200 201void AsanThread::SetThreadStackTopAndBottom() { 202 if (tid() == 0) { 203 // This is the main thread. Libpthread may not be initialized yet. 204 struct rlimit rl; 205 CHECK(getrlimit(RLIMIT_STACK, &rl) == 0); 206 207 // Find the mapping that contains a stack variable. 208 AsanProcMaps proc_maps; 209 uptr start, end, offset; 210 uptr prev_end = 0; 211 while (proc_maps.Next(&start, &end, &offset, 0, 0)) { 212 if ((uptr)&rl < end) 213 break; 214 prev_end = end; 215 } 216 CHECK((uptr)&rl >= start && (uptr)&rl < end); 217 218 // Get stacksize from rlimit, but clip it so that it does not overlap 219 // with other mappings. 220 uptr stacksize = rl.rlim_cur; 221 if (stacksize > end - prev_end) 222 stacksize = end - prev_end; 223 // When running with unlimited stack size, we still want to set some limit. 224 // The unlimited stack size is caused by 'ulimit -s unlimited'. 225 // Also, for some reason, GNU make spawns subprocesses with unlimited stack. 226 if (stacksize > kMaxThreadStackSize) 227 stacksize = kMaxThreadStackSize; 228 stack_top_ = end; 229 stack_bottom_ = end - stacksize; 230 CHECK(AddrIsInStack((uptr)&rl)); 231 return; 232 } 233 pthread_attr_t attr; 234 CHECK(pthread_getattr_np(pthread_self(), &attr) == 0); 235 uptr stacksize = 0; 236 void *stackaddr = 0; 237 pthread_attr_getstack(&attr, &stackaddr, (size_t*)&stacksize); 238 pthread_attr_destroy(&attr); 239 240 stack_top_ = (uptr)stackaddr + stacksize; 241 stack_bottom_ = (uptr)stackaddr; 242 CHECK(stacksize < kMaxThreadStackSize); // Sanity check. 243 CHECK(AddrIsInStack((uptr)&attr)); 244} 245 246AsanLock::AsanLock(LinkerInitialized) { 247 // We assume that pthread_mutex_t initialized to all zeroes is a valid 248 // unlocked mutex. We can not use PTHREAD_MUTEX_INITIALIZER as it triggers 249 // a gcc warning: 250 // extended initializer lists only available with -std=c++0x or -std=gnu++0x 251} 252 253void AsanLock::Lock() { 254 CHECK(sizeof(pthread_mutex_t) <= sizeof(opaque_storage_)); 255 pthread_mutex_lock((pthread_mutex_t*)&opaque_storage_); 256 CHECK(!owner_); 257 owner_ = (uptr)pthread_self(); 258} 259 260void AsanLock::Unlock() { 261 CHECK(owner_ == (uptr)pthread_self()); 262 owner_ = 0; 263 pthread_mutex_unlock((pthread_mutex_t*)&opaque_storage_); 264} 265 266#ifdef __arm__ 267#define UNWIND_STOP _URC_END_OF_STACK 268#define UNWIND_CONTINUE _URC_NO_REASON 269#else 270#define UNWIND_STOP _URC_NORMAL_STOP 271#define UNWIND_CONTINUE _URC_NO_REASON 272#endif 273 274uptr Unwind_GetIP(struct _Unwind_Context *ctx) { 275#ifdef __arm__ 276 uptr val; 277 _Unwind_VRS_Result res = _Unwind_VRS_Get(ctx, _UVRSC_CORE, 278 15 /* r15 = PC */, _UVRSD_UINT32, &val); 279 CHECK(res == _UVRSR_OK && "_Unwind_VRS_Get failed"); 280 // Clear the Thumb bit. 281 return val & ~(uptr)1; 282#else 283 return _Unwind_GetIP(ctx); 284#endif 285} 286 287_Unwind_Reason_Code Unwind_Trace(struct _Unwind_Context *ctx, 288 void *param) { 289 AsanStackTrace *b = (AsanStackTrace*)param; 290 CHECK(b->size < b->max_size); 291 uptr pc = Unwind_GetIP(ctx); 292 b->trace[b->size++] = pc; 293 if (b->size == b->max_size) return UNWIND_STOP; 294 return UNWIND_CONTINUE; 295} 296 297void AsanStackTrace::GetStackTrace(uptr max_s, uptr pc, uptr bp) { 298 size = 0; 299 trace[0] = pc; 300 if ((max_s) > 1) { 301 max_size = max_s; 302#ifdef __arm__ 303 _Unwind_Backtrace(Unwind_Trace, this); 304#else 305 FastUnwindStack(pc, bp); 306#endif 307 } 308} 309 310} // namespace __asan 311 312#endif // __linux__ 313