1622 lines · cpp
1//===-- sanitizer_mac.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-exception6//7//===----------------------------------------------------------------------===//8//9// This file is shared between various sanitizers' runtime libraries and10// implements OSX-specific functions.11//===----------------------------------------------------------------------===//12 13#include "sanitizer_platform.h"14#if SANITIZER_APPLE15# include "interception/interception.h"16# include "sanitizer_mac.h"17 18// Use 64-bit inodes in file operations. ASan does not support OS X 10.5, so19// the clients will most certainly use 64-bit ones as well.20# ifndef _DARWIN_USE_64_BIT_INODE21# define _DARWIN_USE_64_BIT_INODE 122# endif23# include <stdio.h>24 25// Start searching for available memory region past PAGEZERO, which is26// 4KB on 32-bit and 4GB on 64-bit.27# define GAP_SEARCH_START_ADDRESS \28 ((SANITIZER_WORDSIZE == 32) ? 0x000000001000 : 0x000100000000)29 30# include "sanitizer_common.h"31# include "sanitizer_file.h"32# include "sanitizer_flags.h"33# include "sanitizer_interface_internal.h"34# include "sanitizer_internal_defs.h"35# include "sanitizer_libc.h"36# include "sanitizer_platform_limits_posix.h"37# include "sanitizer_procmaps.h"38# include "sanitizer_ptrauth.h"39 40# if !SANITIZER_IOS41# include <crt_externs.h> // for _NSGetEnviron42# else43extern char **environ;44# endif45 46// Integrate with CrashReporter library if available47# if defined(__has_include) && __has_include(<CrashReporterClient.h>)48# define HAVE_CRASHREPORTERCLIENT_H 149# include <CrashReporterClient.h>50# else51# define HAVE_CRASHREPORTERCLIENT_H 052# endif53 54# if !SANITIZER_IOS55# include <crt_externs.h> // for _NSGetArgv and _NSGetEnviron56# else57extern "C" {58extern char ***_NSGetArgv(void);59}60# endif61 62# include <asl.h>63# include <dlfcn.h> // for dladdr()64# include <errno.h>65# include <fcntl.h>66# include <inttypes.h>67# include <libkern/OSAtomic.h>68# include <mach-o/dyld.h>69# include <mach/mach.h>70# include <mach/mach_error.h>71# include <mach/mach_time.h>72# include <mach/vm_statistics.h>73# include <malloc/malloc.h>74# include <os/log.h>75# include <pthread.h>76# include <pthread/introspection.h>77# include <sched.h>78# include <signal.h>79# include <spawn.h>80# include <stdlib.h>81# include <sys/ioctl.h>82# include <sys/mman.h>83# include <sys/resource.h>84# include <sys/stat.h>85# include <sys/sysctl.h>86# include <sys/types.h>87# include <sys/wait.h>88# include <unistd.h>89# include <util.h>90 91// From <crt_externs.h>, but we don't have that file on iOS.92extern "C" {93 extern char ***_NSGetArgv(void);94 extern char ***_NSGetEnviron(void);95}96 97// From <mach/mach_vm.h>, but we don't have that file on iOS.98extern "C" {99 extern kern_return_t mach_vm_region_recurse(100 vm_map_t target_task,101 mach_vm_address_t *address,102 mach_vm_size_t *size,103 natural_t *nesting_depth,104 vm_region_recurse_info_t info,105 mach_msg_type_number_t *infoCnt);106 107 extern const void* _dyld_get_shared_cache_range(size_t* length);108}109 110# if !SANITIZER_GO111// Weak symbol no-op when TSan is not linked112SANITIZER_WEAK_ATTRIBUTE extern void __tsan_set_in_internal_write_call(113 bool value) {}114# endif115 116namespace __sanitizer {117 118#include "sanitizer_syscall_generic.inc"119 120// Direct syscalls, don't call libmalloc hooks (but not available on 10.6).121extern "C" void *__mmap(void *addr, size_t len, int prot, int flags, int fildes,122 off_t off) SANITIZER_WEAK_ATTRIBUTE;123extern "C" int __munmap(void *, size_t) SANITIZER_WEAK_ATTRIBUTE;124 125// ---------------------- sanitizer_libc.h126 127// From <mach/vm_statistics.h>, but not on older OSs.128#ifndef VM_MEMORY_SANITIZER129#define VM_MEMORY_SANITIZER 99130#endif131 132// XNU on Darwin provides a mmap flag that optimizes allocation/deallocation of133// giant memory regions (i.e. shadow memory regions).134#define kXnuFastMmapFd 0x4135static size_t kXnuFastMmapThreshold = 2 << 30; // 2 GB136static bool use_xnu_fast_mmap = false;137 138uptr internal_mmap(void *addr, size_t length, int prot, int flags,139 int fd, u64 offset) {140 if (fd == -1) {141 fd = VM_MAKE_TAG(VM_MEMORY_SANITIZER);142 if (length >= kXnuFastMmapThreshold) {143 if (use_xnu_fast_mmap) fd |= kXnuFastMmapFd;144 }145 }146 if (&__mmap) return (uptr)__mmap(addr, length, prot, flags, fd, offset);147 return (uptr)mmap(addr, length, prot, flags, fd, offset);148}149 150uptr internal_munmap(void *addr, uptr length) {151 if (&__munmap) return __munmap(addr, length);152 return munmap(addr, length);153}154 155uptr internal_mremap(void *old_address, uptr old_size, uptr new_size, int flags,156 void *new_address) {157 CHECK(false && "internal_mremap is unimplemented on Mac");158 return 0;159}160 161int internal_mprotect(void *addr, uptr length, int prot) {162 return mprotect(addr, length, prot);163}164 165int internal_madvise(uptr addr, uptr length, int advice) {166 return madvise((void *)addr, length, advice);167}168 169uptr internal_close(fd_t fd) {170 return close(fd);171}172 173uptr internal_open(const char *filename, int flags) {174 return open(filename, flags);175}176 177uptr internal_open(const char *filename, int flags, u32 mode) {178 return open(filename, flags, mode);179}180 181uptr internal_read(fd_t fd, void *buf, uptr count) {182 return read(fd, buf, count);183}184 185uptr internal_write(fd_t fd, const void *buf, uptr count) {186# if SANITIZER_GO187 return write(fd, buf, count);188# else189 // We need to disable interceptors when writing in TSan190 __tsan_set_in_internal_write_call(true);191 uptr res = write(fd, buf, count);192 __tsan_set_in_internal_write_call(false);193 return res;194# endif195}196 197uptr internal_stat(const char *path, void *buf) {198 return stat(path, (struct stat *)buf);199}200 201uptr internal_lstat(const char *path, void *buf) {202 return lstat(path, (struct stat *)buf);203}204 205uptr internal_fstat(fd_t fd, void *buf) {206 return fstat(fd, (struct stat *)buf);207}208 209uptr internal_filesize(fd_t fd) {210 struct stat st;211 if (internal_fstat(fd, &st))212 return -1;213 return (uptr)st.st_size;214}215 216uptr internal_dup(int oldfd) {217 return dup(oldfd);218}219 220uptr internal_dup2(int oldfd, int newfd) {221 return dup2(oldfd, newfd);222}223 224uptr internal_readlink(const char *path, char *buf, uptr bufsize) {225 return readlink(path, buf, bufsize);226}227 228uptr internal_unlink(const char *path) {229 return unlink(path);230}231 232uptr internal_sched_yield() {233 return sched_yield();234}235 236void internal__exit(int exitcode) {237 _exit(exitcode);238}239 240void internal_usleep(u64 useconds) { usleep(useconds); }241 242uptr internal_getpid() {243 return getpid();244}245 246int internal_dlinfo(void *handle, int request, void *p) {247 UNIMPLEMENTED();248}249 250int internal_sigaction(int signum, const void *act, void *oldact) {251 return sigaction(signum,252 (const struct sigaction *)act, (struct sigaction *)oldact);253}254 255void internal_sigfillset(__sanitizer_sigset_t *set) { sigfillset(set); }256 257uptr internal_sigprocmask(int how, __sanitizer_sigset_t *set,258 __sanitizer_sigset_t *oldset) {259 // Don't use sigprocmask here, because it affects all threads.260 return pthread_sigmask(how, set, oldset);261}262 263// Doesn't call pthread_atfork() handlers (but not available on 10.6).264extern "C" pid_t __fork(void) SANITIZER_WEAK_ATTRIBUTE;265 266int internal_fork() {267 if (&__fork)268 return __fork();269 return fork();270}271 272int internal_sysctl(const int *name, unsigned int namelen, void *oldp,273 uptr *oldlenp, const void *newp, uptr newlen) {274 return sysctl(const_cast<int *>(name), namelen, oldp, (size_t *)oldlenp,275 const_cast<void *>(newp), (size_t)newlen);276}277 278int internal_sysctlbyname(const char *sname, void *oldp, uptr *oldlenp,279 const void *newp, uptr newlen) {280 return sysctlbyname(sname, oldp, (size_t *)oldlenp, const_cast<void *>(newp),281 (size_t)newlen);282}283 284static fd_t internal_spawn_impl(const char *argv[], const char *envp[],285 pid_t *pid) {286 fd_t primary_fd = kInvalidFd;287 fd_t secondary_fd = kInvalidFd;288 289 auto fd_closer = at_scope_exit([&] {290 internal_close(primary_fd);291 internal_close(secondary_fd);292 });293 294 // We need a new pseudoterminal to avoid buffering problems. The 'atos' tool295 // in particular detects when it's talking to a pipe and forgets to flush the296 // output stream after sending a response.297 primary_fd = posix_openpt(O_RDWR);298 if (primary_fd == kInvalidFd)299 return kInvalidFd;300 301 int res = grantpt(primary_fd) || unlockpt(primary_fd);302 if (res != 0) return kInvalidFd;303 304 // Use TIOCPTYGNAME instead of ptsname() to avoid threading problems.305 char secondary_pty_name[128];306 res = ioctl(primary_fd, TIOCPTYGNAME, secondary_pty_name);307 if (res == -1) return kInvalidFd;308 309 secondary_fd = internal_open(secondary_pty_name, O_RDWR);310 if (secondary_fd == kInvalidFd)311 return kInvalidFd;312 313 // File descriptor actions314 posix_spawn_file_actions_t acts;315 res = posix_spawn_file_actions_init(&acts);316 if (res != 0) return kInvalidFd;317 318 auto acts_cleanup = at_scope_exit([&] {319 posix_spawn_file_actions_destroy(&acts);320 });321 322 res = posix_spawn_file_actions_adddup2(&acts, secondary_fd, STDIN_FILENO) ||323 posix_spawn_file_actions_adddup2(&acts, secondary_fd, STDOUT_FILENO) ||324 posix_spawn_file_actions_addclose(&acts, secondary_fd);325 if (res != 0) return kInvalidFd;326 327 // Spawn attributes328 posix_spawnattr_t attrs;329 res = posix_spawnattr_init(&attrs);330 if (res != 0) return kInvalidFd;331 332 auto attrs_cleanup = at_scope_exit([&] {333 posix_spawnattr_destroy(&attrs);334 });335 336 // In the spawned process, close all file descriptors that are not explicitly337 // described by the file actions object. This is Darwin-specific extension.338 res = posix_spawnattr_setflags(&attrs, POSIX_SPAWN_CLOEXEC_DEFAULT);339 if (res != 0) return kInvalidFd;340 341 // posix_spawn342 char **argv_casted = const_cast<char **>(argv);343 char **envp_casted = const_cast<char **>(envp);344 res = posix_spawn(pid, argv[0], &acts, &attrs, argv_casted, envp_casted);345 if (res != 0) return kInvalidFd;346 347 // Disable echo in the new terminal, disable CR.348 struct termios termflags;349 tcgetattr(primary_fd, &termflags);350 termflags.c_oflag &= ~ONLCR;351 termflags.c_lflag &= ~ECHO;352 tcsetattr(primary_fd, TCSANOW, &termflags);353 354 // On success, do not close primary_fd on scope exit.355 fd_t fd = primary_fd;356 primary_fd = kInvalidFd;357 358 return fd;359}360 361fd_t internal_spawn(const char *argv[], const char *envp[], pid_t *pid) {362 // The client program may close its stdin and/or stdout and/or stderr thus363 // allowing open/posix_openpt to reuse file descriptors 0, 1 or 2. In this364 // case the communication is broken if either the parent or the child tries to365 // close or duplicate these descriptors. We temporarily reserve these366 // descriptors here to prevent this.367 fd_t low_fds[3];368 size_t count = 0;369 370 for (; count < 3; count++) {371 low_fds[count] = posix_openpt(O_RDWR);372 if (low_fds[count] >= STDERR_FILENO)373 break;374 }375 376 fd_t fd = internal_spawn_impl(argv, envp, pid);377 378 for (; count > 0; count--) {379 internal_close(low_fds[count]);380 }381 382 return fd;383}384 385uptr internal_rename(const char *oldpath, const char *newpath) {386 return rename(oldpath, newpath);387}388 389uptr internal_ftruncate(fd_t fd, uptr size) {390 return ftruncate(fd, size);391}392 393uptr internal_execve(const char *filename, char *const argv[],394 char *const envp[]) {395 return execve(filename, argv, envp);396}397 398uptr internal_waitpid(int pid, int *status, int options) {399 return waitpid(pid, status, options);400}401 402// ----------------- sanitizer_common.h403bool FileExists(const char *filename) {404 if (ShouldMockFailureToOpen(filename))405 return false;406 struct stat st;407 if (stat(filename, &st))408 return false;409 // Sanity check: filename is a regular file.410 return S_ISREG(st.st_mode);411}412 413bool DirExists(const char *path) {414 struct stat st;415 if (stat(path, &st))416 return false;417 return S_ISDIR(st.st_mode);418}419 420ThreadID GetTid() {421 ThreadID tid;422 pthread_threadid_np(nullptr, &tid);423 return tid;424}425 426void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,427 uptr *stack_bottom) {428 CHECK(stack_top);429 CHECK(stack_bottom);430 uptr stacksize = pthread_get_stacksize_np(pthread_self());431 // pthread_get_stacksize_np() returns an incorrect stack size for the main432 // thread on Mavericks. See433 // https://github.com/google/sanitizers/issues/261434 if ((GetMacosAlignedVersion() >= MacosVersion(10, 9)) && at_initialization &&435 stacksize == (1 << 19)) {436 struct rlimit rl;437 CHECK_EQ(getrlimit(RLIMIT_STACK, &rl), 0);438 // Most often rl.rlim_cur will be the desired 8M.439 if (rl.rlim_cur < kMaxThreadStackSize) {440 stacksize = rl.rlim_cur;441 } else {442 stacksize = kMaxThreadStackSize;443 }444 }445 void *stackaddr = pthread_get_stackaddr_np(pthread_self());446 *stack_top = (uptr)stackaddr;447 *stack_bottom = *stack_top - stacksize;448}449 450char **GetEnviron() {451#if !SANITIZER_IOS452 char ***env_ptr = _NSGetEnviron();453 if (!env_ptr) {454 Report("_NSGetEnviron() returned NULL. Please make sure __asan_init() is "455 "called after libSystem_initializer().\n");456 CHECK(env_ptr);457 }458 char **environ = *env_ptr;459#endif460 CHECK(environ);461 return environ;462}463 464const char *GetEnv(const char *name) {465 char **env = GetEnviron();466 uptr name_len = internal_strlen(name);467 while (*env != 0) {468 uptr len = internal_strlen(*env);469 if (len > name_len) {470 const char *p = *env;471 if (!internal_memcmp(p, name, name_len) &&472 p[name_len] == '=') { // Match.473 return *env + name_len + 1; // String starting after =.474 }475 }476 env++;477 }478 return 0;479}480 481uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) {482 CHECK_LE(kMaxPathLength, buf_len);483 484 // On OS X the executable path is saved to the stack by dyld. Reading it485 // from there is much faster than calling dladdr, especially for large486 // binaries with symbols.487 InternalMmapVector<char> exe_path(kMaxPathLength);488 uint32_t size = exe_path.size();489 if (_NSGetExecutablePath(exe_path.data(), &size) == 0 &&490 realpath(exe_path.data(), buf) != 0) {491 return internal_strlen(buf);492 }493 return 0;494}495 496uptr ReadLongProcessName(/*out*/char *buf, uptr buf_len) {497 return ReadBinaryName(buf, buf_len);498}499 500void ReExec() {501 UNIMPLEMENTED();502}503 504void CheckASLR() {505 // Do nothing506}507 508void CheckMPROTECT() {509 // Do nothing510}511 512uptr GetPageSize() {513 return sysconf(_SC_PAGESIZE);514}515 516extern "C" unsigned malloc_num_zones;517extern "C" malloc_zone_t **malloc_zones;518malloc_zone_t sanitizer_zone;519 520// We need to make sure that sanitizer_zone is registered as malloc_zones[0]. If521// libmalloc tries to set up a different zone as malloc_zones[0], it will call522// mprotect(malloc_zones, ..., PROT_READ). This interceptor will catch that and523// make sure we are still the first (default) zone.524void MprotectMallocZones(void *addr, int prot) {525 if (addr == malloc_zones && prot == PROT_READ) {526 if (malloc_num_zones > 1 && malloc_zones[0] != &sanitizer_zone) {527 for (unsigned i = 1; i < malloc_num_zones; i++) {528 if (malloc_zones[i] == &sanitizer_zone) {529 // Swap malloc_zones[0] and malloc_zones[i].530 malloc_zones[i] = malloc_zones[0];531 malloc_zones[0] = &sanitizer_zone;532 break;533 }534 }535 }536 }537}538 539void FutexWait(atomic_uint32_t *p, u32 cmp) {540 // FIXME: implement actual blocking.541 sched_yield();542}543 544void FutexWake(atomic_uint32_t *p, u32 count) {}545 546u64 NanoTime() {547 timeval tv;548 internal_memset(&tv, 0, sizeof(tv));549 gettimeofday(&tv, 0);550 return (u64)tv.tv_sec * 1000*1000*1000 + tv.tv_usec * 1000;551}552 553// This needs to be called during initialization to avoid being racy.554u64 MonotonicNanoTime() {555 static mach_timebase_info_data_t timebase_info;556 if (timebase_info.denom == 0) mach_timebase_info(&timebase_info);557 return (mach_absolute_time() * timebase_info.numer) / timebase_info.denom;558}559 560uptr GetTlsSize() {561 return 0;562}563 564uptr TlsBaseAddr() {565 uptr segbase = 0;566#if defined(__x86_64__)567 asm("movq %%gs:0,%0" : "=r"(segbase));568#elif defined(__i386__)569 asm("movl %%gs:0,%0" : "=r"(segbase));570#elif defined(__aarch64__)571 asm("mrs %x0, tpidrro_el0" : "=r"(segbase));572 segbase &= 0x07ul; // clearing lower bits, cpu id stored there573#endif574 return segbase;575}576 577// The size of the tls on darwin does not appear to be well documented,578// however the vm memory map suggests that it is 1024 uptrs in size,579// with a size of 0x2000 bytes on x86_64 and 0x1000 bytes on i386.580uptr TlsSize() {581#if defined(__x86_64__) || defined(__i386__)582 return 1024 * sizeof(uptr);583#else584 return 0;585#endif586}587 588void GetThreadStackAndTls(bool main, uptr *stk_begin, uptr *stk_end,589 uptr *tls_begin, uptr *tls_end) {590# if !SANITIZER_GO591 GetThreadStackTopAndBottom(main, stk_end, stk_begin);592 *tls_begin = TlsBaseAddr();593 *tls_end = *tls_begin + TlsSize();594# else595 *stk_begin = 0;596 *stk_end = 0;597 *tls_begin = 0;598 *tls_end = 0;599# endif600}601 602void ListOfModules::init() {603 clearOrInit();604 MemoryMappingLayout memory_mapping(false);605 memory_mapping.DumpListOfModules(&modules_);606}607 608void ListOfModules::fallbackInit() { clear(); }609 610static HandleSignalMode GetHandleSignalModeImpl(int signum) {611 switch (signum) {612 case SIGABRT:613 return common_flags()->handle_abort;614 case SIGILL:615 return common_flags()->handle_sigill;616 case SIGTRAP:617 return common_flags()->handle_sigtrap;618 case SIGFPE:619 return common_flags()->handle_sigfpe;620 case SIGSEGV:621 return common_flags()->handle_segv;622 case SIGBUS:623 return common_flags()->handle_sigbus;624 }625 return kHandleSignalNo;626}627 628HandleSignalMode GetHandleSignalMode(int signum) {629 // Handling fatal signals on watchOS and tvOS devices is disallowed.630 if ((SANITIZER_WATCHOS || SANITIZER_TVOS) && !(SANITIZER_IOSSIM))631 return kHandleSignalNo;632 HandleSignalMode result = GetHandleSignalModeImpl(signum);633 if (result == kHandleSignalYes && !common_flags()->allow_user_segv_handler)634 return kHandleSignalExclusive;635 return result;636}637 638// Offset example:639// XNU 17 -- macOS 10.13 -- iOS 11 -- tvOS 11 -- watchOS 4640constexpr u16 GetOSMajorKernelOffset() {641 if (TARGET_OS_OSX) return 4;642 if (TARGET_OS_IOS || TARGET_OS_TV) return 6;643 if (TARGET_OS_WATCH) return 13;644}645 646using VersStr = char[64];647 648static uptr ApproximateOSVersionViaKernelVersion(VersStr vers) {649 u16 kernel_major = GetDarwinKernelVersion().major;650 u16 offset = GetOSMajorKernelOffset();651 CHECK_GE(kernel_major, offset);652 u16 os_major = kernel_major - offset;653 654 const char *format = "%d.0";655 if (TARGET_OS_OSX) {656 if (os_major >= 16) { // macOS 11+657 os_major -= 5;658 } else { // macOS 10.15 and below659 format = "10.%d";660 }661 }662 return internal_snprintf(vers, sizeof(VersStr), format, os_major);663}664 665static void GetOSVersion(VersStr vers) {666 uptr len = sizeof(VersStr);667 if (SANITIZER_IOSSIM) {668 const char *vers_env = GetEnv("SIMULATOR_RUNTIME_VERSION");669 if (!vers_env) {670 Report("ERROR: Running in simulator but SIMULATOR_RUNTIME_VERSION env "671 "var is not set.\n");672 Die();673 }674 len = internal_strlcpy(vers, vers_env, len);675 } else {676 int res =677 internal_sysctlbyname("kern.osproductversion", vers, &len, nullptr, 0);678 679 // XNU 17 (macOS 10.13) and below do not provide the sysctl680 // `kern.osproductversion` entry (res != 0).681 bool no_os_version = res != 0;682 683 // For launchd, sanitizer initialization runs before sysctl is setup684 // (res == 0 && len != strlen(vers), vers is not a valid version). However,685 // the kernel version `kern.osrelease` is available.686 bool launchd = (res == 0 && internal_strlen(vers) < 3);687 if (launchd) CHECK_EQ(internal_getpid(), 1);688 689 if (no_os_version || launchd) {690 len = ApproximateOSVersionViaKernelVersion(vers);691 }692 }693 CHECK_LT(len, sizeof(VersStr));694}695 696void ParseVersion(const char *vers, u16 *major, u16 *minor) {697 // Format: <major>.<minor>[.<patch>]\0698 CHECK_GE(internal_strlen(vers), 3);699 const char *p = vers;700 *major = internal_simple_strtoll(p, &p, /*base=*/10);701 CHECK_EQ(*p, '.');702 p += 1;703 *minor = internal_simple_strtoll(p, &p, /*base=*/10);704}705 706// Aligned versions example:707// macOS 10.15 -- iOS 13 -- tvOS 13 -- watchOS 6708static void MapToMacos(u16 *major, u16 *minor) {709 if (TARGET_OS_OSX)710 return;711 712 if (TARGET_OS_IOS || TARGET_OS_TV)713 *major += 2;714 else if (TARGET_OS_WATCH)715 *major += 9;716 else717 UNREACHABLE("unsupported platform");718 719 if (*major >= 16) { // macOS 11+720 *major -= 5;721 } else { // macOS 10.15 and below722 *minor = *major;723 *major = 10;724 }725}726 727static MacosVersion GetMacosAlignedVersionInternal() {728 VersStr vers = {};729 GetOSVersion(vers);730 731 u16 major, minor;732 ParseVersion(vers, &major, &minor);733 MapToMacos(&major, &minor);734 735 return MacosVersion(major, minor);736}737 738static_assert(sizeof(MacosVersion) == sizeof(atomic_uint32_t::Type),739 "MacosVersion cache size");740static atomic_uint32_t cached_macos_version;741 742MacosVersion GetMacosAlignedVersion() {743 atomic_uint32_t::Type result =744 atomic_load(&cached_macos_version, memory_order_acquire);745 if (!result) {746 MacosVersion version = GetMacosAlignedVersionInternal();747 result = *reinterpret_cast<atomic_uint32_t::Type *>(&version);748 atomic_store(&cached_macos_version, result, memory_order_release);749 }750 return *reinterpret_cast<MacosVersion *>(&result);751}752 753DarwinKernelVersion GetDarwinKernelVersion() {754 VersStr vers = {};755 uptr len = sizeof(VersStr);756 int res = internal_sysctlbyname("kern.osrelease", vers, &len, nullptr, 0);757 CHECK_EQ(res, 0);758 CHECK_LT(len, sizeof(VersStr));759 760 u16 major, minor;761 ParseVersion(vers, &major, &minor);762 763 return DarwinKernelVersion(major, minor);764}765 766uptr GetRSS() {767 struct task_basic_info info;768 unsigned count = TASK_BASIC_INFO_COUNT;769 kern_return_t result =770 task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t)&info, &count);771 if (UNLIKELY(result != KERN_SUCCESS)) {772 Report("Cannot get task info. Error: %d\n", result);773 Die();774 }775 return info.resident_size;776}777 778void *internal_start_thread(void *(*func)(void *arg), void *arg) {779 // Start the thread with signals blocked, otherwise it can steal user signals.780 __sanitizer_sigset_t set, old;781 internal_sigfillset(&set);782 internal_sigprocmask(SIG_SETMASK, &set, &old);783 pthread_t th;784 pthread_create(&th, 0, func, arg);785 internal_sigprocmask(SIG_SETMASK, &old, 0);786 return th;787}788 789void internal_join_thread(void *th) { pthread_join((pthread_t)th, 0); }790 791#if !SANITIZER_GO792static Mutex syslog_lock;793# endif794 795# if SANITIZER_DRIVERKIT796# define SANITIZER_OS_LOG os_log797# else798# define SANITIZER_OS_LOG os_log_error799# endif800 801void WriteOneLineToSyslog(const char *s) {802#if !SANITIZER_GO803 syslog_lock.CheckLocked();804 if (GetMacosAlignedVersion() >= MacosVersion(10, 12)) {805 SANITIZER_OS_LOG(OS_LOG_DEFAULT, "%{public}s", s);806 } else {807#pragma clang diagnostic push808// as_log is deprecated.809#pragma clang diagnostic ignored "-Wdeprecated-declarations"810 asl_log(nullptr, nullptr, ASL_LEVEL_ERR, "%s", s);811#pragma clang diagnostic pop812 }813#endif814}815 816// buffer to store crash report application information817static char crashreporter_info_buff[__sanitizer::kErrorMessageBufferSize] = {};818static Mutex crashreporter_info_mutex;819 820extern "C" {821 822#if HAVE_CRASHREPORTERCLIENT_H823// Available in CRASHREPORTER_ANNOTATIONS_VERSION 5+824# ifdef CRASHREPORTER_ANNOTATIONS_INITIALIZER825CRASHREPORTER_ANNOTATIONS_INITIALIZER()826# else827// Support for older CrashRerporter annotiations828CRASH_REPORTER_CLIENT_HIDDEN829struct crashreporter_annotations_t gCRAnnotations830 __attribute__((section("__DATA," CRASHREPORTER_ANNOTATIONS_SECTION))) = {831 CRASHREPORTER_ANNOTATIONS_VERSION,832 0,833 0,834 0,835 0,836 0,837 0,838# if CRASHREPORTER_ANNOTATIONS_VERSION > 4839 0,840# endif841};842# endif843# else844// Revert to previous crash reporter API if client header is not available845static const char *__crashreporter_info__ __attribute__((__used__)) =846 &crashreporter_info_buff[0];847asm(".desc ___crashreporter_info__, 0x10");848#endif // HAVE_CRASHREPORTERCLIENT_H849 850} // extern "C"851 852static void CRAppendCrashLogMessage(const char *msg) {853 Lock l(&crashreporter_info_mutex);854 internal_strlcat(crashreporter_info_buff, msg,855 sizeof(crashreporter_info_buff));856#if HAVE_CRASHREPORTERCLIENT_H857 (void)CRSetCrashLogMessage(crashreporter_info_buff);858#endif859}860 861void LogMessageOnPrintf(const char *str) {862 // Log all printf output to CrashLog.863 if (common_flags()->abort_on_error)864 CRAppendCrashLogMessage(str);865}866 867void LogFullErrorReport(const char *buffer) {868# if !SANITIZER_GO869 // When logging with os_log_error this will make it into the crash log.870 if (internal_strncmp(SanitizerToolName, "AddressSanitizer",871 sizeof("AddressSanitizer") - 1) == 0)872 SANITIZER_OS_LOG(OS_LOG_DEFAULT, "Address Sanitizer reported a failure.");873 else if (internal_strncmp(SanitizerToolName, "UndefinedBehaviorSanitizer",874 sizeof("UndefinedBehaviorSanitizer") - 1) == 0)875 SANITIZER_OS_LOG(OS_LOG_DEFAULT,876 "Undefined Behavior Sanitizer reported a failure.");877 else if (internal_strncmp(SanitizerToolName, "ThreadSanitizer",878 sizeof("ThreadSanitizer") - 1) == 0)879 SANITIZER_OS_LOG(OS_LOG_DEFAULT, "Thread Sanitizer reported a failure.");880 else881 SANITIZER_OS_LOG(OS_LOG_DEFAULT, "Sanitizer tool reported a failure.");882 883 if (common_flags()->log_to_syslog)884 SANITIZER_OS_LOG(OS_LOG_DEFAULT, "Consult syslog for more information.");885 886 // Log to syslog.887 // The logging on OS X may call pthread_create so we need the threading888 // environment to be fully initialized. Also, this should never be called when889 // holding the thread registry lock since that may result in a deadlock. If890 // the reporting thread holds the thread registry mutex, and asl_log waits891 // for GCD to dispatch a new thread, the process will deadlock, because the892 // pthread_create wrapper needs to acquire the lock as well.893 Lock l(&syslog_lock);894 if (common_flags()->log_to_syslog)895 WriteToSyslog(buffer);896 897 // The report is added to CrashLog as part of logging all of Printf output.898# endif // !SANITIZER_GO899}900 901SignalContext::WriteFlag SignalContext::GetWriteFlag() const {902#if defined(__x86_64__) || defined(__i386__)903 ucontext_t *ucontext = static_cast<ucontext_t*>(context);904 return ucontext->uc_mcontext->__es.__err & 2 /*T_PF_WRITE*/ ? Write : Read;905#elif defined(__arm64__)906 ucontext_t *ucontext = static_cast<ucontext_t*>(context);907 return ucontext->uc_mcontext->__es.__esr & 0x40 /*ISS_DA_WNR*/ ? Write : Read;908#else909 return Unknown;910#endif911}912 913bool SignalContext::IsTrueFaultingAddress() const {914 auto si = static_cast<const siginfo_t *>(siginfo);915 // "Real" SIGSEGV codes (e.g., SEGV_MAPERR, SEGV_MAPERR) are non-zero.916 return si->si_signo == SIGSEGV && si->si_code != 0;917}918 919#if defined(__aarch64__) && defined(arm_thread_state64_get_sp)920 #define AARCH64_GET_REG(r) \921 (uptr)ptrauth_strip( \922 (void *)arm_thread_state64_get_##r(ucontext->uc_mcontext->__ss), 0)923#else924 #define AARCH64_GET_REG(r) (uptr)ucontext->uc_mcontext->__ss.__##r925#endif926 927static void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) {928 ucontext_t *ucontext = (ucontext_t*)context;929# if defined(__aarch64__)930 *pc = AARCH64_GET_REG(pc);931 *bp = AARCH64_GET_REG(fp);932 *sp = AARCH64_GET_REG(sp);933# elif defined(__x86_64__)934 *pc = ucontext->uc_mcontext->__ss.__rip;935 *bp = ucontext->uc_mcontext->__ss.__rbp;936 *sp = ucontext->uc_mcontext->__ss.__rsp;937# elif defined(__arm__)938 *pc = ucontext->uc_mcontext->__ss.__pc;939 *bp = ucontext->uc_mcontext->__ss.__r[7];940 *sp = ucontext->uc_mcontext->__ss.__sp;941# elif defined(__i386__)942 *pc = ucontext->uc_mcontext->__ss.__eip;943 *bp = ucontext->uc_mcontext->__ss.__ebp;944 *sp = ucontext->uc_mcontext->__ss.__esp;945# else946# error "Unknown architecture"947# endif948}949 950void SignalContext::InitPcSpBp() {951 addr = (uptr)ptrauth_strip((void *)addr, 0);952 GetPcSpBp(context, &pc, &sp, &bp);953}954 955// ASan/TSan use mmap in a way that creates “deallocation gaps” which triggers956// EXC_GUARD exceptions on macOS 10.15+ (XNU 19.0+).957static void DisableMmapExcGuardExceptions() {958 using task_exc_guard_behavior_t = uint32_t;959 using task_set_exc_guard_behavior_t =960 kern_return_t(task_t task, task_exc_guard_behavior_t behavior);961 auto *set_behavior = (task_set_exc_guard_behavior_t *)dlsym(962 RTLD_DEFAULT, "task_set_exc_guard_behavior");963 if (set_behavior == nullptr) return;964 const task_exc_guard_behavior_t task_exc_guard_none = 0;965 kern_return_t res = set_behavior(mach_task_self(), task_exc_guard_none);966 if (res != KERN_SUCCESS) {967 Report(968 "WARN: task_set_exc_guard_behavior returned %d (%s), "969 "mmap may fail unexpectedly.\n",970 res, mach_error_string(res));971 if (res == KERN_DENIED)972 Report(973 "HINT: Check that task_set_exc_guard_behavior is allowed by "974 "sandbox.\n");975 }976}977 978static void VerifyInterceptorsWorking();979static void StripEnv();980 981void InitializePlatformEarly() {982 // Only use xnu_fast_mmap when on x86_64 and the kernel supports it.983 use_xnu_fast_mmap =984#if defined(__x86_64__)985 GetDarwinKernelVersion() >= DarwinKernelVersion(17, 5);986#else987 false;988#endif989 if (GetDarwinKernelVersion() >= DarwinKernelVersion(19, 0))990 DisableMmapExcGuardExceptions();991 992# if !SANITIZER_GO993 MonotonicNanoTime(); // Call to initialize mach_timebase_info994 VerifyInterceptorsWorking();995 StripEnv();996# endif997}998 999#if !SANITIZER_GO1000static const char kDyldInsertLibraries[] = "DYLD_INSERT_LIBRARIES";1001LowLevelAllocator allocator_for_env;1002 1003static bool ShouldCheckInterceptors() {1004 // Restrict "interceptors working?" check1005 const char *sanitizer_names[] = {"AddressSanitizer", "ThreadSanitizer",1006 "RealtimeSanitizer"};1007 size_t count = sizeof(sanitizer_names) / sizeof(sanitizer_names[0]);1008 for (size_t i = 0; i < count; i++) {1009 if (internal_strcmp(sanitizer_names[i], SanitizerToolName) == 0)1010 return true;1011 }1012 return false;1013}1014 1015static void VerifyInterceptorsWorking() {1016 if (!common_flags()->verify_interceptors || !ShouldCheckInterceptors())1017 return;1018 1019 // Verify that interceptors really work. We'll use dlsym to locate1020 // "puts", if interceptors are working, it should really point to1021 // "wrap_puts" within our own dylib.1022 Dl_info info_puts, info_runtime;1023 RAW_CHECK(dladdr(dlsym(RTLD_DEFAULT, "puts"), &info_puts));1024 RAW_CHECK(dladdr((void *)&VerifyInterceptorsWorking, &info_runtime));1025 if (internal_strcmp(info_puts.dli_fname, info_runtime.dli_fname) != 0) {1026 Report(1027 "ERROR: Interceptors are not working. This may be because %s is "1028 "loaded too late (e.g. via dlopen). Please launch the executable "1029 "with:\n%s=%s\n",1030 SanitizerToolName, kDyldInsertLibraries, info_runtime.dli_fname);1031 RAW_CHECK("interceptors not installed" && 0);1032 }1033}1034 1035// Change the value of the env var |name|, leaking the original value.1036// If |name_value| is NULL, the variable is deleted from the environment,1037// otherwise the corresponding "NAME=value" string is replaced with1038// |name_value|.1039static void LeakyResetEnv(const char *name, const char *name_value) {1040 char **env = GetEnviron();1041 uptr name_len = internal_strlen(name);1042 while (*env != 0) {1043 uptr len = internal_strlen(*env);1044 if (len > name_len) {1045 const char *p = *env;1046 if (!internal_memcmp(p, name, name_len) && p[name_len] == '=') {1047 // Match.1048 if (name_value) {1049 // Replace the old value with the new one.1050 *env = const_cast<char*>(name_value);1051 } else {1052 // Shift the subsequent pointers back.1053 char **del = env;1054 do {1055 del[0] = del[1];1056 } while (*del++);1057 }1058 }1059 }1060 env++;1061 }1062}1063 1064static void StripEnv() {1065 if (!common_flags()->strip_env)1066 return;1067 1068 char *dyld_insert_libraries =1069 const_cast<char *>(GetEnv(kDyldInsertLibraries));1070 if (!dyld_insert_libraries)1071 return;1072 1073 Dl_info info;1074 RAW_CHECK(dladdr((void *)&StripEnv, &info));1075 const char *dylib_name = StripModuleName(info.dli_fname);1076 bool lib_is_in_env = internal_strstr(dyld_insert_libraries, dylib_name);1077 if (!lib_is_in_env)1078 return;1079 1080 // DYLD_INSERT_LIBRARIES is set and contains the runtime library. Let's remove1081 // the dylib from the environment variable, because interceptors are installed1082 // and we don't want our children to inherit the variable.1083 1084 uptr old_env_len = internal_strlen(dyld_insert_libraries);1085 uptr dylib_name_len = internal_strlen(dylib_name);1086 uptr env_name_len = internal_strlen(kDyldInsertLibraries);1087 // Allocate memory to hold the previous env var name, its value, the '='1088 // sign and the '\0' char.1089 char *new_env = (char*)allocator_for_env.Allocate(1090 old_env_len + 2 + env_name_len);1091 RAW_CHECK(new_env);1092 internal_memset(new_env, '\0', old_env_len + 2 + env_name_len);1093 internal_strncpy(new_env, kDyldInsertLibraries, env_name_len);1094 new_env[env_name_len] = '=';1095 char *new_env_pos = new_env + env_name_len + 1;1096 1097 // Iterate over colon-separated pieces of |dyld_insert_libraries|.1098 char *piece_start = dyld_insert_libraries;1099 char *piece_end = NULL;1100 char *old_env_end = dyld_insert_libraries + old_env_len;1101 do {1102 if (piece_start[0] == ':') piece_start++;1103 piece_end = internal_strchr(piece_start, ':');1104 if (!piece_end) piece_end = dyld_insert_libraries + old_env_len;1105 if ((uptr)(piece_start - dyld_insert_libraries) > old_env_len) break;1106 uptr piece_len = piece_end - piece_start;1107 1108 char *filename_start =1109 (char *)internal_memrchr(piece_start, '/', piece_len);1110 uptr filename_len = piece_len;1111 if (filename_start) {1112 filename_start += 1;1113 filename_len = piece_len - (filename_start - piece_start);1114 } else {1115 filename_start = piece_start;1116 }1117 1118 // If the current piece isn't the runtime library name,1119 // append it to new_env.1120 if ((dylib_name_len != filename_len) ||1121 (internal_memcmp(filename_start, dylib_name, dylib_name_len) != 0)) {1122 if (new_env_pos != new_env + env_name_len + 1) {1123 new_env_pos[0] = ':';1124 new_env_pos++;1125 }1126 internal_strncpy(new_env_pos, piece_start, piece_len);1127 new_env_pos += piece_len;1128 }1129 // Move on to the next piece.1130 piece_start = piece_end;1131 } while (piece_start < old_env_end);1132 1133 // Can't use setenv() here, because it requires the allocator to be1134 // initialized.1135 // FIXME: instead of filtering DYLD_INSERT_LIBRARIES here, do it in1136 // a separate function called after InitializeAllocator().1137 if (new_env_pos == new_env + env_name_len + 1) new_env = NULL;1138 LeakyResetEnv(kDyldInsertLibraries, new_env);1139}1140#endif // SANITIZER_GO1141 1142// Prints out a consolidated memory map: contiguous regions1143// are merged together.1144static void PrintVmmap() {1145 const mach_vm_address_t max_vm_address = GetMaxVirtualAddress() + 1;1146 mach_vm_address_t address = GAP_SEARCH_START_ADDRESS;1147 kern_return_t kr = KERN_SUCCESS;1148 1149 Report("Memory map:\n");1150 mach_vm_address_t last = 0;1151 mach_vm_address_t lastsz = 0;1152 1153 while (1) {1154 mach_vm_size_t vmsize = 0;1155 natural_t depth = 0;1156 vm_region_submap_short_info_data_64_t vminfo;1157 mach_msg_type_number_t count = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64;1158 kr = mach_vm_region_recurse(mach_task_self(), &address, &vmsize, &depth,1159 (vm_region_info_t)&vminfo, &count);1160 1161 if (kr == KERN_DENIED) {1162 Report(1163 "ERROR: mach_vm_region_recurse got KERN_DENIED when printing memory "1164 "map.\n");1165 Report(1166 "HINT: Check whether mach_vm_region_recurse is allowed by "1167 "sandbox.\n");1168 }1169 1170 if (kr == KERN_SUCCESS && address < max_vm_address) {1171 if (last + lastsz == address) {1172 // This region is contiguous with the last; merge together.1173 lastsz += vmsize;1174 } else {1175 if (lastsz)1176 Printf("|| `[%p, %p]` || size=0x%016" PRIx64 " ||\n", (void*)last,1177 (void*)(last + lastsz), lastsz);1178 1179 last = address;1180 lastsz = vmsize;1181 }1182 address += vmsize;1183 } else {1184 // We've reached the end of the memory map. Print the last remaining1185 // region, if there is one.1186 if (lastsz)1187 Printf("|| `[%p, %p]` || size=0x%016" PRIx64 " ||\n", (void*)last,1188 (void*)(last + lastsz), lastsz);1189 1190 break;1191 }1192 }1193}1194 1195static void ReportShadowAllocFail(uptr shadow_size_bytes, uptr alignment) {1196 Report(1197 "FATAL: Failed to allocate shadow memory. Tried to allocate %p bytes "1198 "(alignment=%p).\n",1199 (void*)shadow_size_bytes, (void*)alignment);1200 PrintVmmap();1201}1202 1203char **GetArgv() {1204 return *_NSGetArgv();1205}1206 1207#if SANITIZER_IOS && !SANITIZER_IOSSIM1208// The task_vm_info struct is normally provided by the macOS SDK, but we need1209// fields only available in 10.12+. Declare the struct manually to be able to1210// build against older SDKs.1211struct __sanitizer_task_vm_info {1212 mach_vm_size_t virtual_size;1213 integer_t region_count;1214 integer_t page_size;1215 mach_vm_size_t resident_size;1216 mach_vm_size_t resident_size_peak;1217 mach_vm_size_t device;1218 mach_vm_size_t device_peak;1219 mach_vm_size_t internal;1220 mach_vm_size_t internal_peak;1221 mach_vm_size_t external;1222 mach_vm_size_t external_peak;1223 mach_vm_size_t reusable;1224 mach_vm_size_t reusable_peak;1225 mach_vm_size_t purgeable_volatile_pmap;1226 mach_vm_size_t purgeable_volatile_resident;1227 mach_vm_size_t purgeable_volatile_virtual;1228 mach_vm_size_t compressed;1229 mach_vm_size_t compressed_peak;1230 mach_vm_size_t compressed_lifetime;1231 mach_vm_size_t phys_footprint;1232 mach_vm_address_t min_address;1233 mach_vm_address_t max_address;1234};1235#define __SANITIZER_TASK_VM_INFO_COUNT ((mach_msg_type_number_t) \1236 (sizeof(__sanitizer_task_vm_info) / sizeof(natural_t)))1237 1238static uptr GetTaskInfoMaxAddress() {1239 __sanitizer_task_vm_info vm_info = {} /* zero initialize */;1240 mach_msg_type_number_t count = __SANITIZER_TASK_VM_INFO_COUNT;1241 int err = task_info(mach_task_self(), TASK_VM_INFO, (int *)&vm_info, &count);1242 return err ? 0 : vm_info.max_address;1243}1244 1245uptr GetMaxUserVirtualAddress() {1246 static uptr max_vm = GetTaskInfoMaxAddress();1247 if (max_vm != 0) {1248 const uptr ret_value = max_vm - 1;1249 CHECK_LE(ret_value, SANITIZER_MMAP_RANGE_SIZE);1250 return ret_value;1251 }1252 1253 // xnu cannot provide vm address limit1254# if SANITIZER_WORDSIZE == 321255 constexpr uptr fallback_max_vm = 0xffe00000 - 1;1256# else1257 constexpr uptr fallback_max_vm = 0x200000000 - 1;1258# endif1259 static_assert(fallback_max_vm <= SANITIZER_MMAP_RANGE_SIZE,1260 "Max virtual address must be less than mmap range size.");1261 return fallback_max_vm;1262}1263 1264#else // !SANITIZER_IOS1265 1266uptr GetMaxUserVirtualAddress() {1267# if SANITIZER_WORDSIZE == 641268 constexpr uptr max_vm = (1ULL << 47) - 1; // 0x00007fffffffffffUL;1269# else // SANITIZER_WORDSIZE == 321270 static_assert(SANITIZER_WORDSIZE == 32, "Wrong wordsize");1271 constexpr uptr max_vm = (1ULL << 32) - 1; // 0xffffffff;1272# endif1273 static_assert(max_vm <= SANITIZER_MMAP_RANGE_SIZE,1274 "Max virtual address must be less than mmap range size.");1275 return max_vm;1276}1277#endif1278 1279uptr GetMaxVirtualAddress() {1280 return GetMaxUserVirtualAddress();1281}1282 1283uptr MapDynamicShadow(uptr shadow_size_bytes, uptr shadow_scale,1284 uptr min_shadow_base_alignment, uptr &high_mem_end,1285 uptr granularity) {1286 const uptr alignment =1287 Max<uptr>(granularity << shadow_scale, 1ULL << min_shadow_base_alignment);1288 const uptr left_padding =1289 Max<uptr>(granularity, 1ULL << min_shadow_base_alignment);1290 1291 uptr space_size = shadow_size_bytes;1292 1293 uptr largest_gap_found = 0;1294 uptr max_occupied_addr = 0;1295 1296 VReport(2, "FindDynamicShadowStart, space_size = %p\n", (void *)space_size);1297 uptr shadow_start =1298 FindAvailableMemoryRange(space_size, alignment, left_padding,1299 &largest_gap_found, &max_occupied_addr);1300 // If the shadow doesn't fit, restrict the address space to make it fit.1301 if (shadow_start == 0) {1302 VReport(1303 2,1304 "Shadow doesn't fit, largest_gap_found = %p, max_occupied_addr = %p\n",1305 (void *)largest_gap_found, (void *)max_occupied_addr);1306 uptr new_max_vm = RoundDownTo(largest_gap_found << shadow_scale, alignment);1307 if (new_max_vm < max_occupied_addr) {1308 Report("Unable to find a memory range for dynamic shadow.\n");1309 Report(1310 "\tspace_size = %p\n\tlargest_gap_found = %p\n\tmax_occupied_addr "1311 "= %p\n\tnew_max_vm = %p\n",1312 (void*)space_size, (void*)largest_gap_found, (void*)max_occupied_addr,1313 (void*)new_max_vm);1314 ReportShadowAllocFail(shadow_size_bytes, alignment);1315 CHECK(0 && "cannot place shadow");1316 }1317 RestrictMemoryToMaxAddress(new_max_vm);1318 high_mem_end = new_max_vm - 1;1319 space_size = (high_mem_end >> shadow_scale);1320 VReport(2, "FindDynamicShadowStart, space_size = %p\n", (void *)space_size);1321 shadow_start = FindAvailableMemoryRange(space_size, alignment, left_padding,1322 nullptr, nullptr);1323 if (shadow_start == 0) {1324 Report("Unable to find a memory range after restricting VM.\n");1325 ReportShadowAllocFail(shadow_size_bytes, alignment);1326 CHECK(0 && "cannot place shadow after restricting vm");1327 }1328 }1329 CHECK_NE((uptr)0, shadow_start);1330 CHECK(IsAligned(shadow_start, alignment));1331 return shadow_start;1332}1333 1334uptr MapDynamicShadowAndAliases(uptr shadow_size, uptr alias_size,1335 uptr num_aliases, uptr ring_buffer_size) {1336 CHECK(false && "HWASan aliasing is unimplemented on Mac");1337 return 0;1338}1339 1340uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding,1341 uptr* largest_gap_found,1342 uptr* max_occupied_addr) {1343 const mach_vm_address_t max_vm_address = GetMaxVirtualAddress() + 1;1344 mach_vm_address_t address = GAP_SEARCH_START_ADDRESS;1345 mach_vm_address_t free_begin = GAP_SEARCH_START_ADDRESS;1346 kern_return_t kr = KERN_SUCCESS;1347 if (largest_gap_found) *largest_gap_found = 0;1348 if (max_occupied_addr) *max_occupied_addr = 0;1349 while (kr == KERN_SUCCESS) {1350 mach_vm_size_t vmsize = 0;1351 natural_t depth = 0;1352 vm_region_submap_short_info_data_64_t vminfo;1353 mach_msg_type_number_t count = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64;1354 kr = mach_vm_region_recurse(mach_task_self(), &address, &vmsize, &depth,1355 (vm_region_info_t)&vminfo, &count);1356 1357 if (kr == KERN_SUCCESS) {1358 // There are cases where going beyond the processes' max vm does1359 // not return KERN_INVALID_ADDRESS so we check for going beyond that1360 // max address as well.1361 if (address > max_vm_address) {1362 address = max_vm_address;1363 kr = -1; // break after this iteration.1364 }1365 1366 if (max_occupied_addr)1367 *max_occupied_addr = address + vmsize;1368 } else if (kr == KERN_INVALID_ADDRESS) {1369 // No more regions beyond "address", consider the gap at the end of VM.1370 address = max_vm_address;1371 1372 // We will break after this iteration anyway since kr != KERN_SUCCESS1373 } else if (kr == KERN_DENIED) {1374 Report("ERROR: Unable to find a memory range for dynamic shadow.\n");1375 Report("HINT: Ensure mach_vm_region_recurse is allowed under sandbox.\n");1376 Die();1377 } else {1378 Report(1379 "WARNING: mach_vm_region_recurse returned unexpected code %d (%s)\n",1380 kr, mach_error_string(kr));1381 DCHECK(false && "mach_vm_region_recurse returned unexpected code");1382 break; // address is not valid unless KERN_SUCCESS, therefore we must not1383 // use it.1384 }1385 1386 if (free_begin != address) {1387 // We found a free region [free_begin..address-1].1388 uptr gap_start = RoundUpTo((uptr)free_begin + left_padding, alignment);1389 uptr gap_end = RoundDownTo((uptr)Min(address, max_vm_address), alignment);1390 uptr gap_size = gap_end > gap_start ? gap_end - gap_start : 0;1391 if (size < gap_size) {1392 return gap_start;1393 }1394 1395 if (largest_gap_found && *largest_gap_found < gap_size) {1396 *largest_gap_found = gap_size;1397 }1398 }1399 // Move to the next region.1400 address += vmsize;1401 free_begin = address;1402 }1403 1404 // We looked at all free regions and could not find one large enough.1405 return 0;1406}1407 1408// This function (when used during initialization when there is1409// only a single thread), can be used to verify that a range1410// of memory hasn't already been mapped, and won't be mapped1411// later in the shared cache.1412//1413// If the syscall mach_vm_region_recurse fails (due to sandbox),1414// we assume that the memory is not mapped so that execution can continue.1415//1416// NOTE: range_end is inclusive1417//1418// WARNING: This function must NOT allocate memory, since it is1419// used in InitializeShadowMemory between where we search for1420// space for shadow and where we actually allocate it.1421bool MemoryRangeIsAvailable(uptr range_start, uptr range_end) {1422 mach_vm_size_t vmsize = 0;1423 natural_t depth = 0;1424 vm_region_submap_short_info_data_64_t vminfo;1425 mach_msg_type_number_t count = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64;1426 mach_vm_address_t address = range_start;1427 1428 // First, check if the range is already mapped.1429 kern_return_t kr =1430 mach_vm_region_recurse(mach_task_self(), &address, &vmsize, &depth,1431 (vm_region_info_t)&vminfo, &count);1432 1433 if (kr == KERN_DENIED) {1434 Report(1435 "WARN: mach_vm_region_recurse returned KERN_DENIED when checking "1436 "whether an address is mapped.\n");1437 Report("HINT: Is mach_vm_region_recurse allowed by sandbox?\n");1438 }1439 1440 if (kr == KERN_SUCCESS && !IntervalsAreSeparate(address, address + vmsize - 1,1441 range_start, range_end)) {1442 // Overlaps with already-mapped memory1443 return false;1444 }1445 1446 size_t cacheLength;1447 uptr cacheStart = (uptr)_dyld_get_shared_cache_range(&cacheLength);1448 1449 if (cacheStart &&1450 !IntervalsAreSeparate(cacheStart, cacheStart + cacheLength - 1,1451 range_start, range_end)) {1452 // Overlaps with shared cache region1453 return false;1454 }1455 1456 // We believe this address is available.1457 return true;1458}1459 1460// FIXME implement on this platform.1461void GetMemoryProfile(fill_profile_f cb, uptr *stats) {}1462 1463void SignalContext::DumpAllRegisters(void *context) {1464 Report("Register values:\n");1465 1466 ucontext_t *ucontext = (ucontext_t*)context;1467# define DUMPREG64(r) \1468 Printf("%s = 0x%016llx ", #r, ucontext->uc_mcontext->__ss.__ ## r);1469# define DUMPREGA64(r) \1470 Printf(" %s = 0x%016lx ", #r, AARCH64_GET_REG(r));1471# define DUMPREG32(r) \1472 Printf("%s = 0x%08x ", #r, ucontext->uc_mcontext->__ss.__ ## r);1473# define DUMPREG_(r) Printf(" "); DUMPREG(r);1474# define DUMPREG__(r) Printf(" "); DUMPREG(r);1475# define DUMPREG___(r) Printf(" "); DUMPREG(r);1476 1477# if defined(__x86_64__)1478# define DUMPREG(r) DUMPREG64(r)1479 DUMPREG(rax); DUMPREG(rbx); DUMPREG(rcx); DUMPREG(rdx); Printf("\n");1480 DUMPREG(rdi); DUMPREG(rsi); DUMPREG(rbp); DUMPREG(rsp); Printf("\n");1481 DUMPREG_(r8); DUMPREG_(r9); DUMPREG(r10); DUMPREG(r11); Printf("\n");1482 DUMPREG(r12); DUMPREG(r13); DUMPREG(r14); DUMPREG(r15); Printf("\n");1483# elif defined(__i386__)1484# define DUMPREG(r) DUMPREG32(r)1485 DUMPREG(eax); DUMPREG(ebx); DUMPREG(ecx); DUMPREG(edx); Printf("\n");1486 DUMPREG(edi); DUMPREG(esi); DUMPREG(ebp); DUMPREG(esp); Printf("\n");1487# elif defined(__aarch64__)1488# define DUMPREG(r) DUMPREG64(r)1489 DUMPREG_(x[0]); DUMPREG_(x[1]); DUMPREG_(x[2]); DUMPREG_(x[3]); Printf("\n");1490 DUMPREG_(x[4]); DUMPREG_(x[5]); DUMPREG_(x[6]); DUMPREG_(x[7]); Printf("\n");1491 DUMPREG_(x[8]); DUMPREG_(x[9]); DUMPREG(x[10]); DUMPREG(x[11]); Printf("\n");1492 DUMPREG(x[12]); DUMPREG(x[13]); DUMPREG(x[14]); DUMPREG(x[15]); Printf("\n");1493 DUMPREG(x[16]); DUMPREG(x[17]); DUMPREG(x[18]); DUMPREG(x[19]); Printf("\n");1494 DUMPREG(x[20]); DUMPREG(x[21]); DUMPREG(x[22]); DUMPREG(x[23]); Printf("\n");1495 DUMPREG(x[24]); DUMPREG(x[25]); DUMPREG(x[26]); DUMPREG(x[27]); Printf("\n");1496 DUMPREG(x[28]); DUMPREGA64(fp); DUMPREGA64(lr); DUMPREGA64(sp); Printf("\n");1497# elif defined(__arm__)1498# define DUMPREG(r) DUMPREG32(r)1499 DUMPREG_(r[0]); DUMPREG_(r[1]); DUMPREG_(r[2]); DUMPREG_(r[3]); Printf("\n");1500 DUMPREG_(r[4]); DUMPREG_(r[5]); DUMPREG_(r[6]); DUMPREG_(r[7]); Printf("\n");1501 DUMPREG_(r[8]); DUMPREG_(r[9]); DUMPREG(r[10]); DUMPREG(r[11]); Printf("\n");1502 DUMPREG(r[12]); DUMPREG___(sp); DUMPREG___(lr); DUMPREG___(pc); Printf("\n");1503# else1504# error "Unknown architecture"1505# endif1506 1507# undef DUMPREG641508# undef DUMPREG321509# undef DUMPREG_1510# undef DUMPREG__1511# undef DUMPREG___1512# undef DUMPREG1513}1514 1515static inline bool CompareBaseAddress(const LoadedModule &a,1516 const LoadedModule &b) {1517 return a.base_address() < b.base_address();1518}1519 1520void FormatUUID(char *out, uptr size, const u8 *uuid) {1521 internal_snprintf(out, size,1522 "<%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-"1523 "%02X%02X%02X%02X%02X%02X>",1524 uuid[0], uuid[1], uuid[2], uuid[3], uuid[4], uuid[5],1525 uuid[6], uuid[7], uuid[8], uuid[9], uuid[10], uuid[11],1526 uuid[12], uuid[13], uuid[14], uuid[15]);1527}1528 1529void DumpProcessMap() {1530 Printf("Process module map:\n");1531 MemoryMappingLayout memory_mapping(false);1532 InternalMmapVector<LoadedModule> modules;1533 modules.reserve(128);1534 memory_mapping.DumpListOfModules(&modules);1535 Sort(modules.data(), modules.size(), CompareBaseAddress);1536 for (uptr i = 0; i < modules.size(); ++i) {1537 char uuid_str[128];1538 FormatUUID(uuid_str, sizeof(uuid_str), modules[i].uuid());1539 Printf("%p-%p %s (%s) %s\n", (void *)modules[i].base_address(),1540 (void *)modules[i].max_address(), modules[i].full_name(),1541 ModuleArchToString(modules[i].arch()), uuid_str);1542 }1543 Printf("End of module map.\n");1544}1545 1546void CheckNoDeepBind(const char *filename, int flag) {1547 // Do nothing.1548}1549 1550bool GetRandom(void *buffer, uptr length, bool blocking) {1551 if (!buffer || !length || length > 256)1552 return false;1553 // arc4random never fails.1554 REAL(arc4random_buf)(buffer, length);1555 return true;1556}1557 1558u32 GetNumberOfCPUs() {1559 return (u32)sysconf(_SC_NPROCESSORS_ONLN);1560}1561 1562void InitializePlatformCommonFlags(CommonFlags *cf) {}1563 1564// Pthread introspection hook1565//1566// * GCD worker threads are created without a call to pthread_create(), but we1567// still need to register these threads (with ThreadCreate/Start()).1568// * We use the "pthread introspection hook" below to observe the creation of1569// such threads.1570// * GCD worker threads don't have parent threads and the CREATE event is1571// delivered in the context of the thread itself. CREATE events for regular1572// threads, are delivered on the parent. We use this to tell apart which1573// threads are GCD workers with `thread == pthread_self()`.1574//1575static pthread_introspection_hook_t prev_pthread_introspection_hook;1576static ThreadEventCallbacks thread_event_callbacks;1577 1578static void sanitizer_pthread_introspection_hook(unsigned int event,1579 pthread_t thread, void *addr,1580 size_t size) {1581 // create -> start -> terminate -> destroy1582 // * create/destroy are usually (not guaranteed) delivered on the parent and1583 // track resource allocation/reclamation1584 // * start/terminate are guaranteed to be delivered in the context of the1585 // thread and give hooks into "just after (before) thread starts (stops)1586 // executing"1587 DCHECK(event >= PTHREAD_INTROSPECTION_THREAD_CREATE &&1588 event <= PTHREAD_INTROSPECTION_THREAD_DESTROY);1589 1590 if (event == PTHREAD_INTROSPECTION_THREAD_CREATE) {1591 bool gcd_worker = (thread == pthread_self());1592 if (thread_event_callbacks.create)1593 thread_event_callbacks.create((uptr)thread, gcd_worker);1594 } else if (event == PTHREAD_INTROSPECTION_THREAD_START) {1595 CHECK_EQ(thread, pthread_self());1596 if (thread_event_callbacks.start)1597 thread_event_callbacks.start((uptr)thread);1598 }1599 1600 if (prev_pthread_introspection_hook)1601 prev_pthread_introspection_hook(event, thread, addr, size);1602 1603 if (event == PTHREAD_INTROSPECTION_THREAD_TERMINATE) {1604 CHECK_EQ(thread, pthread_self());1605 if (thread_event_callbacks.terminate)1606 thread_event_callbacks.terminate((uptr)thread);1607 } else if (event == PTHREAD_INTROSPECTION_THREAD_DESTROY) {1608 if (thread_event_callbacks.destroy)1609 thread_event_callbacks.destroy((uptr)thread);1610 }1611}1612 1613void InstallPthreadIntrospectionHook(const ThreadEventCallbacks &callbacks) {1614 thread_event_callbacks = callbacks;1615 prev_pthread_introspection_hook =1616 pthread_introspection_hook_install(&sanitizer_pthread_introspection_hook);1617}1618 1619} // namespace __sanitizer1620 1621#endif // SANITIZER_APPLE1622