1 //===-- sanitizer_posix.cpp -----------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file is shared between AddressSanitizer and ThreadSanitizer 10 // run-time libraries and implements POSIX-specific functions from 11 // sanitizer_posix.h. 12 //===----------------------------------------------------------------------===// 13 14 #include "sanitizer_platform.h" 15 16 #if SANITIZER_POSIX 17 18 #include "sanitizer_common.h" 19 #include "sanitizer_file.h" 20 #include "sanitizer_flags.h" 21 #include "sanitizer_libc.h" 22 #include "sanitizer_posix.h" 23 #include "sanitizer_procmaps.h" 24 25 #include <errno.h> 26 #include <fcntl.h> 27 #include <signal.h> 28 #include <sys/mman.h> 29 30 #if SANITIZER_FREEBSD 31 // The MAP_NORESERVE define has been removed in FreeBSD 11.x, and even before 32 // that, it was never implemented. So just define it to zero. 33 #undef MAP_NORESERVE 34 #define MAP_NORESERVE 0 35 #endif 36 37 namespace __sanitizer { 38 39 // ------------- sanitizer_common.h 40 uptr GetMmapGranularity() { 41 return GetPageSize(); 42 } 43 44 void *MmapOrDie(uptr size, const char *mem_type, bool raw_report) { 45 size = RoundUpTo(size, GetPageSizeCached()); 46 uptr res = MmapNamed(nullptr, size, PROT_READ | PROT_WRITE, 47 MAP_PRIVATE | MAP_ANON, mem_type); 48 int reserrno; 49 if (UNLIKELY(internal_iserror(res, &reserrno))) 50 ReportMmapFailureAndDie(size, mem_type, "allocate", reserrno, raw_report); 51 IncreaseTotalMmap(size); 52 return (void *)res; 53 } 54 55 void UnmapOrDie(void *addr, uptr size) { 56 if (!addr || !size) return; 57 uptr res = internal_munmap(addr, size); 58 if (UNLIKELY(internal_iserror(res))) { 59 Report("ERROR: %s failed to deallocate 0x%zx (%zd) bytes at address %p\n", 60 SanitizerToolName, size, size, addr); 61 CHECK("unable to unmap" && 0); 62 } 63 DecreaseTotalMmap(size); 64 } 65 66 void *MmapOrDieOnFatalError(uptr size, const char *mem_type) { 67 size = RoundUpTo(size, GetPageSizeCached()); 68 uptr res = MmapNamed(nullptr, size, PROT_READ | PROT_WRITE, 69 MAP_PRIVATE | MAP_ANON, mem_type); 70 int reserrno; 71 if (UNLIKELY(internal_iserror(res, &reserrno))) { 72 if (reserrno == ENOMEM) 73 return nullptr; 74 ReportMmapFailureAndDie(size, mem_type, "allocate", reserrno); 75 } 76 IncreaseTotalMmap(size); 77 return (void *)res; 78 } 79 80 // We want to map a chunk of address space aligned to 'alignment'. 81 // We do it by mapping a bit more and then unmapping redundant pieces. 82 // We probably can do it with fewer syscalls in some OS-dependent way. 83 void *MmapAlignedOrDieOnFatalError(uptr size, uptr alignment, 84 const char *mem_type) { 85 CHECK(IsPowerOfTwo(size)); 86 CHECK(IsPowerOfTwo(alignment)); 87 uptr map_size = size + alignment; 88 uptr map_res = (uptr)MmapOrDieOnFatalError(map_size, mem_type); 89 if (UNLIKELY(!map_res)) 90 return nullptr; 91 uptr map_end = map_res + map_size; 92 uptr res = map_res; 93 if (!IsAligned(res, alignment)) { 94 res = (map_res + alignment - 1) & ~(alignment - 1); 95 UnmapOrDie((void*)map_res, res - map_res); 96 } 97 uptr end = res + size; 98 if (end != map_end) 99 UnmapOrDie((void*)end, map_end - end); 100 return (void*)res; 101 } 102 103 void *MmapNoReserveOrDie(uptr size, const char *mem_type) { 104 size = RoundUpTo(size, GetPageSizeCached()); 105 uptr p = MmapNamed(nullptr, size, PROT_READ | PROT_WRITE, 106 MAP_PRIVATE | MAP_ANON | MAP_NORESERVE, mem_type); 107 int reserrno; 108 if (UNLIKELY(internal_iserror(p, &reserrno))) 109 ReportMmapFailureAndDie(size, mem_type, "allocate noreserve", reserrno); 110 IncreaseTotalMmap(size); 111 return (void *)p; 112 } 113 114 static void *MmapFixedImpl(uptr fixed_addr, uptr size, bool tolerate_enomem, 115 const char *name) { 116 size = RoundUpTo(size, GetPageSizeCached()); 117 fixed_addr = RoundDownTo(fixed_addr, GetPageSizeCached()); 118 uptr p = MmapNamed((void *)fixed_addr, size, PROT_READ | PROT_WRITE, 119 MAP_PRIVATE | MAP_ANON | MAP_FIXED, name); 120 int reserrno; 121 if (UNLIKELY(internal_iserror(p, &reserrno))) { 122 if (tolerate_enomem && reserrno == ENOMEM) 123 return nullptr; 124 char mem_type[40]; 125 internal_snprintf(mem_type, sizeof(mem_type), "memory at address 0x%zx", 126 fixed_addr); 127 ReportMmapFailureAndDie(size, mem_type, "allocate", reserrno); 128 } 129 IncreaseTotalMmap(size); 130 return (void *)p; 131 } 132 133 void *MmapFixedOrDie(uptr fixed_addr, uptr size, const char *name) { 134 return MmapFixedImpl(fixed_addr, size, false /*tolerate_enomem*/, name); 135 } 136 137 void *MmapFixedOrDieOnFatalError(uptr fixed_addr, uptr size, const char *name) { 138 return MmapFixedImpl(fixed_addr, size, true /*tolerate_enomem*/, name); 139 } 140 141 bool MprotectNoAccess(uptr addr, uptr size) { 142 return 0 == internal_mprotect((void*)addr, size, PROT_NONE); 143 } 144 145 bool MprotectReadOnly(uptr addr, uptr size) { 146 return 0 == internal_mprotect((void *)addr, size, PROT_READ); 147 } 148 149 #if !SANITIZER_MAC 150 void MprotectMallocZones(void *addr, int prot) {} 151 #endif 152 153 fd_t OpenFile(const char *filename, FileAccessMode mode, error_t *errno_p) { 154 if (ShouldMockFailureToOpen(filename)) 155 return kInvalidFd; 156 int flags; 157 switch (mode) { 158 case RdOnly: flags = O_RDONLY; break; 159 case WrOnly: flags = O_WRONLY | O_CREAT | O_TRUNC; break; 160 case RdWr: flags = O_RDWR | O_CREAT; break; 161 } 162 fd_t res = internal_open(filename, flags, 0660); 163 if (internal_iserror(res, errno_p)) 164 return kInvalidFd; 165 return ReserveStandardFds(res); 166 } 167 168 void CloseFile(fd_t fd) { 169 internal_close(fd); 170 } 171 172 bool ReadFromFile(fd_t fd, void *buff, uptr buff_size, uptr *bytes_read, 173 error_t *error_p) { 174 uptr res = internal_read(fd, buff, buff_size); 175 if (internal_iserror(res, error_p)) 176 return false; 177 if (bytes_read) 178 *bytes_read = res; 179 return true; 180 } 181 182 bool WriteToFile(fd_t fd, const void *buff, uptr buff_size, uptr *bytes_written, 183 error_t *error_p) { 184 uptr res = internal_write(fd, buff, buff_size); 185 if (internal_iserror(res, error_p)) 186 return false; 187 if (bytes_written) 188 *bytes_written = res; 189 return true; 190 } 191 192 void *MapFileToMemory(const char *file_name, uptr *buff_size) { 193 fd_t fd = OpenFile(file_name, RdOnly); 194 CHECK(fd != kInvalidFd); 195 uptr fsize = internal_filesize(fd); 196 CHECK_NE(fsize, (uptr)-1); 197 CHECK_GT(fsize, 0); 198 *buff_size = RoundUpTo(fsize, GetPageSizeCached()); 199 uptr map = internal_mmap(nullptr, *buff_size, PROT_READ, MAP_PRIVATE, fd, 0); 200 return internal_iserror(map) ? nullptr : (void *)map; 201 } 202 203 void *MapWritableFileToMemory(void *addr, uptr size, fd_t fd, OFF_T offset) { 204 uptr flags = MAP_SHARED; 205 if (addr) flags |= MAP_FIXED; 206 uptr p = internal_mmap(addr, size, PROT_READ | PROT_WRITE, flags, fd, offset); 207 int mmap_errno = 0; 208 if (internal_iserror(p, &mmap_errno)) { 209 Printf("could not map writable file (%d, %lld, %zu): %zd, errno: %d\n", 210 fd, (long long)offset, size, p, mmap_errno); 211 return nullptr; 212 } 213 return (void *)p; 214 } 215 216 static inline bool IntervalsAreSeparate(uptr start1, uptr end1, 217 uptr start2, uptr end2) { 218 CHECK(start1 <= end1); 219 CHECK(start2 <= end2); 220 return (end1 < start2) || (end2 < start1); 221 } 222 223 // FIXME: this is thread-unsafe, but should not cause problems most of the time. 224 // When the shadow is mapped only a single thread usually exists (plus maybe 225 // several worker threads on Mac, which aren't expected to map big chunks of 226 // memory). 227 bool MemoryRangeIsAvailable(uptr range_start, uptr range_end) { 228 MemoryMappingLayout proc_maps(/*cache_enabled*/true); 229 if (proc_maps.Error()) 230 return true; // and hope for the best 231 MemoryMappedSegment segment; 232 while (proc_maps.Next(&segment)) { 233 if (segment.start == segment.end) continue; // Empty range. 234 CHECK_NE(0, segment.end); 235 if (!IntervalsAreSeparate(segment.start, segment.end - 1, range_start, 236 range_end)) 237 return false; 238 } 239 return true; 240 } 241 242 void DumpProcessMap() { 243 MemoryMappingLayout proc_maps(/*cache_enabled*/true); 244 const sptr kBufSize = 4095; 245 char *filename = (char*)MmapOrDie(kBufSize, __func__); 246 MemoryMappedSegment segment(filename, kBufSize); 247 Report("Process memory map follows:\n"); 248 while (proc_maps.Next(&segment)) { 249 Printf("\t%p-%p\t%s\n", (void *)segment.start, (void *)segment.end, 250 segment.filename); 251 } 252 Report("End of process memory map.\n"); 253 UnmapOrDie(filename, kBufSize); 254 } 255 256 const char *GetPwd() { 257 return GetEnv("PWD"); 258 } 259 260 bool IsPathSeparator(const char c) { 261 return c == '/'; 262 } 263 264 bool IsAbsolutePath(const char *path) { 265 return path != nullptr && IsPathSeparator(path[0]); 266 } 267 268 void ReportFile::Write(const char *buffer, uptr length) { 269 SpinMutexLock l(mu); 270 ReopenIfNecessary(); 271 internal_write(fd, buffer, length); 272 } 273 274 bool GetCodeRangeForFile(const char *module, uptr *start, uptr *end) { 275 MemoryMappingLayout proc_maps(/*cache_enabled*/false); 276 InternalScopedString buff(kMaxPathLength); 277 MemoryMappedSegment segment(buff.data(), kMaxPathLength); 278 while (proc_maps.Next(&segment)) { 279 if (segment.IsExecutable() && 280 internal_strcmp(module, segment.filename) == 0) { 281 *start = segment.start; 282 *end = segment.end; 283 return true; 284 } 285 } 286 return false; 287 } 288 289 uptr SignalContext::GetAddress() const { 290 auto si = static_cast<const siginfo_t *>(siginfo); 291 return (uptr)si->si_addr; 292 } 293 294 bool SignalContext::IsMemoryAccess() const { 295 auto si = static_cast<const siginfo_t *>(siginfo); 296 return si->si_signo == SIGSEGV; 297 } 298 299 int SignalContext::GetType() const { 300 return static_cast<const siginfo_t *>(siginfo)->si_signo; 301 } 302 303 const char *SignalContext::Describe() const { 304 switch (GetType()) { 305 case SIGFPE: 306 return "FPE"; 307 case SIGILL: 308 return "ILL"; 309 case SIGABRT: 310 return "ABRT"; 311 case SIGSEGV: 312 return "SEGV"; 313 case SIGBUS: 314 return "BUS"; 315 case SIGTRAP: 316 return "TRAP"; 317 } 318 return "UNKNOWN SIGNAL"; 319 } 320 321 fd_t ReserveStandardFds(fd_t fd) { 322 CHECK_GE(fd, 0); 323 if (fd > 2) 324 return fd; 325 bool used[3]; 326 internal_memset(used, 0, sizeof(used)); 327 while (fd <= 2) { 328 used[fd] = true; 329 fd = internal_dup(fd); 330 } 331 for (int i = 0; i <= 2; ++i) 332 if (used[i]) 333 internal_close(i); 334 return fd; 335 } 336 337 bool ShouldMockFailureToOpen(const char *path) { 338 return common_flags()->test_only_emulate_no_memorymap && 339 internal_strncmp(path, "/proc/", 6) == 0; 340 } 341 342 #if SANITIZER_LINUX && !SANITIZER_ANDROID && !SANITIZER_GO 343 int GetNamedMappingFd(const char *name, uptr size, int *flags) { 344 if (!common_flags()->decorate_proc_maps || !name) 345 return -1; 346 char shmname[200]; 347 CHECK(internal_strlen(name) < sizeof(shmname) - 10); 348 internal_snprintf(shmname, sizeof(shmname), "/dev/shm/%zu [%s]", 349 internal_getpid(), name); 350 int o_cloexec = 0; 351 #if defined(O_CLOEXEC) 352 o_cloexec = O_CLOEXEC; 353 #endif 354 int fd = ReserveStandardFds( 355 internal_open(shmname, O_RDWR | O_CREAT | O_TRUNC | o_cloexec, S_IRWXU)); 356 CHECK_GE(fd, 0); 357 if (!o_cloexec) { 358 int res = fcntl(fd, F_SETFD, FD_CLOEXEC); 359 CHECK_EQ(0, res); 360 } 361 int res = internal_ftruncate(fd, size); 362 CHECK_EQ(0, res); 363 res = internal_unlink(shmname); 364 CHECK_EQ(0, res); 365 *flags &= ~(MAP_ANON | MAP_ANONYMOUS); 366 return fd; 367 } 368 #else 369 int GetNamedMappingFd(const char *name, uptr size, int *flags) { 370 return -1; 371 } 372 #endif 373 374 #if SANITIZER_ANDROID 375 #define PR_SET_VMA 0x53564d41 376 #define PR_SET_VMA_ANON_NAME 0 377 void DecorateMapping(uptr addr, uptr size, const char *name) { 378 if (!common_flags()->decorate_proc_maps || !name) 379 return; 380 internal_prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, addr, size, (uptr)name); 381 } 382 #else 383 void DecorateMapping(uptr addr, uptr size, const char *name) { 384 } 385 #endif 386 387 uptr MmapNamed(void *addr, uptr length, int prot, int flags, const char *name) { 388 int fd = GetNamedMappingFd(name, length, &flags); 389 uptr res = internal_mmap(addr, length, prot, flags, fd, 0); 390 if (!internal_iserror(res)) 391 DecorateMapping(res, length, name); 392 return res; 393 } 394 395 396 } // namespace __sanitizer 397 398 #endif // SANITIZER_POSIX 399