1*68d75effSDimitry Andric //===-- asan_mac.cpp ------------------------------------------------------===// 2*68d75effSDimitry Andric // 3*68d75effSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*68d75effSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*68d75effSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*68d75effSDimitry Andric // 7*68d75effSDimitry Andric //===----------------------------------------------------------------------===// 8*68d75effSDimitry Andric // 9*68d75effSDimitry Andric // This file is a part of AddressSanitizer, an address sanity checker. 10*68d75effSDimitry Andric // 11*68d75effSDimitry Andric // Mac-specific details. 12*68d75effSDimitry Andric //===----------------------------------------------------------------------===// 13*68d75effSDimitry Andric 14*68d75effSDimitry Andric #include "sanitizer_common/sanitizer_platform.h" 15*68d75effSDimitry Andric #if SANITIZER_MAC 16*68d75effSDimitry Andric 17*68d75effSDimitry Andric #include "asan_interceptors.h" 18*68d75effSDimitry Andric #include "asan_internal.h" 19*68d75effSDimitry Andric #include "asan_mapping.h" 20*68d75effSDimitry Andric #include "asan_stack.h" 21*68d75effSDimitry Andric #include "asan_thread.h" 22*68d75effSDimitry Andric #include "sanitizer_common/sanitizer_atomic.h" 23*68d75effSDimitry Andric #include "sanitizer_common/sanitizer_libc.h" 24*68d75effSDimitry Andric #include "sanitizer_common/sanitizer_mac.h" 25*68d75effSDimitry Andric 26*68d75effSDimitry Andric #include <dlfcn.h> 27*68d75effSDimitry Andric #include <fcntl.h> 28*68d75effSDimitry Andric #include <libkern/OSAtomic.h> 29*68d75effSDimitry Andric #include <mach-o/dyld.h> 30*68d75effSDimitry Andric #include <mach-o/getsect.h> 31*68d75effSDimitry Andric #include <mach-o/loader.h> 32*68d75effSDimitry Andric #include <pthread.h> 33*68d75effSDimitry Andric #include <stdlib.h> // for free() 34*68d75effSDimitry Andric #include <sys/mman.h> 35*68d75effSDimitry Andric #include <sys/resource.h> 36*68d75effSDimitry Andric #include <sys/sysctl.h> 37*68d75effSDimitry Andric #include <sys/ucontext.h> 38*68d75effSDimitry Andric #include <unistd.h> 39*68d75effSDimitry Andric 40*68d75effSDimitry Andric // from <crt_externs.h>, but we don't have that file on iOS 41*68d75effSDimitry Andric extern "C" { 42*68d75effSDimitry Andric extern char ***_NSGetArgv(void); 43*68d75effSDimitry Andric extern char ***_NSGetEnviron(void); 44*68d75effSDimitry Andric } 45*68d75effSDimitry Andric 46*68d75effSDimitry Andric namespace __asan { 47*68d75effSDimitry Andric 48*68d75effSDimitry Andric void InitializePlatformInterceptors() {} 49*68d75effSDimitry Andric void InitializePlatformExceptionHandlers() {} 50*68d75effSDimitry Andric bool IsSystemHeapAddress (uptr addr) { return false; } 51*68d75effSDimitry Andric 52*68d75effSDimitry Andric // No-op. Mac does not support static linkage anyway. 53*68d75effSDimitry Andric void *AsanDoesNotSupportStaticLinkage() { 54*68d75effSDimitry Andric return 0; 55*68d75effSDimitry Andric } 56*68d75effSDimitry Andric 57*68d75effSDimitry Andric uptr FindDynamicShadowStart() { 58*68d75effSDimitry Andric uptr granularity = GetMmapGranularity(); 59*68d75effSDimitry Andric uptr alignment = 8 * granularity; 60*68d75effSDimitry Andric uptr left_padding = granularity; 61*68d75effSDimitry Andric uptr space_size = kHighShadowEnd + left_padding; 62*68d75effSDimitry Andric 63*68d75effSDimitry Andric uptr largest_gap_found = 0; 64*68d75effSDimitry Andric uptr max_occupied_addr = 0; 65*68d75effSDimitry Andric VReport(2, "FindDynamicShadowStart, space_size = %p\n", space_size); 66*68d75effSDimitry Andric uptr shadow_start = 67*68d75effSDimitry Andric FindAvailableMemoryRange(space_size, alignment, granularity, 68*68d75effSDimitry Andric &largest_gap_found, &max_occupied_addr); 69*68d75effSDimitry Andric // If the shadow doesn't fit, restrict the address space to make it fit. 70*68d75effSDimitry Andric if (shadow_start == 0) { 71*68d75effSDimitry Andric VReport( 72*68d75effSDimitry Andric 2, 73*68d75effSDimitry Andric "Shadow doesn't fit, largest_gap_found = %p, max_occupied_addr = %p\n", 74*68d75effSDimitry Andric largest_gap_found, max_occupied_addr); 75*68d75effSDimitry Andric uptr new_max_vm = RoundDownTo(largest_gap_found << SHADOW_SCALE, alignment); 76*68d75effSDimitry Andric if (new_max_vm < max_occupied_addr) { 77*68d75effSDimitry Andric Report("Unable to find a memory range for dynamic shadow.\n"); 78*68d75effSDimitry Andric Report( 79*68d75effSDimitry Andric "space_size = %p, largest_gap_found = %p, max_occupied_addr = %p, " 80*68d75effSDimitry Andric "new_max_vm = %p\n", 81*68d75effSDimitry Andric space_size, largest_gap_found, max_occupied_addr, new_max_vm); 82*68d75effSDimitry Andric CHECK(0 && "cannot place shadow"); 83*68d75effSDimitry Andric } 84*68d75effSDimitry Andric RestrictMemoryToMaxAddress(new_max_vm); 85*68d75effSDimitry Andric kHighMemEnd = new_max_vm - 1; 86*68d75effSDimitry Andric space_size = kHighShadowEnd + left_padding; 87*68d75effSDimitry Andric VReport(2, "FindDynamicShadowStart, space_size = %p\n", space_size); 88*68d75effSDimitry Andric shadow_start = FindAvailableMemoryRange(space_size, alignment, granularity, 89*68d75effSDimitry Andric nullptr, nullptr); 90*68d75effSDimitry Andric if (shadow_start == 0) { 91*68d75effSDimitry Andric Report("Unable to find a memory range after restricting VM.\n"); 92*68d75effSDimitry Andric CHECK(0 && "cannot place shadow after restricting vm"); 93*68d75effSDimitry Andric } 94*68d75effSDimitry Andric } 95*68d75effSDimitry Andric CHECK_NE((uptr)0, shadow_start); 96*68d75effSDimitry Andric CHECK(IsAligned(shadow_start, alignment)); 97*68d75effSDimitry Andric return shadow_start; 98*68d75effSDimitry Andric } 99*68d75effSDimitry Andric 100*68d75effSDimitry Andric // No-op. Mac does not support static linkage anyway. 101*68d75effSDimitry Andric void AsanCheckDynamicRTPrereqs() {} 102*68d75effSDimitry Andric 103*68d75effSDimitry Andric // No-op. Mac does not support static linkage anyway. 104*68d75effSDimitry Andric void AsanCheckIncompatibleRT() {} 105*68d75effSDimitry Andric 106*68d75effSDimitry Andric void AsanApplyToGlobals(globals_op_fptr op, const void *needle) { 107*68d75effSDimitry Andric // Find the Mach-O header for the image containing the needle 108*68d75effSDimitry Andric Dl_info info; 109*68d75effSDimitry Andric int err = dladdr(needle, &info); 110*68d75effSDimitry Andric if (err == 0) return; 111*68d75effSDimitry Andric 112*68d75effSDimitry Andric #if __LP64__ 113*68d75effSDimitry Andric const struct mach_header_64 *mh = (struct mach_header_64 *)info.dli_fbase; 114*68d75effSDimitry Andric #else 115*68d75effSDimitry Andric const struct mach_header *mh = (struct mach_header *)info.dli_fbase; 116*68d75effSDimitry Andric #endif 117*68d75effSDimitry Andric 118*68d75effSDimitry Andric // Look up the __asan_globals section in that image and register its globals 119*68d75effSDimitry Andric unsigned long size = 0; 120*68d75effSDimitry Andric __asan_global *globals = (__asan_global *)getsectiondata( 121*68d75effSDimitry Andric mh, 122*68d75effSDimitry Andric "__DATA", "__asan_globals", 123*68d75effSDimitry Andric &size); 124*68d75effSDimitry Andric 125*68d75effSDimitry Andric if (!globals) return; 126*68d75effSDimitry Andric if (size % sizeof(__asan_global) != 0) return; 127*68d75effSDimitry Andric op(globals, size / sizeof(__asan_global)); 128*68d75effSDimitry Andric } 129*68d75effSDimitry Andric 130*68d75effSDimitry Andric void ReadContextStack(void *context, uptr *stack, uptr *ssize) { 131*68d75effSDimitry Andric UNIMPLEMENTED(); 132*68d75effSDimitry Andric } 133*68d75effSDimitry Andric 134*68d75effSDimitry Andric // Support for the following functions from libdispatch on Mac OS: 135*68d75effSDimitry Andric // dispatch_async_f() 136*68d75effSDimitry Andric // dispatch_async() 137*68d75effSDimitry Andric // dispatch_sync_f() 138*68d75effSDimitry Andric // dispatch_sync() 139*68d75effSDimitry Andric // dispatch_after_f() 140*68d75effSDimitry Andric // dispatch_after() 141*68d75effSDimitry Andric // dispatch_group_async_f() 142*68d75effSDimitry Andric // dispatch_group_async() 143*68d75effSDimitry Andric // TODO(glider): libdispatch API contains other functions that we don't support 144*68d75effSDimitry Andric // yet. 145*68d75effSDimitry Andric // 146*68d75effSDimitry Andric // dispatch_sync() and dispatch_sync_f() are synchronous, although chances are 147*68d75effSDimitry Andric // they can cause jobs to run on a thread different from the current one. 148*68d75effSDimitry Andric // TODO(glider): if so, we need a test for this (otherwise we should remove 149*68d75effSDimitry Andric // them). 150*68d75effSDimitry Andric // 151*68d75effSDimitry Andric // The following functions use dispatch_barrier_async_f() (which isn't a library 152*68d75effSDimitry Andric // function but is exported) and are thus supported: 153*68d75effSDimitry Andric // dispatch_source_set_cancel_handler_f() 154*68d75effSDimitry Andric // dispatch_source_set_cancel_handler() 155*68d75effSDimitry Andric // dispatch_source_set_event_handler_f() 156*68d75effSDimitry Andric // dispatch_source_set_event_handler() 157*68d75effSDimitry Andric // 158*68d75effSDimitry Andric // The reference manual for Grand Central Dispatch is available at 159*68d75effSDimitry Andric // http://developer.apple.com/library/mac/#documentation/Performance/Reference/GCD_libdispatch_Ref/Reference/reference.html 160*68d75effSDimitry Andric // The implementation details are at 161*68d75effSDimitry Andric // http://libdispatch.macosforge.org/trac/browser/trunk/src/queue.c 162*68d75effSDimitry Andric 163*68d75effSDimitry Andric typedef void* dispatch_group_t; 164*68d75effSDimitry Andric typedef void* dispatch_queue_t; 165*68d75effSDimitry Andric typedef void* dispatch_source_t; 166*68d75effSDimitry Andric typedef u64 dispatch_time_t; 167*68d75effSDimitry Andric typedef void (*dispatch_function_t)(void *block); 168*68d75effSDimitry Andric typedef void* (*worker_t)(void *block); 169*68d75effSDimitry Andric 170*68d75effSDimitry Andric // A wrapper for the ObjC blocks used to support libdispatch. 171*68d75effSDimitry Andric typedef struct { 172*68d75effSDimitry Andric void *block; 173*68d75effSDimitry Andric dispatch_function_t func; 174*68d75effSDimitry Andric u32 parent_tid; 175*68d75effSDimitry Andric } asan_block_context_t; 176*68d75effSDimitry Andric 177*68d75effSDimitry Andric ALWAYS_INLINE 178*68d75effSDimitry Andric void asan_register_worker_thread(int parent_tid, StackTrace *stack) { 179*68d75effSDimitry Andric AsanThread *t = GetCurrentThread(); 180*68d75effSDimitry Andric if (!t) { 181*68d75effSDimitry Andric t = AsanThread::Create(/* start_routine */ nullptr, /* arg */ nullptr, 182*68d75effSDimitry Andric parent_tid, stack, /* detached */ true); 183*68d75effSDimitry Andric t->Init(); 184*68d75effSDimitry Andric asanThreadRegistry().StartThread(t->tid(), GetTid(), ThreadType::Worker, 185*68d75effSDimitry Andric nullptr); 186*68d75effSDimitry Andric SetCurrentThread(t); 187*68d75effSDimitry Andric } 188*68d75effSDimitry Andric } 189*68d75effSDimitry Andric 190*68d75effSDimitry Andric // For use by only those functions that allocated the context via 191*68d75effSDimitry Andric // alloc_asan_context(). 192*68d75effSDimitry Andric extern "C" 193*68d75effSDimitry Andric void asan_dispatch_call_block_and_release(void *block) { 194*68d75effSDimitry Andric GET_STACK_TRACE_THREAD; 195*68d75effSDimitry Andric asan_block_context_t *context = (asan_block_context_t*)block; 196*68d75effSDimitry Andric VReport(2, 197*68d75effSDimitry Andric "asan_dispatch_call_block_and_release(): " 198*68d75effSDimitry Andric "context: %p, pthread_self: %p\n", 199*68d75effSDimitry Andric block, pthread_self()); 200*68d75effSDimitry Andric asan_register_worker_thread(context->parent_tid, &stack); 201*68d75effSDimitry Andric // Call the original dispatcher for the block. 202*68d75effSDimitry Andric context->func(context->block); 203*68d75effSDimitry Andric asan_free(context, &stack, FROM_MALLOC); 204*68d75effSDimitry Andric } 205*68d75effSDimitry Andric 206*68d75effSDimitry Andric } // namespace __asan 207*68d75effSDimitry Andric 208*68d75effSDimitry Andric using namespace __asan; 209*68d75effSDimitry Andric 210*68d75effSDimitry Andric // Wrap |ctxt| and |func| into an asan_block_context_t. 211*68d75effSDimitry Andric // The caller retains control of the allocated context. 212*68d75effSDimitry Andric extern "C" 213*68d75effSDimitry Andric asan_block_context_t *alloc_asan_context(void *ctxt, dispatch_function_t func, 214*68d75effSDimitry Andric BufferedStackTrace *stack) { 215*68d75effSDimitry Andric asan_block_context_t *asan_ctxt = 216*68d75effSDimitry Andric (asan_block_context_t*) asan_malloc(sizeof(asan_block_context_t), stack); 217*68d75effSDimitry Andric asan_ctxt->block = ctxt; 218*68d75effSDimitry Andric asan_ctxt->func = func; 219*68d75effSDimitry Andric asan_ctxt->parent_tid = GetCurrentTidOrInvalid(); 220*68d75effSDimitry Andric return asan_ctxt; 221*68d75effSDimitry Andric } 222*68d75effSDimitry Andric 223*68d75effSDimitry Andric // Define interceptor for dispatch_*_f function with the three most common 224*68d75effSDimitry Andric // parameters: dispatch_queue_t, context, dispatch_function_t. 225*68d75effSDimitry Andric #define INTERCEPT_DISPATCH_X_F_3(dispatch_x_f) \ 226*68d75effSDimitry Andric INTERCEPTOR(void, dispatch_x_f, dispatch_queue_t dq, void *ctxt, \ 227*68d75effSDimitry Andric dispatch_function_t func) { \ 228*68d75effSDimitry Andric GET_STACK_TRACE_THREAD; \ 229*68d75effSDimitry Andric asan_block_context_t *asan_ctxt = alloc_asan_context(ctxt, func, &stack); \ 230*68d75effSDimitry Andric if (Verbosity() >= 2) { \ 231*68d75effSDimitry Andric Report(#dispatch_x_f "(): context: %p, pthread_self: %p\n", \ 232*68d75effSDimitry Andric asan_ctxt, pthread_self()); \ 233*68d75effSDimitry Andric PRINT_CURRENT_STACK(); \ 234*68d75effSDimitry Andric } \ 235*68d75effSDimitry Andric return REAL(dispatch_x_f)(dq, (void*)asan_ctxt, \ 236*68d75effSDimitry Andric asan_dispatch_call_block_and_release); \ 237*68d75effSDimitry Andric } 238*68d75effSDimitry Andric 239*68d75effSDimitry Andric INTERCEPT_DISPATCH_X_F_3(dispatch_async_f) 240*68d75effSDimitry Andric INTERCEPT_DISPATCH_X_F_3(dispatch_sync_f) 241*68d75effSDimitry Andric INTERCEPT_DISPATCH_X_F_3(dispatch_barrier_async_f) 242*68d75effSDimitry Andric 243*68d75effSDimitry Andric INTERCEPTOR(void, dispatch_after_f, dispatch_time_t when, 244*68d75effSDimitry Andric dispatch_queue_t dq, void *ctxt, 245*68d75effSDimitry Andric dispatch_function_t func) { 246*68d75effSDimitry Andric GET_STACK_TRACE_THREAD; 247*68d75effSDimitry Andric asan_block_context_t *asan_ctxt = alloc_asan_context(ctxt, func, &stack); 248*68d75effSDimitry Andric if (Verbosity() >= 2) { 249*68d75effSDimitry Andric Report("dispatch_after_f: %p\n", asan_ctxt); 250*68d75effSDimitry Andric PRINT_CURRENT_STACK(); 251*68d75effSDimitry Andric } 252*68d75effSDimitry Andric return REAL(dispatch_after_f)(when, dq, (void*)asan_ctxt, 253*68d75effSDimitry Andric asan_dispatch_call_block_and_release); 254*68d75effSDimitry Andric } 255*68d75effSDimitry Andric 256*68d75effSDimitry Andric INTERCEPTOR(void, dispatch_group_async_f, dispatch_group_t group, 257*68d75effSDimitry Andric dispatch_queue_t dq, void *ctxt, 258*68d75effSDimitry Andric dispatch_function_t func) { 259*68d75effSDimitry Andric GET_STACK_TRACE_THREAD; 260*68d75effSDimitry Andric asan_block_context_t *asan_ctxt = alloc_asan_context(ctxt, func, &stack); 261*68d75effSDimitry Andric if (Verbosity() >= 2) { 262*68d75effSDimitry Andric Report("dispatch_group_async_f(): context: %p, pthread_self: %p\n", 263*68d75effSDimitry Andric asan_ctxt, pthread_self()); 264*68d75effSDimitry Andric PRINT_CURRENT_STACK(); 265*68d75effSDimitry Andric } 266*68d75effSDimitry Andric REAL(dispatch_group_async_f)(group, dq, (void*)asan_ctxt, 267*68d75effSDimitry Andric asan_dispatch_call_block_and_release); 268*68d75effSDimitry Andric } 269*68d75effSDimitry Andric 270*68d75effSDimitry Andric #if !defined(MISSING_BLOCKS_SUPPORT) 271*68d75effSDimitry Andric extern "C" { 272*68d75effSDimitry Andric void dispatch_async(dispatch_queue_t dq, void(^work)(void)); 273*68d75effSDimitry Andric void dispatch_group_async(dispatch_group_t dg, dispatch_queue_t dq, 274*68d75effSDimitry Andric void(^work)(void)); 275*68d75effSDimitry Andric void dispatch_after(dispatch_time_t when, dispatch_queue_t queue, 276*68d75effSDimitry Andric void(^work)(void)); 277*68d75effSDimitry Andric void dispatch_source_set_cancel_handler(dispatch_source_t ds, 278*68d75effSDimitry Andric void(^work)(void)); 279*68d75effSDimitry Andric void dispatch_source_set_event_handler(dispatch_source_t ds, void(^work)(void)); 280*68d75effSDimitry Andric } 281*68d75effSDimitry Andric 282*68d75effSDimitry Andric #define GET_ASAN_BLOCK(work) \ 283*68d75effSDimitry Andric void (^asan_block)(void); \ 284*68d75effSDimitry Andric int parent_tid = GetCurrentTidOrInvalid(); \ 285*68d75effSDimitry Andric asan_block = ^(void) { \ 286*68d75effSDimitry Andric GET_STACK_TRACE_THREAD; \ 287*68d75effSDimitry Andric asan_register_worker_thread(parent_tid, &stack); \ 288*68d75effSDimitry Andric work(); \ 289*68d75effSDimitry Andric } 290*68d75effSDimitry Andric 291*68d75effSDimitry Andric INTERCEPTOR(void, dispatch_async, 292*68d75effSDimitry Andric dispatch_queue_t dq, void(^work)(void)) { 293*68d75effSDimitry Andric ENABLE_FRAME_POINTER; 294*68d75effSDimitry Andric GET_ASAN_BLOCK(work); 295*68d75effSDimitry Andric REAL(dispatch_async)(dq, asan_block); 296*68d75effSDimitry Andric } 297*68d75effSDimitry Andric 298*68d75effSDimitry Andric INTERCEPTOR(void, dispatch_group_async, 299*68d75effSDimitry Andric dispatch_group_t dg, dispatch_queue_t dq, void(^work)(void)) { 300*68d75effSDimitry Andric ENABLE_FRAME_POINTER; 301*68d75effSDimitry Andric GET_ASAN_BLOCK(work); 302*68d75effSDimitry Andric REAL(dispatch_group_async)(dg, dq, asan_block); 303*68d75effSDimitry Andric } 304*68d75effSDimitry Andric 305*68d75effSDimitry Andric INTERCEPTOR(void, dispatch_after, 306*68d75effSDimitry Andric dispatch_time_t when, dispatch_queue_t queue, void(^work)(void)) { 307*68d75effSDimitry Andric ENABLE_FRAME_POINTER; 308*68d75effSDimitry Andric GET_ASAN_BLOCK(work); 309*68d75effSDimitry Andric REAL(dispatch_after)(when, queue, asan_block); 310*68d75effSDimitry Andric } 311*68d75effSDimitry Andric 312*68d75effSDimitry Andric INTERCEPTOR(void, dispatch_source_set_cancel_handler, 313*68d75effSDimitry Andric dispatch_source_t ds, void(^work)(void)) { 314*68d75effSDimitry Andric if (!work) { 315*68d75effSDimitry Andric REAL(dispatch_source_set_cancel_handler)(ds, work); 316*68d75effSDimitry Andric return; 317*68d75effSDimitry Andric } 318*68d75effSDimitry Andric ENABLE_FRAME_POINTER; 319*68d75effSDimitry Andric GET_ASAN_BLOCK(work); 320*68d75effSDimitry Andric REAL(dispatch_source_set_cancel_handler)(ds, asan_block); 321*68d75effSDimitry Andric } 322*68d75effSDimitry Andric 323*68d75effSDimitry Andric INTERCEPTOR(void, dispatch_source_set_event_handler, 324*68d75effSDimitry Andric dispatch_source_t ds, void(^work)(void)) { 325*68d75effSDimitry Andric ENABLE_FRAME_POINTER; 326*68d75effSDimitry Andric GET_ASAN_BLOCK(work); 327*68d75effSDimitry Andric REAL(dispatch_source_set_event_handler)(ds, asan_block); 328*68d75effSDimitry Andric } 329*68d75effSDimitry Andric #endif 330*68d75effSDimitry Andric 331*68d75effSDimitry Andric #endif // SANITIZER_MAC 332