asan_linux.cc revision 6f350e0d1c385189cb94ddde7b288a2533b45b32
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 38extern "C" void* _DYNAMIC; 39 40namespace __asan { 41 42const size_t kMaxThreadStackSize = 256 * (1 << 20); // 256M 43 44void *AsanDoesNotSupportStaticLinkage() { 45 // This will fail to link with -static. 46 return &_DYNAMIC; // defined in link.h 47} 48 49bool AsanShadowRangeIsAvailable() { 50 // FIXME: shall we need anything here on Linux? 51 return true; 52} 53 54void GetPcSpBp(void *context, uintptr_t *pc, uintptr_t *sp, uintptr_t *bp) { 55#ifdef ANDROID 56 *pc = *sp = *bp = 0; 57#elif defined(__arm__) 58 ucontext_t *ucontext = (ucontext_t*)context; 59 *pc = ucontext->uc_mcontext.arm_pc; 60 *bp = ucontext->uc_mcontext.arm_fp; 61 *sp = ucontext->uc_mcontext.arm_sp; 62# elif defined(__x86_64__) 63 ucontext_t *ucontext = (ucontext_t*)context; 64 *pc = ucontext->uc_mcontext.gregs[REG_RIP]; 65 *bp = ucontext->uc_mcontext.gregs[REG_RBP]; 66 *sp = ucontext->uc_mcontext.gregs[REG_RSP]; 67# elif defined(__i386__) 68 ucontext_t *ucontext = (ucontext_t*)context; 69 *pc = ucontext->uc_mcontext.gregs[REG_EIP]; 70 *bp = ucontext->uc_mcontext.gregs[REG_EBP]; 71 *sp = ucontext->uc_mcontext.gregs[REG_ESP]; 72#else 73# error "Unsupported arch" 74#endif 75} 76 77bool AsanInterceptsSignal(int signum) { 78 return signum == SIGSEGV && FLAG_handle_segv; 79} 80 81static void *asan_mmap(void *addr, size_t length, int prot, int flags, 82 int fd, uint64_t offset) { 83# if __WORDSIZE == 64 84 return (void *)syscall(__NR_mmap, addr, length, prot, flags, fd, offset); 85# else 86 return (void *)syscall(__NR_mmap2, addr, length, prot, flags, fd, offset); 87# endif 88} 89 90void *AsanMmapSomewhereOrDie(size_t size, const char *mem_type) { 91 size = RoundUpTo(size, kPageSize); 92 void *res = asan_mmap(0, size, 93 PROT_READ | PROT_WRITE, 94 MAP_PRIVATE | MAP_ANON, -1, 0); 95 if (res == (void*)-1) { 96 OutOfMemoryMessageAndDie(mem_type, size); 97 } 98 return res; 99} 100 101void *AsanMmapFixedNoReserve(uintptr_t fixed_addr, size_t size) { 102 return asan_mmap((void*)fixed_addr, size, 103 PROT_READ | PROT_WRITE, 104 MAP_PRIVATE | MAP_ANON | MAP_FIXED | MAP_NORESERVE, 105 0, 0); 106} 107 108void *AsanMprotect(uintptr_t fixed_addr, size_t size) { 109 return asan_mmap((void*)fixed_addr, size, 110 PROT_NONE, 111 MAP_PRIVATE | MAP_ANON | MAP_FIXED | MAP_NORESERVE, 112 0, 0); 113} 114 115void AsanUnmapOrDie(void *addr, size_t size) { 116 if (!addr || !size) return; 117 int res = syscall(__NR_munmap, addr, size); 118 if (res != 0) { 119 Report("Failed to unmap\n"); 120 AsanDie(); 121 } 122} 123 124size_t AsanWrite(int fd, const void *buf, size_t count) { 125 return (size_t)syscall(__NR_write, fd, buf, count); 126} 127 128int AsanOpenReadonly(const char* filename) { 129 return syscall(__NR_open, filename, O_RDONLY); 130} 131 132// Like getenv, but reads env directly from /proc and does not use libc. 133// This function should be called first inside __asan_init. 134const char* AsanGetEnv(const char* name) { 135 static char *environ; 136 static size_t len; 137 static bool inited; 138 if (!inited) { 139 inited = true; 140 size_t environ_size; 141 len = ReadFileToBuffer("/proc/self/environ", 142 &environ, &environ_size, 1 << 26); 143 } 144 if (!environ || len == 0) return NULL; 145 size_t namelen = internal_strlen(name); 146 const char *p = environ; 147 while (*p != '\0') { // will happen at the \0\0 that terminates the buffer 148 // proc file has the format NAME=value\0NAME=value\0NAME=value\0... 149 const char* endp = 150 (char*)internal_memchr(p, '\0', len - (p - environ)); 151 if (endp == NULL) // this entry isn't NUL terminated 152 return NULL; 153 else if (!internal_memcmp(p, name, namelen) && p[namelen] == '=') // Match. 154 return p + namelen + 1; // point after = 155 p = endp + 1; 156 } 157 return NULL; // Not found. 158} 159 160size_t AsanRead(int fd, void *buf, size_t count) { 161 return (size_t)syscall(__NR_read, fd, buf, count); 162} 163 164int AsanClose(int fd) { 165 return syscall(__NR_close, fd); 166} 167 168AsanProcMaps::AsanProcMaps() { 169 proc_self_maps_buff_len_ = 170 ReadFileToBuffer("/proc/self/maps", &proc_self_maps_buff_, 171 &proc_self_maps_buff_mmaped_size_, 1 << 26); 172 CHECK(proc_self_maps_buff_len_ > 0); 173 // AsanWrite(2, proc_self_maps_buff_, proc_self_maps_buff_len_); 174 Reset(); 175} 176 177AsanProcMaps::~AsanProcMaps() { 178 AsanUnmapOrDie(proc_self_maps_buff_, proc_self_maps_buff_mmaped_size_); 179} 180 181void AsanProcMaps::Reset() { 182 current_ = proc_self_maps_buff_; 183} 184 185bool AsanProcMaps::Next(uintptr_t *start, uintptr_t *end, 186 uintptr_t *offset, char filename[], 187 size_t filename_size) { 188 char *last = proc_self_maps_buff_ + proc_self_maps_buff_len_; 189 if (current_ >= last) return false; 190 int consumed = 0; 191 char flags[10]; 192 int major, minor; 193 uintptr_t inode; 194 char *next_line = (char*)internal_memchr(current_, '\n', last - current_); 195 if (next_line == NULL) 196 next_line = last; 197 if (SScanf(current_, 198 "%lx-%lx %4s %lx %x:%x %ld %n", 199 start, end, flags, offset, &major, &minor, 200 &inode, &consumed) != 7) 201 return false; 202 current_ += consumed; 203 // Skip spaces. 204 while (current_ < next_line && *current_ == ' ') 205 current_++; 206 // Fill in the filename. 207 size_t i = 0; 208 while (current_ < next_line) { 209 if (filename && i < filename_size - 1) 210 filename[i++] = *current_; 211 current_++; 212 } 213 if (filename && i < filename_size) 214 filename[i] = 0; 215 current_ = next_line + 1; 216 return true; 217} 218 219#if 1 220 221// Gets the object name and the offset by walking AsanProcMaps. 222bool AsanProcMaps::GetObjectNameAndOffset(uintptr_t addr, uintptr_t *offset, 223 char filename[], 224 size_t filename_size) { 225 return IterateForObjectNameAndOffset(addr, offset, filename, filename_size); 226} 227 228#else 229// dl_iterate_phdr machinery is not working well for us. 230// We either need to fix it or get rid of it. 231struct DlIterateData { 232 int count; 233 uintptr_t addr; 234 uintptr_t offset; 235 char *filename; 236 size_t filename_size; 237}; 238 239static int dl_iterate_phdr_callback(struct dl_phdr_info *info, 240 size_t size, void *raw_data) { 241 DlIterateData *data = (DlIterateData*)raw_data; 242 int count = data->count++; 243 if (info->dlpi_addr > data->addr) 244 return 0; 245 if (count == 0) { 246 // The first item (the main executable) does not have a so name, 247 // but we can just read it from /proc/self/exe. 248 size_t path_len = readlink("/proc/self/exe", 249 data->filename, data->filename_size - 1); 250 data->filename[path_len] = 0; 251 } else { 252 CHECK(info->dlpi_name); 253 REAL(strncpy)(data->filename, info->dlpi_name, data->filename_size); 254 } 255 data->offset = data->addr - info->dlpi_addr; 256 return 1; 257} 258 259// Gets the object name and the offset using dl_iterate_phdr. 260bool AsanProcMaps::GetObjectNameAndOffset(uintptr_t addr, uintptr_t *offset, 261 char filename[], 262 size_t filename_size) { 263 DlIterateData data; 264 data.count = 0; 265 data.addr = addr; 266 data.filename = filename; 267 data.filename_size = filename_size; 268 if (dl_iterate_phdr(dl_iterate_phdr_callback, &data)) { 269 *offset = data.offset; 270 return true; 271 } 272 return false; 273} 274 275#endif // __arm__ 276 277void AsanThread::SetThreadStackTopAndBottom() { 278 if (tid() == 0) { 279 // This is the main thread. Libpthread may not be initialized yet. 280 struct rlimit rl; 281 CHECK(getrlimit(RLIMIT_STACK, &rl) == 0); 282 283 // Find the mapping that contains a stack variable. 284 AsanProcMaps proc_maps; 285 uintptr_t start, end, offset; 286 uintptr_t prev_end = 0; 287 while (proc_maps.Next(&start, &end, &offset, NULL, 0)) { 288 if ((uintptr_t)&rl < end) 289 break; 290 prev_end = end; 291 } 292 CHECK((uintptr_t)&rl >= start && (uintptr_t)&rl < end); 293 294 // Get stacksize from rlimit, but clip it so that it does not overlap 295 // with other mappings. 296 size_t stacksize = rl.rlim_cur; 297 if (stacksize > end - prev_end) 298 stacksize = end - prev_end; 299 // When running with unlimited stack size, we still want to set some limit. 300 // The unlimited stack size is caused by 'ulimit -s unlimited'. 301 // Also, for some reason, GNU make spawns subrocesses with unlimited stack. 302 if (stacksize > kMaxThreadStackSize) 303 stacksize = kMaxThreadStackSize; 304 stack_top_ = end; 305 stack_bottom_ = end - stacksize; 306 CHECK(AddrIsInStack((uintptr_t)&rl)); 307 return; 308 } 309 pthread_attr_t attr; 310 CHECK(pthread_getattr_np(pthread_self(), &attr) == 0); 311 size_t stacksize = 0; 312 void *stackaddr = NULL; 313 pthread_attr_getstack(&attr, &stackaddr, &stacksize); 314 pthread_attr_destroy(&attr); 315 316 stack_top_ = (uintptr_t)stackaddr + stacksize; 317 stack_bottom_ = (uintptr_t)stackaddr; 318 CHECK(stacksize < kMaxThreadStackSize); // Sanity check. 319 CHECK(AddrIsInStack((uintptr_t)&attr)); 320} 321 322AsanLock::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 329void 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 336void 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 350uintptr_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 373void 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