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