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