asan_mac.cc 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419
  1. //===-- asan_mac.cc -------------------------------------------------------===//
  2. //
  3. // This file is distributed under the University of Illinois Open Source
  4. // License. See LICENSE.TXT for details.
  5. //
  6. //===----------------------------------------------------------------------===//
  7. //
  8. // This file is a part of AddressSanitizer, an address sanity checker.
  9. //
  10. // Mac-specific details.
  11. //===----------------------------------------------------------------------===//
  12. #include "sanitizer_common/sanitizer_platform.h"
  13. #if SANITIZER_MAC
  14. #include "asan_interceptors.h"
  15. #include "asan_internal.h"
  16. #include "asan_mapping.h"
  17. #include "asan_stack.h"
  18. #include "asan_thread.h"
  19. #include "sanitizer_common/sanitizer_atomic.h"
  20. #include "sanitizer_common/sanitizer_libc.h"
  21. #include "sanitizer_common/sanitizer_mac.h"
  22. #include <crt_externs.h> // for _NSGetArgv
  23. #include <dlfcn.h> // for dladdr()
  24. #include <mach-o/dyld.h>
  25. #include <mach-o/loader.h>
  26. #include <sys/mman.h>
  27. #include <sys/resource.h>
  28. #include <sys/sysctl.h>
  29. #include <sys/ucontext.h>
  30. #include <fcntl.h>
  31. #include <pthread.h>
  32. #include <stdlib.h> // for free()
  33. #include <unistd.h>
  34. #include <libkern/OSAtomic.h>
  35. namespace __asan {
  36. void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) {
  37. ucontext_t *ucontext = (ucontext_t*)context;
  38. # if SANITIZER_WORDSIZE == 64
  39. *pc = ucontext->uc_mcontext->__ss.__rip;
  40. *bp = ucontext->uc_mcontext->__ss.__rbp;
  41. *sp = ucontext->uc_mcontext->__ss.__rsp;
  42. # else
  43. *pc = ucontext->uc_mcontext->__ss.__eip;
  44. *bp = ucontext->uc_mcontext->__ss.__ebp;
  45. *sp = ucontext->uc_mcontext->__ss.__esp;
  46. # endif // SANITIZER_WORDSIZE
  47. }
  48. bool PlatformHasDifferentMemcpyAndMemmove() {
  49. // On OS X 10.7 memcpy() and memmove() are both resolved
  50. // into memmove$VARIANT$sse42.
  51. // See also http://code.google.com/p/address-sanitizer/issues/detail?id=34.
  52. // TODO(glider): need to check dynamically that memcpy() and memmove() are
  53. // actually the same function.
  54. return GetMacosVersion() == MACOS_VERSION_SNOW_LEOPARD;
  55. }
  56. extern "C"
  57. void __asan_init();
  58. static const char kDyldInsertLibraries[] = "DYLD_INSERT_LIBRARIES";
  59. LowLevelAllocator allocator_for_env;
  60. // Change the value of the env var |name|, leaking the original value.
  61. // If |name_value| is NULL, the variable is deleted from the environment,
  62. // otherwise the corresponding "NAME=value" string is replaced with
  63. // |name_value|.
  64. void LeakyResetEnv(const char *name, const char *name_value) {
  65. char ***env_ptr = _NSGetEnviron();
  66. CHECK(env_ptr);
  67. char **environ = *env_ptr;
  68. CHECK(environ);
  69. uptr name_len = internal_strlen(name);
  70. while (*environ != 0) {
  71. uptr len = internal_strlen(*environ);
  72. if (len > name_len) {
  73. const char *p = *environ;
  74. if (!internal_memcmp(p, name, name_len) && p[name_len] == '=') {
  75. // Match.
  76. if (name_value) {
  77. // Replace the old value with the new one.
  78. *environ = const_cast<char*>(name_value);
  79. } else {
  80. // Shift the subsequent pointers back.
  81. char **del = environ;
  82. do {
  83. del[0] = del[1];
  84. } while (*del++);
  85. }
  86. }
  87. }
  88. environ++;
  89. }
  90. }
  91. void MaybeReexec() {
  92. if (!flags()->allow_reexec) return;
  93. // Make sure the dynamic ASan runtime library is preloaded so that the
  94. // wrappers work. If it is not, set DYLD_INSERT_LIBRARIES and re-exec
  95. // ourselves.
  96. Dl_info info;
  97. CHECK(dladdr((void*)((uptr)__asan_init), &info));
  98. char *dyld_insert_libraries =
  99. const_cast<char*>(GetEnv(kDyldInsertLibraries));
  100. uptr old_env_len = dyld_insert_libraries ?
  101. internal_strlen(dyld_insert_libraries) : 0;
  102. uptr fname_len = internal_strlen(info.dli_fname);
  103. if (!dyld_insert_libraries ||
  104. !REAL(strstr)(dyld_insert_libraries, info.dli_fname)) {
  105. // DYLD_INSERT_LIBRARIES is not set or does not contain the runtime
  106. // library.
  107. char program_name[1024];
  108. uint32_t buf_size = sizeof(program_name);
  109. _NSGetExecutablePath(program_name, &buf_size);
  110. char *new_env = const_cast<char*>(info.dli_fname);
  111. if (dyld_insert_libraries) {
  112. // Append the runtime dylib name to the existing value of
  113. // DYLD_INSERT_LIBRARIES.
  114. new_env = (char*)allocator_for_env.Allocate(old_env_len + fname_len + 2);
  115. internal_strncpy(new_env, dyld_insert_libraries, old_env_len);
  116. new_env[old_env_len] = ':';
  117. // Copy fname_len and add a trailing zero.
  118. internal_strncpy(new_env + old_env_len + 1, info.dli_fname,
  119. fname_len + 1);
  120. // Ok to use setenv() since the wrappers don't depend on the value of
  121. // asan_inited.
  122. setenv(kDyldInsertLibraries, new_env, /*overwrite*/1);
  123. } else {
  124. // Set DYLD_INSERT_LIBRARIES equal to the runtime dylib name.
  125. setenv(kDyldInsertLibraries, info.dli_fname, /*overwrite*/0);
  126. }
  127. VReport(1, "exec()-ing the program with\n");
  128. VReport(1, "%s=%s\n", kDyldInsertLibraries, new_env);
  129. VReport(1, "to enable ASan wrappers.\n");
  130. VReport(1, "Set ASAN_OPTIONS=allow_reexec=0 to disable this.\n");
  131. execv(program_name, *_NSGetArgv());
  132. } else {
  133. // DYLD_INSERT_LIBRARIES is set and contains the runtime library.
  134. if (old_env_len == fname_len) {
  135. // It's just the runtime library name - fine to unset the variable.
  136. LeakyResetEnv(kDyldInsertLibraries, NULL);
  137. } else {
  138. uptr env_name_len = internal_strlen(kDyldInsertLibraries);
  139. // Allocate memory to hold the previous env var name, its value, the '='
  140. // sign and the '\0' char.
  141. char *new_env = (char*)allocator_for_env.Allocate(
  142. old_env_len + 2 + env_name_len);
  143. CHECK(new_env);
  144. internal_memset(new_env, '\0', old_env_len + 2 + env_name_len);
  145. internal_strncpy(new_env, kDyldInsertLibraries, env_name_len);
  146. new_env[env_name_len] = '=';
  147. char *new_env_pos = new_env + env_name_len + 1;
  148. // Iterate over colon-separated pieces of |dyld_insert_libraries|.
  149. char *piece_start = dyld_insert_libraries;
  150. char *piece_end = NULL;
  151. char *old_env_end = dyld_insert_libraries + old_env_len;
  152. do {
  153. if (piece_start[0] == ':') piece_start++;
  154. piece_end = REAL(strchr)(piece_start, ':');
  155. if (!piece_end) piece_end = dyld_insert_libraries + old_env_len;
  156. if ((uptr)(piece_start - dyld_insert_libraries) > old_env_len) break;
  157. uptr piece_len = piece_end - piece_start;
  158. // If the current piece isn't the runtime library name,
  159. // append it to new_env.
  160. if ((piece_len != fname_len) ||
  161. (internal_strncmp(piece_start, info.dli_fname, fname_len) != 0)) {
  162. if (new_env_pos != new_env + env_name_len + 1) {
  163. new_env_pos[0] = ':';
  164. new_env_pos++;
  165. }
  166. internal_strncpy(new_env_pos, piece_start, piece_len);
  167. }
  168. // Move on to the next piece.
  169. new_env_pos += piece_len;
  170. piece_start = piece_end;
  171. } while (piece_start < old_env_end);
  172. // Can't use setenv() here, because it requires the allocator to be
  173. // initialized.
  174. // FIXME: instead of filtering DYLD_INSERT_LIBRARIES here, do it in
  175. // a separate function called after InitializeAllocator().
  176. LeakyResetEnv(kDyldInsertLibraries, new_env);
  177. }
  178. }
  179. }
  180. // No-op. Mac does not support static linkage anyway.
  181. void *AsanDoesNotSupportStaticLinkage() {
  182. return 0;
  183. }
  184. // No-op. Mac does not support static linkage anyway.
  185. void AsanCheckDynamicRTPrereqs() {}
  186. // No-op. Mac does not support static linkage anyway.
  187. void AsanCheckIncompatibleRT() {}
  188. bool AsanInterceptsSignal(int signum) {
  189. return (signum == SIGSEGV || signum == SIGBUS) &&
  190. common_flags()->handle_segv;
  191. }
  192. void AsanPlatformThreadInit() {
  193. }
  194. void ReadContextStack(void *context, uptr *stack, uptr *ssize) {
  195. UNIMPLEMENTED();
  196. }
  197. // Support for the following functions from libdispatch on Mac OS:
  198. // dispatch_async_f()
  199. // dispatch_async()
  200. // dispatch_sync_f()
  201. // dispatch_sync()
  202. // dispatch_after_f()
  203. // dispatch_after()
  204. // dispatch_group_async_f()
  205. // dispatch_group_async()
  206. // TODO(glider): libdispatch API contains other functions that we don't support
  207. // yet.
  208. //
  209. // dispatch_sync() and dispatch_sync_f() are synchronous, although chances are
  210. // they can cause jobs to run on a thread different from the current one.
  211. // TODO(glider): if so, we need a test for this (otherwise we should remove
  212. // them).
  213. //
  214. // The following functions use dispatch_barrier_async_f() (which isn't a library
  215. // function but is exported) and are thus supported:
  216. // dispatch_source_set_cancel_handler_f()
  217. // dispatch_source_set_cancel_handler()
  218. // dispatch_source_set_event_handler_f()
  219. // dispatch_source_set_event_handler()
  220. //
  221. // The reference manual for Grand Central Dispatch is available at
  222. // http://developer.apple.com/library/mac/#documentation/Performance/Reference/GCD_libdispatch_Ref/Reference/reference.html
  223. // The implementation details are at
  224. // http://libdispatch.macosforge.org/trac/browser/trunk/src/queue.c
  225. typedef void* dispatch_group_t;
  226. typedef void* dispatch_queue_t;
  227. typedef void* dispatch_source_t;
  228. typedef u64 dispatch_time_t;
  229. typedef void (*dispatch_function_t)(void *block);
  230. typedef void* (*worker_t)(void *block);
  231. // A wrapper for the ObjC blocks used to support libdispatch.
  232. typedef struct {
  233. void *block;
  234. dispatch_function_t func;
  235. u32 parent_tid;
  236. } asan_block_context_t;
  237. ALWAYS_INLINE
  238. void asan_register_worker_thread(int parent_tid, StackTrace *stack) {
  239. AsanThread *t = GetCurrentThread();
  240. if (!t) {
  241. t = AsanThread::Create(0, 0);
  242. CreateThreadContextArgs args = { t, stack };
  243. asanThreadRegistry().CreateThread(*(uptr*)t, true, parent_tid, &args);
  244. t->Init();
  245. asanThreadRegistry().StartThread(t->tid(), 0, 0);
  246. SetCurrentThread(t);
  247. }
  248. }
  249. // For use by only those functions that allocated the context via
  250. // alloc_asan_context().
  251. extern "C"
  252. void asan_dispatch_call_block_and_release(void *block) {
  253. GET_STACK_TRACE_THREAD;
  254. asan_block_context_t *context = (asan_block_context_t*)block;
  255. VReport(2,
  256. "asan_dispatch_call_block_and_release(): "
  257. "context: %p, pthread_self: %p\n",
  258. block, pthread_self());
  259. asan_register_worker_thread(context->parent_tid, &stack);
  260. // Call the original dispatcher for the block.
  261. context->func(context->block);
  262. asan_free(context, &stack, FROM_MALLOC);
  263. }
  264. } // namespace __asan
  265. using namespace __asan; // NOLINT
  266. // Wrap |ctxt| and |func| into an asan_block_context_t.
  267. // The caller retains control of the allocated context.
  268. extern "C"
  269. asan_block_context_t *alloc_asan_context(void *ctxt, dispatch_function_t func,
  270. BufferedStackTrace *stack) {
  271. asan_block_context_t *asan_ctxt =
  272. (asan_block_context_t*) asan_malloc(sizeof(asan_block_context_t), stack);
  273. asan_ctxt->block = ctxt;
  274. asan_ctxt->func = func;
  275. asan_ctxt->parent_tid = GetCurrentTidOrInvalid();
  276. return asan_ctxt;
  277. }
  278. // Define interceptor for dispatch_*_f function with the three most common
  279. // parameters: dispatch_queue_t, context, dispatch_function_t.
  280. #define INTERCEPT_DISPATCH_X_F_3(dispatch_x_f) \
  281. INTERCEPTOR(void, dispatch_x_f, dispatch_queue_t dq, void *ctxt, \
  282. dispatch_function_t func) { \
  283. GET_STACK_TRACE_THREAD; \
  284. asan_block_context_t *asan_ctxt = alloc_asan_context(ctxt, func, &stack); \
  285. if (common_flags()->verbosity >= 2) { \
  286. Report(#dispatch_x_f "(): context: %p, pthread_self: %p\n", \
  287. asan_ctxt, pthread_self()); \
  288. PRINT_CURRENT_STACK(); \
  289. } \
  290. return REAL(dispatch_x_f)(dq, (void*)asan_ctxt, \
  291. asan_dispatch_call_block_and_release); \
  292. }
  293. INTERCEPT_DISPATCH_X_F_3(dispatch_async_f)
  294. INTERCEPT_DISPATCH_X_F_3(dispatch_sync_f)
  295. INTERCEPT_DISPATCH_X_F_3(dispatch_barrier_async_f)
  296. INTERCEPTOR(void, dispatch_after_f, dispatch_time_t when,
  297. dispatch_queue_t dq, void *ctxt,
  298. dispatch_function_t func) {
  299. GET_STACK_TRACE_THREAD;
  300. asan_block_context_t *asan_ctxt = alloc_asan_context(ctxt, func, &stack);
  301. if (common_flags()->verbosity >= 2) {
  302. Report("dispatch_after_f: %p\n", asan_ctxt);
  303. PRINT_CURRENT_STACK();
  304. }
  305. return REAL(dispatch_after_f)(when, dq, (void*)asan_ctxt,
  306. asan_dispatch_call_block_and_release);
  307. }
  308. INTERCEPTOR(void, dispatch_group_async_f, dispatch_group_t group,
  309. dispatch_queue_t dq, void *ctxt,
  310. dispatch_function_t func) {
  311. GET_STACK_TRACE_THREAD;
  312. asan_block_context_t *asan_ctxt = alloc_asan_context(ctxt, func, &stack);
  313. if (common_flags()->verbosity >= 2) {
  314. Report("dispatch_group_async_f(): context: %p, pthread_self: %p\n",
  315. asan_ctxt, pthread_self());
  316. PRINT_CURRENT_STACK();
  317. }
  318. REAL(dispatch_group_async_f)(group, dq, (void*)asan_ctxt,
  319. asan_dispatch_call_block_and_release);
  320. }
  321. #if !defined(MISSING_BLOCKS_SUPPORT)
  322. extern "C" {
  323. void dispatch_async(dispatch_queue_t dq, void(^work)(void));
  324. void dispatch_group_async(dispatch_group_t dg, dispatch_queue_t dq,
  325. void(^work)(void));
  326. void dispatch_after(dispatch_time_t when, dispatch_queue_t queue,
  327. void(^work)(void));
  328. void dispatch_source_set_cancel_handler(dispatch_source_t ds,
  329. void(^work)(void));
  330. void dispatch_source_set_event_handler(dispatch_source_t ds, void(^work)(void));
  331. }
  332. #define GET_ASAN_BLOCK(work) \
  333. void (^asan_block)(void); \
  334. int parent_tid = GetCurrentTidOrInvalid(); \
  335. asan_block = ^(void) { \
  336. GET_STACK_TRACE_THREAD; \
  337. asan_register_worker_thread(parent_tid, &stack); \
  338. work(); \
  339. }
  340. // Forces the compiler to generate a frame pointer in the function.
  341. #define ENABLE_FRAME_POINTER \
  342. do { \
  343. volatile uptr enable_fp; \
  344. enable_fp = GET_CURRENT_FRAME(); \
  345. } while (0)
  346. INTERCEPTOR(void, dispatch_async,
  347. dispatch_queue_t dq, void(^work)(void)) {
  348. ENABLE_FRAME_POINTER;
  349. GET_ASAN_BLOCK(work);
  350. REAL(dispatch_async)(dq, asan_block);
  351. }
  352. INTERCEPTOR(void, dispatch_group_async,
  353. dispatch_group_t dg, dispatch_queue_t dq, void(^work)(void)) {
  354. ENABLE_FRAME_POINTER;
  355. GET_ASAN_BLOCK(work);
  356. REAL(dispatch_group_async)(dg, dq, asan_block);
  357. }
  358. INTERCEPTOR(void, dispatch_after,
  359. dispatch_time_t when, dispatch_queue_t queue, void(^work)(void)) {
  360. ENABLE_FRAME_POINTER;
  361. GET_ASAN_BLOCK(work);
  362. REAL(dispatch_after)(when, queue, asan_block);
  363. }
  364. INTERCEPTOR(void, dispatch_source_set_cancel_handler,
  365. dispatch_source_t ds, void(^work)(void)) {
  366. ENABLE_FRAME_POINTER;
  367. GET_ASAN_BLOCK(work);
  368. REAL(dispatch_source_set_cancel_handler)(ds, asan_block);
  369. }
  370. INTERCEPTOR(void, dispatch_source_set_event_handler,
  371. dispatch_source_t ds, void(^work)(void)) {
  372. ENABLE_FRAME_POINTER;
  373. GET_ASAN_BLOCK(work);
  374. REAL(dispatch_source_set_event_handler)(ds, asan_block);
  375. }
  376. #endif
  377. #endif // SANITIZER_MAC