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