1 //===-- sanitizer_posix.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 shared between AddressSanitizer and ThreadSanitizer 11 // run-time libraries and implements POSIX-specific functions from 12 // sanitizer_posix.h. 13 //===----------------------------------------------------------------------===// 14 15 #include "sanitizer_platform.h" 16 17 #if SANITIZER_POSIX 18 19 #include "sanitizer_common.h" 20 #include "sanitizer_libc.h" 21 #include "sanitizer_posix.h" 22 #include "sanitizer_procmaps.h" 23 #include "sanitizer_stacktrace.h" 24 25 #include <fcntl.h> 26 #include <signal.h> 27 #include <sys/mman.h> 28 29 #if SANITIZER_LINUX 30 #include <sys/utsname.h> 31 #endif 32 33 #if SANITIZER_LINUX && !SANITIZER_ANDROID 34 #include <sys/personality.h> 35 #endif 36 37 #if SANITIZER_FREEBSD 38 // The MAP_NORESERVE define has been removed in FreeBSD 11.x, and even before 39 // that, it was never implemented. So just define it to zero. 40 #undef MAP_NORESERVE 41 #define MAP_NORESERVE 0 42 #endif 43 44 namespace __sanitizer { 45 46 // ------------- sanitizer_common.h 47 uptr GetMmapGranularity() { 48 return GetPageSize(); 49 } 50 51 #if SANITIZER_WORDSIZE == 32 52 // Take care of unusable kernel area in top gigabyte. 53 static uptr GetKernelAreaSize() { 54 #if SANITIZER_LINUX && !SANITIZER_X32 55 const uptr gbyte = 1UL << 30; 56 57 // Firstly check if there are writable segments 58 // mapped to top gigabyte (e.g. stack). 59 MemoryMappingLayout proc_maps(/*cache_enabled*/true); 60 uptr end, prot; 61 while (proc_maps.Next(/*start*/nullptr, &end, 62 /*offset*/nullptr, /*filename*/nullptr, 63 /*filename_size*/0, &prot)) { 64 if ((end >= 3 * gbyte) 65 && (prot & MemoryMappingLayout::kProtectionWrite) != 0) 66 return 0; 67 } 68 69 #if !SANITIZER_ANDROID 70 // Even if nothing is mapped, top Gb may still be accessible 71 // if we are running on 64-bit kernel. 72 // Uname may report misleading results if personality type 73 // is modified (e.g. under schroot) so check this as well. 74 struct utsname uname_info; 75 int pers = personality(0xffffffffUL); 76 if (!(pers & PER_MASK) 77 && uname(&uname_info) == 0 78 && internal_strstr(uname_info.machine, "64")) 79 return 0; 80 #endif // SANITIZER_ANDROID 81 82 // Top gigabyte is reserved for kernel. 83 return gbyte; 84 #else 85 return 0; 86 #endif // SANITIZER_LINUX && !SANITIZER_X32 87 } 88 #endif // SANITIZER_WORDSIZE == 32 89 90 uptr GetMaxVirtualAddress() { 91 #if SANITIZER_WORDSIZE == 64 92 # if defined(__aarch64__) && SANITIZER_IOS && !SANITIZER_IOSSIM 93 // Ideally, we would derive the upper bound from MACH_VM_MAX_ADDRESS. The 94 // upper bound can change depending on the device. 95 return 0x200000000 - 1; 96 # elif defined(__powerpc64__) || defined(__aarch64__) 97 // On PowerPC64 we have two different address space layouts: 44- and 46-bit. 98 // We somehow need to figure out which one we are using now and choose 99 // one of 0x00000fffffffffffUL and 0x00003fffffffffffUL. 100 // Note that with 'ulimit -s unlimited' the stack is moved away from the top 101 // of the address space, so simply checking the stack address is not enough. 102 // This should (does) work for both PowerPC64 Endian modes. 103 // Similarly, aarch64 has multiple address space layouts: 39, 42 and 47-bit. 104 return (1ULL << (MostSignificantSetBitIndex(GET_CURRENT_FRAME()) + 1)) - 1; 105 # elif defined(__mips64) 106 return (1ULL << 40) - 1; // 0x000000ffffffffffUL; 107 # elif defined(__s390x__) 108 return (1ULL << 53) - 1; // 0x001fffffffffffffUL; 109 # else 110 return (1ULL << 47) - 1; // 0x00007fffffffffffUL; 111 # endif 112 #else // SANITIZER_WORDSIZE == 32 113 # if defined(__s390__) 114 return (1ULL << 31) - 1; // 0x7fffffff; 115 # else 116 uptr res = (1ULL << 32) - 1; // 0xffffffff; 117 if (!common_flags()->full_address_space) 118 res -= GetKernelAreaSize(); 119 CHECK_LT(reinterpret_cast<uptr>(&res), res); 120 return res; 121 # endif 122 #endif // SANITIZER_WORDSIZE 123 } 124 125 void *MmapOrDie(uptr size, const char *mem_type, bool raw_report) { 126 size = RoundUpTo(size, GetPageSizeCached()); 127 uptr res = internal_mmap(nullptr, size, 128 PROT_READ | PROT_WRITE, 129 MAP_PRIVATE | MAP_ANON, -1, 0); 130 int reserrno; 131 if (internal_iserror(res, &reserrno)) 132 ReportMmapFailureAndDie(size, mem_type, "allocate", reserrno, raw_report); 133 IncreaseTotalMmap(size); 134 return (void *)res; 135 } 136 137 void UnmapOrDie(void *addr, uptr size) { 138 if (!addr || !size) return; 139 uptr res = internal_munmap(addr, size); 140 if (internal_iserror(res)) { 141 Report("ERROR: %s failed to deallocate 0x%zx (%zd) bytes at address %p\n", 142 SanitizerToolName, size, size, addr); 143 CHECK("unable to unmap" && 0); 144 } 145 DecreaseTotalMmap(size); 146 } 147 148 // We want to map a chunk of address space aligned to 'alignment'. 149 // We do it by maping a bit more and then unmaping redundant pieces. 150 // We probably can do it with fewer syscalls in some OS-dependent way. 151 void *MmapAlignedOrDie(uptr size, uptr alignment, const char *mem_type) { 152 CHECK(IsPowerOfTwo(size)); 153 CHECK(IsPowerOfTwo(alignment)); 154 uptr map_size = size + alignment; 155 uptr map_res = (uptr)MmapOrDie(map_size, mem_type); 156 uptr map_end = map_res + map_size; 157 uptr res = map_res; 158 if (res & (alignment - 1)) // Not aligned. 159 res = (map_res + alignment) & ~(alignment - 1); 160 uptr end = res + size; 161 if (res != map_res) 162 UnmapOrDie((void*)map_res, res - map_res); 163 if (end != map_end) 164 UnmapOrDie((void*)end, map_end - end); 165 return (void*)res; 166 } 167 168 void *MmapNoReserveOrDie(uptr size, const char *mem_type) { 169 uptr PageSize = GetPageSizeCached(); 170 uptr p = internal_mmap(nullptr, 171 RoundUpTo(size, PageSize), 172 PROT_READ | PROT_WRITE, 173 MAP_PRIVATE | MAP_ANON | MAP_NORESERVE, 174 -1, 0); 175 int reserrno; 176 if (internal_iserror(p, &reserrno)) 177 ReportMmapFailureAndDie(size, mem_type, "allocate noreserve", reserrno); 178 IncreaseTotalMmap(size); 179 return (void *)p; 180 } 181 182 void *MmapFixedOrDie(uptr fixed_addr, uptr size) { 183 uptr PageSize = GetPageSizeCached(); 184 uptr p = internal_mmap((void*)(fixed_addr & ~(PageSize - 1)), 185 RoundUpTo(size, PageSize), 186 PROT_READ | PROT_WRITE, 187 MAP_PRIVATE | MAP_ANON | MAP_FIXED, 188 -1, 0); 189 int reserrno; 190 if (internal_iserror(p, &reserrno)) { 191 char mem_type[30]; 192 internal_snprintf(mem_type, sizeof(mem_type), "memory at address 0x%zx", 193 fixed_addr); 194 ReportMmapFailureAndDie(size, mem_type, "allocate", reserrno); 195 } 196 IncreaseTotalMmap(size); 197 return (void *)p; 198 } 199 200 bool MprotectNoAccess(uptr addr, uptr size) { 201 return 0 == internal_mprotect((void*)addr, size, PROT_NONE); 202 } 203 204 bool MprotectReadOnly(uptr addr, uptr size) { 205 return 0 == internal_mprotect((void *)addr, size, PROT_READ); 206 } 207 208 fd_t OpenFile(const char *filename, FileAccessMode mode, error_t *errno_p) { 209 int flags; 210 switch (mode) { 211 case RdOnly: flags = O_RDONLY; break; 212 case WrOnly: flags = O_WRONLY | O_CREAT; break; 213 case RdWr: flags = O_RDWR | O_CREAT; break; 214 } 215 fd_t res = internal_open(filename, flags, 0660); 216 if (internal_iserror(res, errno_p)) 217 return kInvalidFd; 218 return res; 219 } 220 221 void CloseFile(fd_t fd) { 222 internal_close(fd); 223 } 224 225 bool ReadFromFile(fd_t fd, void *buff, uptr buff_size, uptr *bytes_read, 226 error_t *error_p) { 227 uptr res = internal_read(fd, buff, buff_size); 228 if (internal_iserror(res, error_p)) 229 return false; 230 if (bytes_read) 231 *bytes_read = res; 232 return true; 233 } 234 235 bool WriteToFile(fd_t fd, const void *buff, uptr buff_size, uptr *bytes_written, 236 error_t *error_p) { 237 uptr res = internal_write(fd, buff, buff_size); 238 if (internal_iserror(res, error_p)) 239 return false; 240 if (bytes_written) 241 *bytes_written = res; 242 return true; 243 } 244 245 bool RenameFile(const char *oldpath, const char *newpath, error_t *error_p) { 246 uptr res = internal_rename(oldpath, newpath); 247 return !internal_iserror(res, error_p); 248 } 249 250 void *MapFileToMemory(const char *file_name, uptr *buff_size) { 251 fd_t fd = OpenFile(file_name, RdOnly); 252 CHECK(fd != kInvalidFd); 253 uptr fsize = internal_filesize(fd); 254 CHECK_NE(fsize, (uptr)-1); 255 CHECK_GT(fsize, 0); 256 *buff_size = RoundUpTo(fsize, GetPageSizeCached()); 257 uptr map = internal_mmap(nullptr, *buff_size, PROT_READ, MAP_PRIVATE, fd, 0); 258 return internal_iserror(map) ? nullptr : (void *)map; 259 } 260 261 void *MapWritableFileToMemory(void *addr, uptr size, fd_t fd, OFF_T offset) { 262 uptr flags = MAP_SHARED; 263 if (addr) flags |= MAP_FIXED; 264 uptr p = internal_mmap(addr, size, PROT_READ | PROT_WRITE, flags, fd, offset); 265 int mmap_errno = 0; 266 if (internal_iserror(p, &mmap_errno)) { 267 Printf("could not map writable file (%d, %lld, %zu): %zd, errno: %d\n", 268 fd, (long long)offset, size, p, mmap_errno); 269 return nullptr; 270 } 271 return (void *)p; 272 } 273 274 static inline bool IntervalsAreSeparate(uptr start1, uptr end1, 275 uptr start2, uptr end2) { 276 CHECK(start1 <= end1); 277 CHECK(start2 <= end2); 278 return (end1 < start2) || (end2 < start1); 279 } 280 281 // FIXME: this is thread-unsafe, but should not cause problems most of the time. 282 // When the shadow is mapped only a single thread usually exists (plus maybe 283 // several worker threads on Mac, which aren't expected to map big chunks of 284 // memory). 285 bool MemoryRangeIsAvailable(uptr range_start, uptr range_end) { 286 MemoryMappingLayout proc_maps(/*cache_enabled*/true); 287 uptr start, end; 288 while (proc_maps.Next(&start, &end, 289 /*offset*/nullptr, /*filename*/nullptr, 290 /*filename_size*/0, /*protection*/nullptr)) { 291 if (start == end) continue; // Empty range. 292 CHECK_NE(0, end); 293 if (!IntervalsAreSeparate(start, end - 1, range_start, range_end)) 294 return false; 295 } 296 return true; 297 } 298 299 void DumpProcessMap() { 300 MemoryMappingLayout proc_maps(/*cache_enabled*/true); 301 uptr start, end; 302 const sptr kBufSize = 4095; 303 char *filename = (char*)MmapOrDie(kBufSize, __func__); 304 Report("Process memory map follows:\n"); 305 while (proc_maps.Next(&start, &end, /* file_offset */nullptr, 306 filename, kBufSize, /* protection */nullptr)) { 307 Printf("\t%p-%p\t%s\n", (void*)start, (void*)end, filename); 308 } 309 Report("End of process memory map.\n"); 310 UnmapOrDie(filename, kBufSize); 311 } 312 313 const char *GetPwd() { 314 return GetEnv("PWD"); 315 } 316 317 bool IsPathSeparator(const char c) { 318 return c == '/'; 319 } 320 321 bool IsAbsolutePath(const char *path) { 322 return path != nullptr && IsPathSeparator(path[0]); 323 } 324 325 void ReportFile::Write(const char *buffer, uptr length) { 326 SpinMutexLock l(mu); 327 static const char *kWriteError = 328 "ReportFile::Write() can't output requested buffer!\n"; 329 ReopenIfNecessary(); 330 if (length != internal_write(fd, buffer, length)) { 331 internal_write(fd, kWriteError, internal_strlen(kWriteError)); 332 Die(); 333 } 334 } 335 336 bool GetCodeRangeForFile(const char *module, uptr *start, uptr *end) { 337 uptr s, e, off, prot; 338 InternalScopedString buff(kMaxPathLength); 339 MemoryMappingLayout proc_maps(/*cache_enabled*/false); 340 while (proc_maps.Next(&s, &e, &off, buff.data(), buff.size(), &prot)) { 341 if ((prot & MemoryMappingLayout::kProtectionExecute) != 0 342 && internal_strcmp(module, buff.data()) == 0) { 343 *start = s; 344 *end = e; 345 return true; 346 } 347 } 348 return false; 349 } 350 351 SignalContext SignalContext::Create(void *siginfo, void *context) { 352 auto si = (siginfo_t *)siginfo; 353 uptr addr = (uptr)si->si_addr; 354 uptr pc, sp, bp; 355 GetPcSpBp(context, &pc, &sp, &bp); 356 WriteFlag write_flag = GetWriteFlag(context); 357 bool is_memory_access = si->si_signo == SIGSEGV; 358 return SignalContext(context, addr, pc, sp, bp, is_memory_access, write_flag); 359 } 360 361 } // namespace __sanitizer 362 363 #endif // SANITIZER_POSIX 364