asan_linux.cc revision c549dd7b5fa5fb97270f57067797224cee0429f2
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_procmaps.h" 19#include "asan_thread.h" 20 21#include <sys/time.h> 22#include <sys/resource.h> 23#include <sys/mman.h> 24#include <sys/syscall.h> 25#include <sys/types.h> 26#include <fcntl.h> 27#include <pthread.h> 28#include <stdio.h> 29#include <unistd.h> 30 31extern char _DYNAMIC[]; 32 33namespace __asan { 34 35void *AsanDoesNotSupportStaticLinkage() { 36 // This will fail to link with -static. 37 return &_DYNAMIC; 38} 39 40static void *asan_mmap(void *addr, size_t length, int prot, int flags, 41 int fd, uint64_t offset) { 42# if __WORDSIZE == 64 43 return (void *)syscall(__NR_mmap, addr, length, prot, flags, fd, offset); 44# else 45 return (void *)syscall(__NR_mmap2, addr, length, prot, flags, fd, offset); 46# endif 47} 48 49void *AsanMmapSomewhereOrDie(size_t size, const char *mem_type) { 50 size = RoundUpTo(size, kPageSize); 51 void *res = asan_mmap(0, size, 52 PROT_READ | PROT_WRITE, 53 MAP_PRIVATE | MAP_ANON, -1, 0); 54 if (res == (void*)-1) { 55 OutOfMemoryMessageAndDie(mem_type, size); 56 } 57 return res; 58} 59 60void *AsanMmapFixedNoReserve(uintptr_t fixed_addr, size_t size) { 61 return asan_mmap((void*)fixed_addr, size, 62 PROT_READ | PROT_WRITE, 63 MAP_PRIVATE | MAP_ANON | MAP_FIXED | MAP_NORESERVE, 64 0, 0); 65} 66 67void *AsanMmapFixedReserve(uintptr_t fixed_addr, size_t size) { 68 return asan_mmap((void*)fixed_addr, size, 69 PROT_READ | PROT_WRITE, 70 MAP_PRIVATE | MAP_ANON | MAP_FIXED, 71 0, 0); 72} 73 74void *AsanMprotect(uintptr_t fixed_addr, size_t size) { 75 return asan_mmap((void*)fixed_addr, size, 76 PROT_NONE, 77 MAP_PRIVATE | MAP_ANON | MAP_FIXED | MAP_NORESERVE, 78 0, 0); 79} 80 81void AsanUnmapOrDie(void *addr, size_t size) { 82 if (!addr || !size) return; 83 int res = syscall(__NR_munmap, addr, size); 84 if (res != 0) { 85 Report("Failed to unmap\n"); 86 ASAN_DIE; 87 } 88} 89 90ssize_t AsanWrite(int fd, const void *buf, size_t count) { 91 return (ssize_t)syscall(__NR_write, fd, buf, count); 92} 93 94int AsanOpenReadonly(const char* filename) { 95 return open(filename, O_RDONLY); 96} 97 98ssize_t AsanRead(int fd, void *buf, size_t count) { 99 return (ssize_t)syscall(__NR_read, fd, buf, count); 100} 101 102int AsanClose(int fd) { 103 return close(fd); 104} 105 106AsanProcMaps::AsanProcMaps() { 107 proc_self_maps_buff_len_ = 108 ReadFileToBuffer("/proc/self/maps", &proc_self_maps_buff_, 109 &proc_self_maps_buff_mmaped_size_, 1 << 20); 110 CHECK(proc_self_maps_buff_len_ > 0); 111 // AsanWrite(2, proc_self_maps_buff_, proc_self_maps_buff_len_); 112 Reset(); 113} 114 115AsanProcMaps::~AsanProcMaps() { 116 AsanUnmapOrDie(proc_self_maps_buff_, proc_self_maps_buff_mmaped_size_); 117} 118 119void AsanProcMaps::Reset() { 120 current_ = proc_self_maps_buff_; 121} 122 123bool AsanProcMaps::Next(uint64_t *start, uint64_t *end, 124 uint64_t *offset, char filename[], 125 size_t filename_size) { 126 char *last = proc_self_maps_buff_ + proc_self_maps_buff_len_; 127 if (current_ >= last) return false; 128 int consumed = 0; 129 char flags[10]; 130 int major, minor; 131 uint64_t inode; 132 char *next_line = (char*)internal_memchr(current_, '\n', last - current_); 133 if (next_line == NULL) 134 next_line = last; 135 if (SScanf(current_, 136 "%llx-%llx %4s %llx %x:%x %lld %n", 137 start, end, flags, offset, &major, &minor, 138 &inode, &consumed) != 7) 139 return false; 140 current_ += consumed; 141 // Skip spaces. 142 while (current_ < next_line && *current_ == ' ') 143 current_++; 144 // Fill in the filename. 145 size_t i = 0; 146 while (current_ < next_line) { 147 if (filename && i < filename_size - 1) 148 filename[i++] = *current_; 149 current_++; 150 } 151 if (filename && i < filename_size) 152 filename[i] = 0; 153 current_ = next_line + 1; 154 return true; 155} 156 157void AsanThread::SetThreadStackTopAndBottom() { 158 if (tid() == 0) { 159 // This is the main thread. Libpthread may not be initialized yet. 160 struct rlimit rl; 161 CHECK(getrlimit(RLIMIT_STACK, &rl) == 0); 162 163 // Find the mapping that contains a stack variable. 164 AsanProcMaps proc_maps; 165 uint64_t start, end, offset; 166 uint64_t prev_end = 0; 167 while (proc_maps.Next(&start, &end, &offset, NULL, 0)) { 168 if ((uintptr_t)&rl < end) 169 break; 170 prev_end = end; 171 } 172 CHECK((uintptr_t)&rl >= start && (uintptr_t)&rl < end); 173 174 // Get stacksize from rlimit, but clip it so that it does not overlap 175 // with other mappings. 176 size_t stacksize = rl.rlim_cur; 177 if (stacksize > end - prev_end) 178 stacksize = end - prev_end; 179 if (stacksize > kMaxThreadStackSize) 180 stacksize = kMaxThreadStackSize; 181 stack_top_ = end; 182 stack_bottom_ = end - stacksize; 183 CHECK(AddrIsInStack((uintptr_t)&rl)); 184 return; 185 } 186 pthread_attr_t attr; 187 CHECK(pthread_getattr_np(pthread_self(), &attr) == 0); 188 size_t stacksize = 0; 189 void *stackaddr = NULL; 190 pthread_attr_getstack(&attr, &stackaddr, &stacksize); 191 pthread_attr_destroy(&attr); 192 193 stack_top_ = (uintptr_t)stackaddr + stacksize; 194 stack_bottom_ = (uintptr_t)stackaddr; 195 // When running with unlimited stack size, we still want to set some limit. 196 // The unlimited stack size is caused by 'ulimit -s unlimited'. 197 // Also, for some reason, GNU make spawns subrocesses with unlimited stack. 198 if (stacksize > kMaxThreadStackSize) { 199 stack_bottom_ = stack_top_ - kMaxThreadStackSize; 200 } 201 CHECK(AddrIsInStack((uintptr_t)&attr)); 202} 203 204 205} // namespace __asan 206 207#endif // __linux__ 208