2019-08-01 21:43:28 +08:00
|
|
|
//===-- asan_mac.cpp ------------------------------------------------------===//
|
2011-11-30 09:07:02 +08:00
|
|
|
//
|
2019-01-19 16:50:56 +08:00
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
2011-11-30 09:07:02 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This file is a part of AddressSanitizer, an address sanity checker.
|
|
|
|
//
|
|
|
|
// Mac-specific details.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2013-03-19 22:33:38 +08:00
|
|
|
#include "sanitizer_common/sanitizer_platform.h"
|
2013-03-19 22:54:17 +08:00
|
|
|
#if SANITIZER_MAC
|
2011-11-30 09:07:02 +08:00
|
|
|
|
2012-03-21 20:03:44 +08:00
|
|
|
#include "asan_interceptors.h"
|
2011-11-30 09:07:02 +08:00
|
|
|
#include "asan_internal.h"
|
2012-02-14 01:14:31 +08:00
|
|
|
#include "asan_mapping.h"
|
2011-11-30 09:07:02 +08:00
|
|
|
#include "asan_stack.h"
|
|
|
|
#include "asan_thread.h"
|
2013-07-16 17:29:48 +08:00
|
|
|
#include "sanitizer_common/sanitizer_atomic.h"
|
2012-06-04 22:27:50 +08:00
|
|
|
#include "sanitizer_common/sanitizer_libc.h"
|
2014-02-03 23:32:19 +08:00
|
|
|
#include "sanitizer_common/sanitizer_mac.h"
|
2011-11-30 09:07:02 +08:00
|
|
|
|
2016-03-29 04:28:17 +08:00
|
|
|
#include <dlfcn.h>
|
2015-10-28 04:12:55 +08:00
|
|
|
#include <fcntl.h>
|
|
|
|
#include <libkern/OSAtomic.h>
|
2012-01-18 19:16:05 +08:00
|
|
|
#include <mach-o/dyld.h>
|
2016-03-29 04:28:17 +08:00
|
|
|
#include <mach-o/getsect.h>
|
2012-01-31 06:11:04 +08:00
|
|
|
#include <mach-o/loader.h>
|
2015-10-28 04:12:55 +08:00
|
|
|
#include <pthread.h>
|
|
|
|
#include <stdlib.h> // for free()
|
2011-11-30 09:07:02 +08:00
|
|
|
#include <sys/mman.h>
|
2012-01-06 10:12:25 +08:00
|
|
|
#include <sys/resource.h>
|
2012-01-31 21:19:18 +08:00
|
|
|
#include <sys/sysctl.h>
|
2012-01-07 03:11:09 +08:00
|
|
|
#include <sys/ucontext.h>
|
2011-11-30 09:07:02 +08:00
|
|
|
#include <unistd.h>
|
|
|
|
|
2016-02-02 10:01:17 +08:00
|
|
|
// from <crt_externs.h>, but we don't have that file on iOS
|
|
|
|
extern "C" {
|
|
|
|
extern char ***_NSGetArgv(void);
|
|
|
|
extern char ***_NSGetEnviron(void);
|
|
|
|
}
|
|
|
|
|
2011-11-30 09:07:02 +08:00
|
|
|
namespace __asan {
|
|
|
|
|
2015-03-16 22:22:53 +08:00
|
|
|
void InitializePlatformInterceptors() {}
|
2016-07-12 05:40:59 +08:00
|
|
|
void InitializePlatformExceptionHandlers() {}
|
2017-02-22 00:09:38 +08:00
|
|
|
bool IsSystemHeapAddress (uptr addr) { return false; }
|
2015-03-16 22:22:53 +08:00
|
|
|
|
2011-11-30 09:07:02 +08:00
|
|
|
// No-op. Mac does not support static linkage anyway.
|
|
|
|
void *AsanDoesNotSupportStaticLinkage() {
|
2012-05-31 22:35:53 +08:00
|
|
|
return 0;
|
2011-11-30 09:07:02 +08:00
|
|
|
}
|
|
|
|
|
2017-07-13 07:29:21 +08:00
|
|
|
uptr FindDynamicShadowStart() {
|
[compiler-rt][asan][hwasan] Refactor shadow setup into sanitizer_common (NFCI)
Summary:
This refactors some common support related to shadow memory setup from
asan and hwasan into sanitizer_common. This should not only reduce code
duplication but also make these facilities available for new compiler-rt
uses (e.g. heap profiling).
In most cases the separate copies of the code were either identical, or
at least functionally identical. A few notes:
In ProtectGap, the asan version checked the address against an upper
bound (kZeroBaseMaxShadowStart, which is (2^18). I have created a copy
of kZeroBaseMaxShadowStart in hwasan_mapping.h, with the same value, as
it isn't clear why that code should not do the same check. If it
shouldn't, I can remove this and guard this check so that it only
happens for asan.
In asan's InitializeShadowMemory, in the dynamic shadow case it was
setting __asan_shadow_memory_dynamic_address to 0 (which then sets both
macro SHADOW_OFFSET as well as macro kLowShadowBeg to 0) before calling
FindDynamicShadowStart(). AFAICT this is only needed because
FindDynamicShadowStart utilizes kHighShadowEnd to
get the shadow size, and kHighShadowEnd is a macro invoking
MEM_TO_SHADOW(kHighMemEnd) which in turn invokes:
(((kHighMemEnd) >> SHADOW_SCALE) + (SHADOW_OFFSET))
I.e. it computes the shadow space needed by kHighMemEnd (the shift), and
adds the offset. Since we only want the shadow space here, the earlier
setting of SHADOW_OFFSET to 0 via __asan_shadow_memory_dynamic_address
accomplishes this. In the hwasan version, it simply gets the shadow
space via "MemToShadowSize(kHighMemEnd)", where MemToShadowSize just
does the shift. I've simplified the asan handling to do the same
thing, and therefore was able to remove the setting of the SHADOW_OFFSET
via __asan_shadow_memory_dynamic_address to 0.
Reviewers: vitalybuka, kcc, eugenis
Subscribers: dberris, #sanitizers, llvm-commits, davidxl
Tags: #sanitizers
Differential Revision: https://reviews.llvm.org/D83247
2020-07-07 02:05:12 +08:00
|
|
|
return MapDynamicShadow(MemToShadowSize(kHighMemEnd), SHADOW_SCALE,
|
|
|
|
/*min_shadow_base_alignment*/ 0, kHighMemEnd);
|
2017-07-13 07:29:21 +08:00
|
|
|
}
|
|
|
|
|
2014-04-01 21:16:30 +08:00
|
|
|
// No-op. Mac does not support static linkage anyway.
|
|
|
|
void AsanCheckDynamicRTPrereqs() {}
|
|
|
|
|
|
|
|
// No-op. Mac does not support static linkage anyway.
|
|
|
|
void AsanCheckIncompatibleRT() {}
|
|
|
|
|
2016-03-29 04:28:17 +08:00
|
|
|
void AsanApplyToGlobals(globals_op_fptr op, const void *needle) {
|
|
|
|
// Find the Mach-O header for the image containing the needle
|
|
|
|
Dl_info info;
|
|
|
|
int err = dladdr(needle, &info);
|
|
|
|
if (err == 0) return;
|
|
|
|
|
|
|
|
#if __LP64__
|
|
|
|
const struct mach_header_64 *mh = (struct mach_header_64 *)info.dli_fbase;
|
|
|
|
#else
|
|
|
|
const struct mach_header *mh = (struct mach_header *)info.dli_fbase;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// Look up the __asan_globals section in that image and register its globals
|
|
|
|
unsigned long size = 0;
|
|
|
|
__asan_global *globals = (__asan_global *)getsectiondata(
|
|
|
|
mh,
|
|
|
|
"__DATA", "__asan_globals",
|
|
|
|
&size);
|
|
|
|
|
|
|
|
if (!globals) return;
|
|
|
|
if (size % sizeof(__asan_global) != 0) return;
|
|
|
|
op(globals, size / sizeof(__asan_global));
|
|
|
|
}
|
|
|
|
|
2020-07-22 02:06:15 +08:00
|
|
|
void FlushUnneededASanShadowMemory(uptr p, uptr size) {
|
|
|
|
// Since asan's mapping is compacting, the shadow chunk may be
|
|
|
|
// not page-aligned, so we only flush the page-aligned portion.
|
|
|
|
ReleaseMemoryPagesToOS(MemToShadow(p), MemToShadow(p + size));
|
|
|
|
}
|
|
|
|
|
2013-01-17 23:45:28 +08:00
|
|
|
void ReadContextStack(void *context, uptr *stack, uptr *ssize) {
|
2012-11-23 18:14:44 +08:00
|
|
|
UNIMPLEMENTED();
|
|
|
|
}
|
|
|
|
|
2011-11-30 09:07:02 +08:00
|
|
|
// Support for the following functions from libdispatch on Mac OS:
|
|
|
|
// dispatch_async_f()
|
|
|
|
// dispatch_async()
|
|
|
|
// dispatch_sync_f()
|
|
|
|
// dispatch_sync()
|
|
|
|
// dispatch_after_f()
|
|
|
|
// dispatch_after()
|
|
|
|
// dispatch_group_async_f()
|
|
|
|
// dispatch_group_async()
|
|
|
|
// TODO(glider): libdispatch API contains other functions that we don't support
|
|
|
|
// yet.
|
|
|
|
//
|
|
|
|
// dispatch_sync() and dispatch_sync_f() are synchronous, although chances are
|
|
|
|
// they can cause jobs to run on a thread different from the current one.
|
|
|
|
// TODO(glider): if so, we need a test for this (otherwise we should remove
|
|
|
|
// them).
|
|
|
|
//
|
|
|
|
// The following functions use dispatch_barrier_async_f() (which isn't a library
|
|
|
|
// function but is exported) and are thus supported:
|
|
|
|
// dispatch_source_set_cancel_handler_f()
|
|
|
|
// dispatch_source_set_cancel_handler()
|
|
|
|
// dispatch_source_set_event_handler_f()
|
|
|
|
// dispatch_source_set_event_handler()
|
|
|
|
//
|
|
|
|
// The reference manual for Grand Central Dispatch is available at
|
|
|
|
// http://developer.apple.com/library/mac/#documentation/Performance/Reference/GCD_libdispatch_Ref/Reference/reference.html
|
|
|
|
// The implementation details are at
|
|
|
|
// http://libdispatch.macosforge.org/trac/browser/trunk/src/queue.c
|
|
|
|
|
2015-09-07 20:25:51 +08:00
|
|
|
typedef void* dispatch_group_t;
|
|
|
|
typedef void* dispatch_queue_t;
|
|
|
|
typedef void* dispatch_source_t;
|
|
|
|
typedef u64 dispatch_time_t;
|
|
|
|
typedef void (*dispatch_function_t)(void *block);
|
2012-03-21 20:29:54 +08:00
|
|
|
typedef void* (*worker_t)(void *block);
|
|
|
|
|
|
|
|
// A wrapper for the ObjC blocks used to support libdispatch.
|
|
|
|
typedef struct {
|
|
|
|
void *block;
|
|
|
|
dispatch_function_t func;
|
2012-06-06 23:06:58 +08:00
|
|
|
u32 parent_tid;
|
2012-03-21 20:29:54 +08:00
|
|
|
} asan_block_context_t;
|
|
|
|
|
2013-03-29 05:16:09 +08:00
|
|
|
ALWAYS_INLINE
|
2012-08-28 19:54:30 +08:00
|
|
|
void asan_register_worker_thread(int parent_tid, StackTrace *stack) {
|
2013-03-20 18:11:24 +08:00
|
|
|
AsanThread *t = GetCurrentThread();
|
2012-08-23 17:34:40 +08:00
|
|
|
if (!t) {
|
2014-12-06 01:31:13 +08:00
|
|
|
t = AsanThread::Create(/* start_routine */ nullptr, /* arg */ nullptr,
|
|
|
|
parent_tid, stack, /* detached */ true);
|
2012-08-23 17:34:40 +08:00
|
|
|
t->Init();
|
2019-02-07 19:01:22 +08:00
|
|
|
asanThreadRegistry().StartThread(t->tid(), GetTid(), ThreadType::Worker,
|
|
|
|
nullptr);
|
2013-03-20 18:11:24 +08:00
|
|
|
SetCurrentThread(t);
|
2012-08-23 17:34:40 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-20 19:59:26 +08:00
|
|
|
// For use by only those functions that allocated the context via
|
|
|
|
// alloc_asan_context().
|
2011-11-30 09:07:02 +08:00
|
|
|
extern "C"
|
|
|
|
void asan_dispatch_call_block_and_release(void *block) {
|
2012-12-13 17:34:23 +08:00
|
|
|
GET_STACK_TRACE_THREAD;
|
2011-11-30 09:07:02 +08:00
|
|
|
asan_block_context_t *context = (asan_block_context_t*)block;
|
2013-12-05 20:04:51 +08:00
|
|
|
VReport(2,
|
|
|
|
"asan_dispatch_call_block_and_release(): "
|
|
|
|
"context: %p, pthread_self: %p\n",
|
|
|
|
block, pthread_self());
|
2012-08-23 17:34:40 +08:00
|
|
|
asan_register_worker_thread(context->parent_tid, &stack);
|
2011-11-30 09:07:02 +08:00
|
|
|
// Call the original dispatcher for the block.
|
|
|
|
context->func(context->block);
|
2012-12-21 16:53:59 +08:00
|
|
|
asan_free(context, &stack, FROM_MALLOC);
|
2011-11-30 09:07:02 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace __asan
|
|
|
|
|
2019-09-12 07:19:48 +08:00
|
|
|
using namespace __asan;
|
2011-11-30 09:07:02 +08:00
|
|
|
|
|
|
|
// Wrap |ctxt| and |func| into an asan_block_context_t.
|
|
|
|
// The caller retains control of the allocated context.
|
|
|
|
extern "C"
|
|
|
|
asan_block_context_t *alloc_asan_context(void *ctxt, dispatch_function_t func,
|
2014-10-28 00:20:59 +08:00
|
|
|
BufferedStackTrace *stack) {
|
2011-11-30 09:07:02 +08:00
|
|
|
asan_block_context_t *asan_ctxt =
|
|
|
|
(asan_block_context_t*) asan_malloc(sizeof(asan_block_context_t), stack);
|
|
|
|
asan_ctxt->block = ctxt;
|
|
|
|
asan_ctxt->func = func;
|
2013-03-20 18:11:24 +08:00
|
|
|
asan_ctxt->parent_tid = GetCurrentTidOrInvalid();
|
2011-11-30 09:07:02 +08:00
|
|
|
return asan_ctxt;
|
|
|
|
}
|
|
|
|
|
2012-08-20 17:25:10 +08:00
|
|
|
// Define interceptor for dispatch_*_f function with the three most common
|
|
|
|
// parameters: dispatch_queue_t, context, dispatch_function_t.
|
|
|
|
#define INTERCEPT_DISPATCH_X_F_3(dispatch_x_f) \
|
|
|
|
INTERCEPTOR(void, dispatch_x_f, dispatch_queue_t dq, void *ctxt, \
|
|
|
|
dispatch_function_t func) { \
|
2012-12-13 17:34:23 +08:00
|
|
|
GET_STACK_TRACE_THREAD; \
|
2012-08-20 17:25:10 +08:00
|
|
|
asan_block_context_t *asan_ctxt = alloc_asan_context(ctxt, func, &stack); \
|
2015-01-20 21:21:20 +08:00
|
|
|
if (Verbosity() >= 2) { \
|
2012-08-20 17:25:10 +08:00
|
|
|
Report(#dispatch_x_f "(): context: %p, pthread_self: %p\n", \
|
|
|
|
asan_ctxt, pthread_self()); \
|
2013-12-05 20:04:51 +08:00
|
|
|
PRINT_CURRENT_STACK(); \
|
|
|
|
} \
|
|
|
|
return REAL(dispatch_x_f)(dq, (void*)asan_ctxt, \
|
|
|
|
asan_dispatch_call_block_and_release); \
|
2012-08-21 14:43:44 +08:00
|
|
|
}
|
2012-08-20 17:25:10 +08:00
|
|
|
|
|
|
|
INTERCEPT_DISPATCH_X_F_3(dispatch_async_f)
|
|
|
|
INTERCEPT_DISPATCH_X_F_3(dispatch_sync_f)
|
|
|
|
INTERCEPT_DISPATCH_X_F_3(dispatch_barrier_async_f)
|
2011-11-30 09:07:02 +08:00
|
|
|
|
2012-02-02 18:39:40 +08:00
|
|
|
INTERCEPTOR(void, dispatch_after_f, dispatch_time_t when,
|
|
|
|
dispatch_queue_t dq, void *ctxt,
|
|
|
|
dispatch_function_t func) {
|
2012-12-13 17:34:23 +08:00
|
|
|
GET_STACK_TRACE_THREAD;
|
2011-11-30 09:07:02 +08:00
|
|
|
asan_block_context_t *asan_ctxt = alloc_asan_context(ctxt, func, &stack);
|
2015-01-20 21:21:20 +08:00
|
|
|
if (Verbosity() >= 2) {
|
2011-11-30 09:07:02 +08:00
|
|
|
Report("dispatch_after_f: %p\n", asan_ctxt);
|
|
|
|
PRINT_CURRENT_STACK();
|
|
|
|
}
|
2012-02-08 21:45:31 +08:00
|
|
|
return REAL(dispatch_after_f)(when, dq, (void*)asan_ctxt,
|
|
|
|
asan_dispatch_call_block_and_release);
|
2011-11-30 09:07:02 +08:00
|
|
|
}
|
|
|
|
|
2012-08-23 17:34:40 +08:00
|
|
|
INTERCEPTOR(void, dispatch_group_async_f, dispatch_group_t group,
|
|
|
|
dispatch_queue_t dq, void *ctxt,
|
|
|
|
dispatch_function_t func) {
|
2012-12-13 17:34:23 +08:00
|
|
|
GET_STACK_TRACE_THREAD;
|
2012-08-23 17:34:40 +08:00
|
|
|
asan_block_context_t *asan_ctxt = alloc_asan_context(ctxt, func, &stack);
|
2015-01-20 21:21:20 +08:00
|
|
|
if (Verbosity() >= 2) {
|
2012-08-23 17:34:40 +08:00
|
|
|
Report("dispatch_group_async_f(): context: %p, pthread_self: %p\n",
|
|
|
|
asan_ctxt, pthread_self());
|
|
|
|
PRINT_CURRENT_STACK();
|
|
|
|
}
|
|
|
|
REAL(dispatch_group_async_f)(group, dq, (void*)asan_ctxt,
|
|
|
|
asan_dispatch_call_block_and_release);
|
|
|
|
}
|
|
|
|
|
2013-02-05 23:57:12 +08:00
|
|
|
#if !defined(MISSING_BLOCKS_SUPPORT)
|
2012-08-23 17:34:40 +08:00
|
|
|
extern "C" {
|
|
|
|
void dispatch_async(dispatch_queue_t dq, void(^work)(void));
|
|
|
|
void dispatch_group_async(dispatch_group_t dg, dispatch_queue_t dq,
|
|
|
|
void(^work)(void));
|
|
|
|
void dispatch_after(dispatch_time_t when, dispatch_queue_t queue,
|
|
|
|
void(^work)(void));
|
|
|
|
void dispatch_source_set_cancel_handler(dispatch_source_t ds,
|
|
|
|
void(^work)(void));
|
|
|
|
void dispatch_source_set_event_handler(dispatch_source_t ds, void(^work)(void));
|
2012-08-20 19:59:26 +08:00
|
|
|
}
|
|
|
|
|
2012-08-23 17:34:40 +08:00
|
|
|
#define GET_ASAN_BLOCK(work) \
|
|
|
|
void (^asan_block)(void); \
|
2013-03-20 18:11:24 +08:00
|
|
|
int parent_tid = GetCurrentTidOrInvalid(); \
|
2012-08-23 17:34:40 +08:00
|
|
|
asan_block = ^(void) { \
|
2012-12-13 17:34:23 +08:00
|
|
|
GET_STACK_TRACE_THREAD; \
|
2012-08-23 17:34:40 +08:00
|
|
|
asan_register_worker_thread(parent_tid, &stack); \
|
|
|
|
work(); \
|
2012-08-20 19:59:26 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
INTERCEPTOR(void, dispatch_async,
|
2012-08-23 17:34:40 +08:00
|
|
|
dispatch_queue_t dq, void(^work)(void)) {
|
2014-07-10 08:06:53 +08:00
|
|
|
ENABLE_FRAME_POINTER;
|
2012-08-23 17:34:40 +08:00
|
|
|
GET_ASAN_BLOCK(work);
|
|
|
|
REAL(dispatch_async)(dq, asan_block);
|
|
|
|
}
|
|
|
|
|
|
|
|
INTERCEPTOR(void, dispatch_group_async,
|
|
|
|
dispatch_group_t dg, dispatch_queue_t dq, void(^work)(void)) {
|
2014-07-10 08:06:53 +08:00
|
|
|
ENABLE_FRAME_POINTER;
|
2012-08-23 17:34:40 +08:00
|
|
|
GET_ASAN_BLOCK(work);
|
|
|
|
REAL(dispatch_group_async)(dg, dq, asan_block);
|
2012-08-20 19:59:26 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
INTERCEPTOR(void, dispatch_after,
|
2012-08-23 17:34:40 +08:00
|
|
|
dispatch_time_t when, dispatch_queue_t queue, void(^work)(void)) {
|
2014-07-10 08:06:53 +08:00
|
|
|
ENABLE_FRAME_POINTER;
|
2012-08-23 17:34:40 +08:00
|
|
|
GET_ASAN_BLOCK(work);
|
|
|
|
REAL(dispatch_after)(when, queue, asan_block);
|
2012-08-20 19:59:26 +08:00
|
|
|
}
|
|
|
|
|
2012-08-23 17:34:40 +08:00
|
|
|
INTERCEPTOR(void, dispatch_source_set_cancel_handler,
|
|
|
|
dispatch_source_t ds, void(^work)(void)) {
|
2014-12-23 01:30:04 +08:00
|
|
|
if (!work) {
|
|
|
|
REAL(dispatch_source_set_cancel_handler)(ds, work);
|
|
|
|
return;
|
|
|
|
}
|
2014-07-10 08:06:53 +08:00
|
|
|
ENABLE_FRAME_POINTER;
|
2012-08-23 17:34:40 +08:00
|
|
|
GET_ASAN_BLOCK(work);
|
|
|
|
REAL(dispatch_source_set_cancel_handler)(ds, asan_block);
|
2011-11-30 09:07:02 +08:00
|
|
|
}
|
|
|
|
|
2012-08-23 17:34:40 +08:00
|
|
|
INTERCEPTOR(void, dispatch_source_set_event_handler,
|
|
|
|
dispatch_source_t ds, void(^work)(void)) {
|
2014-07-10 08:06:53 +08:00
|
|
|
ENABLE_FRAME_POINTER;
|
2012-08-23 17:34:40 +08:00
|
|
|
GET_ASAN_BLOCK(work);
|
|
|
|
REAL(dispatch_source_set_event_handler)(ds, asan_block);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2013-04-03 15:29:53 +08:00
|
|
|
#endif // SANITIZER_MAC
|