diff options
-rw-r--r-- | lib/asan/Makefile.mk | 4 | ||||
-rw-r--r-- | lib/asan/Makefile.old | 13 | ||||
-rw-r--r-- | lib/asan/asan_interceptors.cc | 128 | ||||
-rw-r--r-- | lib/asan/asan_interceptors.h | 61 | ||||
-rw-r--r-- | lib/asan/asan_mac.cc | 23 | ||||
-rw-r--r-- | lib/asan/asan_mac.h | 10 | ||||
-rw-r--r-- | lib/asan/asan_malloc_mac.cc | 4 | ||||
-rw-r--r-- | lib/asan/interception/Makefile.mk | 22 | ||||
-rw-r--r-- | lib/asan/interception/interception.h | 136 | ||||
-rw-r--r-- | lib/asan/interception/interception_linux.cc | 27 | ||||
-rw-r--r-- | lib/asan/interception/interception_linux.h | 33 | ||||
-rw-r--r-- | lib/asan/interception/interception_mac.cc | 34 | ||||
-rw-r--r-- | lib/asan/interception/interception_mac.h | 47 |
13 files changed, 364 insertions, 178 deletions
diff --git a/lib/asan/Makefile.mk b/lib/asan/Makefile.mk index bc8c1c6e0..358e0d1e8 100644 --- a/lib/asan/Makefile.mk +++ b/lib/asan/Makefile.mk @@ -8,7 +8,7 @@ #===------------------------------------------------------------------------===# ModuleName := asan -SubDirs := mach_override +SubDirs := interception mach_override Sources := $(foreach file,$(wildcard $(Dir)/*.cc),$(notdir $(file))) ObjNames := $(Sources:%.cc=%.o) @@ -17,6 +17,8 @@ Implementation := Generic # FIXME: use automatic dependencies? Dependencies := $(wildcard $(Dir)/*.h) +Dependencies += $(wildcard $(Dir)/interception/*.h) +Dependencies += $(wildcard $(Dir)/mach_override/*.h) # Define a convenience variable for all the asan functions. AsanFunctions := $(Sources:%.cc=%) diff --git a/lib/asan/Makefile.old b/lib/asan/Makefile.old index 18d2b1b15..744475ab7 100644 --- a/lib/asan/Makefile.old +++ b/lib/asan/Makefile.old @@ -178,6 +178,9 @@ RTL_HDR=asan_allocator.h \ asan_stats.h \ asan_thread.h \ asan_thread_registry.h \ + interception/interception.h \ + interception/interception_linux.h \ + interception/interception_mac.h \ mach_override/mach_override.h LIBASAN_OBJ=$(BIN)/asan_rtl$(SUFF).o \ @@ -195,6 +198,8 @@ LIBASAN_OBJ=$(BIN)/asan_rtl$(SUFF).o \ $(BIN)/asan_stats$(SUFF).o \ $(BIN)/asan_thread$(SUFF).o \ $(BIN)/asan_thread_registry$(SUFF).o \ + $(BIN)/interception/interception_linux$(SUFF).o \ + $(BIN)/interception/interception_mac$(SUFF).o \ $(BIN)/mach_override/mach_override$(SUFF).o GTEST_ROOT=third_party/googletest @@ -215,9 +220,9 @@ t64: b64 t32: b32 $(BIN)/asan_test32 -b64: | $(BIN) +b64: | mk_bin_dir $(MAKE) -f $(MAKEFILE) ARCH=x86_64 asan_test asan_benchmarks -b32: | $(BIN) +b32: | mk_bin_dir $(MAKE) -f $(MAKEFILE) ARCH=i386 asan_test asan_benchmarks lib64: @@ -225,8 +230,9 @@ lib64: lib32: $(MAKE) $(MAKEFILE) ARCH=i386 lib -$(BIN): +mk_bin_dir: mkdir -p $(BIN) + mkdir -p $(BIN)/interception mkdir -p $(BIN)/mach_override clang: @@ -330,6 +336,7 @@ ADDRESS_SANITIZER_CPP=../../../../lib/Transforms/Instrumentation/AddressSanitize lint: third_party/cpplint/cpplint.py --filter=$(LLVM_LINT_FILTER) $(ADDRESS_SANITIZER_CPP) third_party/cpplint/cpplint.py --filter=$(RTL_LINT_FITLER) asan_*.cc asan_*.h + third_party/cpplint/cpplint.py --filter=$(RTL_LINT_FITLER) interception/interception*.h interception/interception*.cc third_party/cpplint/cpplint.py --filter=$(TEST_LINT_FITLER) tests/*.cc get_third_party: diff --git a/lib/asan/asan_interceptors.cc b/lib/asan/asan_interceptors.cc index 075bb6870..1be867d51 100644 --- a/lib/asan/asan_interceptors.cc +++ b/lib/asan/asan_interceptors.cc @@ -21,74 +21,22 @@ #include "asan_stack.h" #include "asan_stats.h" #include "asan_thread_registry.h" +#include "interception/interception.h" #include <new> #include <ctype.h> #ifndef _WIN32 -#include <dlfcn.h> #include <pthread.h> -#endif +#endif // _WIN32 -// To replace weak system functions on Linux we just need to declare functions -// with same names in our library and then obtain the real function pointers -// using dlsym(). This is not so on Mac OS, where the two-level namespace makes -// our replacement functions invisible to other libraries. This may be overcomed -// using the DYLD_FORCE_FLAT_NAMESPACE, but some errors loading the shared -// libraries in Chromium were noticed when doing so. -// Instead we use mach_override, a handy framework for patching functions at -// runtime. To avoid possible name clashes, our replacement functions have -// the "wrap_" prefix on Mac. -// -// After interception, the calls to system functions will be substituted by -// calls to our interceptors. We store pointers to system function f() -// in __asan::real_f(). #if defined(__APPLE__) -// Include the declarations of the original functions. +// FIXME(samsonov): Gradually replace system headers with declarations of +// intercepted functions. #include <signal.h> #include <string.h> #include <strings.h> - -#include "mach_override/mach_override.h" - -#define OVERRIDE_FUNCTION(oldfunc, newfunc) \ - do {CHECK(0 == __asan_mach_override_ptr_custom((void*)(oldfunc), \ - (void*)(newfunc), \ - (void**)&real_##oldfunc, \ - __asan_allocate_island, \ - __asan_deallocate_island)); \ - CHECK(real_##oldfunc != NULL); } while (0) - -#define OVERRIDE_FUNCTION_IF_EXISTS(oldfunc, newfunc) \ - do { __asan_mach_override_ptr_custom((void*)(oldfunc), \ - (void*)(newfunc), \ - (void**)&real_##oldfunc, \ - __asan_allocate_island, \ - __asan_deallocate_island); \ - } while (0) - -#define INTERCEPT_FUNCTION(func) \ - OVERRIDE_FUNCTION(func, WRAP(func)) - -#define INTERCEPT_FUNCTION_IF_EXISTS(func) \ - OVERRIDE_FUNCTION_IF_EXISTS(func, WRAP(func)) - -#elif defined(_WIN32) -// TODO(timurrrr): change these macros once we decide how to intercept -// functions on Windows. -#define INTERCEPT_FUNCTION(func) \ - do { } while (0) - -#define INTERCEPT_FUNCTION_IF_EXISTS(func) \ - do { } while (0) - -#else // __linux__ -#define INTERCEPT_FUNCTION(func) \ - CHECK((real_##func = (func##_f)dlsym(RTLD_NEXT, #func))); - -#define INTERCEPT_FUNCTION_IF_EXISTS(func) \ - do { real_##func = (func##_f)dlsym(RTLD_NEXT, #func); } while (0) -#endif +#endif // __APPLE__ namespace __asan { @@ -581,12 +529,12 @@ INTERCEPTOR(size_t, strnlen, const char *s, size_t maxlen) { namespace __asan { void InitializeAsanInterceptors() { #ifndef __APPLE__ - INTERCEPT_FUNCTION(index); + CHECK(INTERCEPT_FUNCTION(index)); #else - OVERRIDE_FUNCTION(index, WRAP(strchr)); + CHECK(OVERRIDE_FUNCTION(index, WRAP(strchr))); #endif - INTERCEPT_FUNCTION(memcmp); - INTERCEPT_FUNCTION(memmove); + CHECK(INTERCEPT_FUNCTION(memcmp)); + CHECK(INTERCEPT_FUNCTION(memmove)); #ifdef __APPLE__ // Wrap memcpy() on OS X 10.6 only, because on 10.7 memcpy() and memmove() // are resolved into memmove$VARIANT$sse42. @@ -594,44 +542,44 @@ void InitializeAsanInterceptors() { // TODO(glider): need to check dynamically that memcpy() and memmove() are // actually the same function. if (GetMacosVersion() == MACOS_VERSION_SNOW_LEOPARD) { - INTERCEPT_FUNCTION(memcpy); + CHECK(INTERCEPT_FUNCTION(memcpy)); } else { REAL(memcpy) = REAL(memmove); } #else // Always wrap memcpy() on non-Darwin platforms. - INTERCEPT_FUNCTION(memcpy); + CHECK(INTERCEPT_FUNCTION(memcpy)); #endif - INTERCEPT_FUNCTION(memset); - INTERCEPT_FUNCTION(strcasecmp); - INTERCEPT_FUNCTION(strcat); // NOLINT - INTERCEPT_FUNCTION(strchr); - INTERCEPT_FUNCTION(strcmp); - INTERCEPT_FUNCTION(strcpy); // NOLINT - INTERCEPT_FUNCTION(strdup); - INTERCEPT_FUNCTION(strlen); - INTERCEPT_FUNCTION(strncasecmp); - INTERCEPT_FUNCTION(strncmp); - INTERCEPT_FUNCTION(strncpy); - - INTERCEPT_FUNCTION(sigaction); - INTERCEPT_FUNCTION(signal); - INTERCEPT_FUNCTION(longjmp); - INTERCEPT_FUNCTION(_longjmp); - INTERCEPT_FUNCTION_IF_EXISTS(__cxa_throw); - INTERCEPT_FUNCTION(pthread_create); + CHECK(INTERCEPT_FUNCTION(memset)); + CHECK(INTERCEPT_FUNCTION(strcasecmp)); + CHECK(INTERCEPT_FUNCTION(strcat)); // NOLINT + CHECK(INTERCEPT_FUNCTION(strchr)); + CHECK(INTERCEPT_FUNCTION(strcmp)); + CHECK(INTERCEPT_FUNCTION(strcpy)); // NOLINT + CHECK(INTERCEPT_FUNCTION(strdup)); + CHECK(INTERCEPT_FUNCTION(strlen)); + CHECK(INTERCEPT_FUNCTION(strncasecmp)); + CHECK(INTERCEPT_FUNCTION(strncmp)); + CHECK(INTERCEPT_FUNCTION(strncpy)); + + CHECK(INTERCEPT_FUNCTION(sigaction)); + CHECK(INTERCEPT_FUNCTION(signal)); + CHECK(INTERCEPT_FUNCTION(longjmp)); + CHECK(INTERCEPT_FUNCTION(_longjmp)); + INTERCEPT_FUNCTION(__cxa_throw); + CHECK(INTERCEPT_FUNCTION(pthread_create)); #ifdef __APPLE__ - INTERCEPT_FUNCTION(dispatch_async_f); - INTERCEPT_FUNCTION(dispatch_sync_f); - INTERCEPT_FUNCTION(dispatch_after_f); - INTERCEPT_FUNCTION(dispatch_barrier_async_f); - INTERCEPT_FUNCTION(dispatch_group_async_f); + CHECK(INTERCEPT_FUNCTION(dispatch_async_f)); + CHECK(INTERCEPT_FUNCTION(dispatch_sync_f)); + CHECK(INTERCEPT_FUNCTION(dispatch_after_f)); + CHECK(INTERCEPT_FUNCTION(dispatch_barrier_async_f)); + CHECK(INTERCEPT_FUNCTION(dispatch_group_async_f)); // We don't need to intercept pthread_workqueue_additem_np() to support the // libdispatch API, but it helps us to debug the unsupported functions. Let's // intercept it only during verbose runs. if (FLAG_v >= 2) { - INTERCEPT_FUNCTION(pthread_workqueue_additem_np); + CHECK(INTERCEPT_FUNCTION(pthread_workqueue_additem_np)); } // Normally CFStringCreateCopy should not copy constant CF strings. // Replacing the default CFAllocator causes constant strings to be copied @@ -640,15 +588,15 @@ void InitializeAsanInterceptors() { // http://code.google.com/p/address-sanitizer/issues/detail?id=10 // Until this problem is fixed we need to check that the string is // non-constant before calling CFStringCreateCopy. - INTERCEPT_FUNCTION(CFStringCreateCopy); + CHECK(INTERCEPT_FUNCTION(CFStringCreateCopy)); #else // On Darwin siglongjmp tailcalls longjmp, so we don't want to intercept it // there. - INTERCEPT_FUNCTION(siglongjmp); + CHECK(INTERCEPT_FUNCTION(siglongjmp)); #endif #ifndef __APPLE__ - INTERCEPT_FUNCTION(strnlen); + CHECK(INTERCEPT_FUNCTION(strnlen)); #endif if (FLAG_v > 0) { Printf("AddressSanitizer: libc interceptors initialized\n"); diff --git a/lib/asan/asan_interceptors.h b/lib/asan/asan_interceptors.h index 665339aba..93ec87b0b 100644 --- a/lib/asan/asan_interceptors.h +++ b/lib/asan/asan_interceptors.h @@ -15,66 +15,7 @@ #define ASAN_INTERCEPTORS_H #include "asan_internal.h" - -// Suppose you need to wrap/replace system function (generally, from libc): -// int foo(const char *bar, double baz); -// You'll need to: -// 1) define INTERCEPT(int, foo, const char *bar, double baz) { ... } -// 2) add a line "INTERCEPT_FUNCTION(foo)" to InitializeAsanInterceptors() -// You can access original function by calling __asan::real_foo(bar, baz). -// By defualt, real_foo will be visible only inside your interceptor, and if -// you want to use it in other parts of RTL, you'll need to: -// 3a) add DECLARE_REAL(int, foo, const char*, double); to a -// header file. -// However, if you want to implement your interceptor somewhere outside -// asan_interceptors.cc, you'll instead need to: -// 3b) add DECLARE_REAL_AND_INTERCEPTOR(int, foo, const char*, double); -// to a header. - -#if defined(__APPLE__) -# define WRAP(x) wrap_##x -# define WRAPPER_NAME(x) "wrap_"#x -# define INTERCEPTOR_ATTRIBUTE -#elif defined(_WIN32) -// TODO(timurrrr): we're likely to use something else later on Windows. -# define WRAP(x) wrap_##x -# define WRAPPER_NAME(x) #x -# define INTERCEPTOR_ATTRIBUTE -#else -# define WRAP(x) x -# define WRAPPER_NAME(x) #x -# define INTERCEPTOR_ATTRIBUTE __attribute__((visibility("default"))) -#endif - -#define REAL(x) real_##x -#define FUNC_TYPE(x) x##_f - -#define DECLARE_REAL(ret_type, func, ...); \ - typedef ret_type (*FUNC_TYPE(func))(__VA_ARGS__); \ - namespace __asan { \ - extern FUNC_TYPE(func) REAL(func); \ - } - -#define DECLARE_REAL_AND_INTERCEPTOR(ret_type, func, ...); \ - DECLARE_REAL(ret_type, func, ##__VA_ARGS__); \ - extern "C" \ - ret_type WRAP(func)(__VA_ARGS__); - -// Generally, you don't need to use DEFINE_REAL by itself, as INTERCEPTOR -// macros does its job. In exceptional cases you may need to call REAL(foo) -// without defining INTERCEPTOR(..., foo, ...). For example, if you override -// foo with interceptor for other function. -#define DEFINE_REAL(ret_type, func, ...); \ - typedef ret_type (*FUNC_TYPE(func))(__VA_ARGS__); \ - namespace __asan { \ - FUNC_TYPE(func) REAL(func); \ - } - -#define INTERCEPTOR(ret_type, func, ...); \ - DEFINE_REAL(ret_type, func, __VA_ARGS__); \ - extern "C" \ - INTERCEPTOR_ATTRIBUTE \ - ret_type WRAP(func)(__VA_ARGS__) +#include "interception/interception.h" DECLARE_REAL(int, memcmp, const void *a1, const void *a2, size_t size); DECLARE_REAL(void*, memcpy, void *to, const void *from, size_t size); diff --git a/lib/asan/asan_mac.cc b/lib/asan/asan_mac.cc index 90f96f346..8943a4ac2 100644 --- a/lib/asan/asan_mac.cc +++ b/lib/asan/asan_mac.cc @@ -36,8 +36,6 @@ namespace __asan { -void *island_allocator_pos = NULL; - void GetPcSpBp(void *context, uintptr_t *pc, uintptr_t *sp, uintptr_t *bp) { ucontext_t *ucontext = (ucontext_t*)context; # if __WORDSIZE == 64 @@ -314,25 +312,26 @@ void AsanStackTrace::GetStackTrace(size_t max_s, uintptr_t pc, uintptr_t bp) { } } -// The range of pages to be used by __asan_mach_override_ptr for escape -// islands. +// The range of pages to be used for escape islands. // TODO(glider): instead of mapping a fixed range we must find a range of // unmapped pages in vmmap and take them. // These constants were chosen empirically and may not work if the shadow // memory layout changes. Unfortunately they do necessarily depend on // kHighMemBeg or kHighMemEnd. +static void *island_allocator_pos = NULL; + #if __WORDSIZE == 32 -#define kIslandEnd (0xffdf0000 - kPageSize) -#define kIslandBeg (kIslandEnd - 256 * kPageSize) +# define kIslandEnd (0xffdf0000 - kPageSize) +# define kIslandBeg (kIslandEnd - 256 * kPageSize) #else -#define kIslandEnd (0x7fffffdf0000 - kPageSize) -#define kIslandBeg (kIslandEnd - 256 * kPageSize) +# define kIslandEnd (0x7fffffdf0000 - kPageSize) +# define kIslandBeg (kIslandEnd - 256 * kPageSize) #endif extern "C" -mach_error_t __asan_allocate_island(void **ptr, - size_t unused_size, - void *unused_hint) { +mach_error_t __interception_allocate_island(void **ptr, + size_t unused_size, + void *unused_hint) { if (!island_allocator_pos) { island_allocator_pos = asan_mmap((void*)kIslandBeg, kIslandEnd - kIslandBeg, @@ -349,7 +348,7 @@ mach_error_t __asan_allocate_island(void **ptr, } extern "C" -mach_error_t __asan_deallocate_island(void *ptr) { +mach_error_t __interception_deallocate_island(void *ptr) { // Do nothing. // TODO(glider): allow to free and reuse the island memory. return err_none; diff --git a/lib/asan/asan_mac.h b/lib/asan/asan_mac.h index 506cf87bd..59993ce07 100644 --- a/lib/asan/asan_mac.h +++ b/lib/asan/asan_mac.h @@ -20,7 +20,6 @@ // TODO(glider): need to check if the OS X version is 10.6 or greater. #include <dispatch/dispatch.h> -#include <mach/mach_error.h> #include <setjmp.h> #include <CoreFoundation/CFString.h> @@ -79,15 +78,6 @@ typedef struct { extern "C" { -// Allocate memory for the escape island. This cannot be moved to -// mach_override, because the allocator needs to know about the ASan shadow -// mappings. -// TODO(glider): in order to place a relative jump the allocated memory should -// be within 2 Gb from the hint address. -mach_error_t __asan_allocate_island(void **ptr, size_t unused_size, - void *unused_hint); -mach_error_t __asan_deallocate_island(void *ptr); - // dispatch_barrier_async_f() is not declared in <dispatch/dispatch.h>. void dispatch_barrier_async_f(dispatch_queue_t dq, void *ctxt, dispatch_function_t func); diff --git a/lib/asan/asan_malloc_mac.cc b/lib/asan/asan_malloc_mac.cc index d6ff2eab6..aeacc5f7d 100644 --- a/lib/asan/asan_malloc_mac.cc +++ b/lib/asan/asan_malloc_mac.cc @@ -310,7 +310,7 @@ extern bool kCFUseCollectableAllocator; // is GC on? namespace __asan { void ReplaceSystemMalloc() { static malloc_introspection_t asan_introspection; - __asan::REAL(memset)(&asan_introspection, 0, sizeof(asan_introspection)); + REAL(memset)(&asan_introspection, 0, sizeof(asan_introspection)); asan_introspection.enumerator = &mi_enumerator; asan_introspection.good_size = &mi_good_size; @@ -321,7 +321,7 @@ void ReplaceSystemMalloc() { asan_introspection.force_unlock = &mi_force_unlock; static malloc_zone_t asan_zone; - __asan::REAL(memset)(&asan_zone, 0, sizeof(malloc_zone_t)); + REAL(memset)(&asan_zone, 0, sizeof(malloc_zone_t)); // Start with a version 4 zone which is used for OS X 10.4 and 10.5. asan_zone.version = 4; diff --git a/lib/asan/interception/Makefile.mk b/lib/asan/interception/Makefile.mk new file mode 100644 index 000000000..f8071a8e6 --- /dev/null +++ b/lib/asan/interception/Makefile.mk @@ -0,0 +1,22 @@ +#===- lib/asan/interception/Makefile.mk --------------------*- Makefile -*--===# +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +#===------------------------------------------------------------------------===# + +ModuleName := asan +SubDirs := + +Sources := $(foreach file,$(wildcard $(Dir)/*.cc),$(notdir $(file))) +ObjNames := $(Sources:%.cc=%.o) + +Implementation := Generic + +# FIXME: use automatic dependencies? +Dependencies := $(wildcard $(Dir)/*.h) + +# Define a convenience variable for all the asan functions. +AsanFunctions += $(Sources:%.cc=%) diff --git a/lib/asan/interception/interception.h b/lib/asan/interception/interception.h new file mode 100644 index 000000000..14008852f --- /dev/null +++ b/lib/asan/interception/interception.h @@ -0,0 +1,136 @@ +//===-- interception.h ------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of AddressSanitizer, an address sanity checker. +// +// Machinery for providing replacements/wrappers for system functions. +//===----------------------------------------------------------------------===// + +#ifndef INTERCEPTION_H +#define INTERCEPTION_H + +#if !defined(__linux__) && !defined(__APPLE__) && !defined(_WIN32) +# error "Interception doesn't work on this operating system." +#endif + +// How to use this library: +// 1) Include this header to define your own interceptors +// (see details below). +// 2) Build all *.cc files and link against them. +// On Mac you will also need to: +// 3) Provide your own implementation for the following functions: +// mach_error_t __interception::allocate_island(void **ptr, +// size_t size, +// void *hint); +// mach_error_t __interception::deallocate_island(void *ptr); +// See "interception_mac.h" for more details. + +// How to add an interceptor: +// Suppose you need to wrap/replace system function (generally, from libc): +// int foo(const char *bar, double baz); +// You'll need to: +// 1) define INTERCEPTOR(int, foo, const char *bar, double baz) { ... } in +// your source file. +// 2) Call "INTERCEPT_FUNCTION(foo)" prior to the first call of "foo". +// INTERCEPT_FUNCTION(foo) evaluates to "true" iff the function was +// intercepted successfully. +// You can access original function by calling REAL(foo)(bar, baz). +// By default, REAL(foo) will be visible only inside your interceptor, and if +// you want to use it in other parts of RTL, you'll need to: +// 3a) add DECLARE_REAL(int, foo, const char*, double); to a +// header file. +// However, if the call "INTERCEPT_FUNCTION(foo)" and definition for +// INTERCEPTOR(..., foo, ...) are in different files, you'll instead need to: +// 3b) add DECLARE_REAL_AND_INTERCEPTOR(int, foo, const char*, double); +// to a header file. + +// Notes: 1. Things may not work properly if macro INTERCEPT(...) {...} or +// DECLARE_REAL(...); are located inside namespaces. +// 2. On Mac you can also use: "OVERRIDE_FUNCTION(foo, zoo);" to +// effectively redirect calls from "foo" to "zoo". In this case +// you aren't required to implement +// INTERCEPTOR(int, foo, const char *bar, double baz); +// but instead you'll have to add +// DEFINE_REAL(int, foo, const char *bar, double baz); in your +// source file (to define a pointer to overriden function). + +// How it works: +// To replace weak system functions on Linux we just need to declare functions +// with same names in our library and then obtain the real function pointers +// using dlsym(). This is not so on Mac OS, where the two-level namespace makes +// our replacement functions invisible to other libraries. This may be overcomed +// using the DYLD_FORCE_FLAT_NAMESPACE, but some errors loading the shared +// libraries in Chromium were noticed when doing so. +// Instead we use mach_override, a handy framework for patching functions at +// runtime. To avoid possible name clashes, our replacement functions have +// the "wrap_" prefix on Mac. + +#if defined(__APPLE__) +# define WRAP(x) wrap_##x +# define WRAPPER_NAME(x) "wrap_"#x +# define INTERCEPTOR_ATTRIBUTE +#elif defined(_WIN32) +// TODO(timurrrr): we're likely to use something else later on Windows. +# define WRAP(x) wrap_##x +# define WRAPPER_NAME(x) #x +# define INTERCEPTOR_ATTRIBUTE +#else +# define WRAP(x) x +# define WRAPPER_NAME(x) #x +# define INTERCEPTOR_ATTRIBUTE __attribute__((visibility("default"))) +#endif + +#define PTR_TO_REAL(x) real_##x +#define REAL(x) __interception::PTR_TO_REAL(x) +#define FUNC_TYPE(x) x##_f + +#define DECLARE_REAL(ret_type, func, ...); \ + typedef ret_type (*FUNC_TYPE(func))(__VA_ARGS__); \ + namespace __interception { \ + extern FUNC_TYPE(func) PTR_TO_REAL(func); \ + } + +#define DECLARE_REAL_AND_INTERCEPTOR(ret_type, func, ...); \ + DECLARE_REAL(ret_type, func, ##__VA_ARGS__); \ + extern "C" ret_type WRAP(func)(__VA_ARGS__); + +// Generally, you don't need to use DEFINE_REAL by itself, as INTERCEPTOR +// macros does its job. In exceptional cases you may need to call REAL(foo) +// without defining INTERCEPTOR(..., foo, ...). For example, if you override +// foo with an interceptor for other function. +#define DEFINE_REAL(ret_type, func, ...); \ + typedef ret_type (*FUNC_TYPE(func))(__VA_ARGS__); \ + namespace __interception { \ + FUNC_TYPE(func) PTR_TO_REAL(func); \ + } + +#define INTERCEPTOR(ret_type, func, ...) \ + DEFINE_REAL(ret_type, func, __VA_ARGS__); \ + extern "C" \ + INTERCEPTOR_ATTRIBUTE \ + ret_type WRAP(func)(__VA_ARGS__) + +#define INCLUDED_FROM_INTERCEPTION_LIB + +#if defined(__linux__) +# include "interception_linux.h" +# define INTERCEPT_FUNCTION(func) INTERCEPT_FUNCTION_LINUX(func) +#elif defined(__APPLE__) +# include "interception_mac.h" +# define OVERRIDE_FUNCTION(old_func, new_func) \ + OVERRIDE_FUNCTION_MAC(old_func, new_func) +# define INTERCEPT_FUNCTION(func) INTERCEPT_FUNCTION_MAC(func) +#else // defined(_WIN32) + // FIXME: deal with interception on Win. +# define INTERCEPT_FUNCTON(func) true +#endif + +#undef INCLUDED_FROM_INTERCEPTION_LIB + +#endif // INTERCEPTION_H diff --git a/lib/asan/interception/interception_linux.cc b/lib/asan/interception/interception_linux.cc new file mode 100644 index 000000000..db43e81e7 --- /dev/null +++ b/lib/asan/interception/interception_linux.cc @@ -0,0 +1,27 @@ +//===-- interception_linux.cc -----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of AddressSanitizer, an address sanity checker. +// +// Linux-specific interception methods. +//===----------------------------------------------------------------------===// + +#ifdef __linux__ + +#include <dlfcn.h> // for dlsym + +namespace __interception { +bool GetRealFunctionAddress(const char *func_name, void **func_addr) { + *func_addr = dlsym(RTLD_NEXT, func_name); + return (*func_addr != NULL); +} +} // namespace __interception + + +#endif // __linux__ diff --git a/lib/asan/interception/interception_linux.h b/lib/asan/interception/interception_linux.h new file mode 100644 index 000000000..214e68319 --- /dev/null +++ b/lib/asan/interception/interception_linux.h @@ -0,0 +1,33 @@ +//===-- interception_linux.h ------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of AddressSanitizer, an address sanity checker. +// +// Linux-specific interception methods. +//===----------------------------------------------------------------------===// + +#ifdef __linux__ + +#if !defined(INCLUDED_FROM_INTERCEPTION_LIB) +# error "interception_mac.h should be included from interception library only" +#endif + +#ifndef INTERCEPTION_LINUX_H +#define INTERCEPTION_LINUX_H + +namespace __interception { +// returns true if a function with the given name was found. +bool GetRealFunctionAddress(const char *func_name, void **func_addr); +} // namespace __interception + +#define INTERCEPT_FUNCTION_LINUX(func) \ + ::__interception::GetRealFunctionAddress(#func, (void**)&REAL(func)) + +#endif // INTERCEPTION_LINUX_H +#endif // __linux__ diff --git a/lib/asan/interception/interception_mac.cc b/lib/asan/interception/interception_mac.cc new file mode 100644 index 000000000..7c63dd3bd --- /dev/null +++ b/lib/asan/interception/interception_mac.cc @@ -0,0 +1,34 @@ +//===-- interception_mac.cc -------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of AddressSanitizer, an address sanity checker. +// +// Mac-specific interception methods. +//===----------------------------------------------------------------------===// + +#ifdef __APPLE__ + +#define INCLUDED_FROM_INTERCEPTION_LIB +#include "interception_mac.h" +#undef INCLUDED_FROM_INTERCEPTION_LIB +// FIXME(samsonov): Put mach_override/ under interception/ +#include "../mach_override/mach_override.h" + +namespace __interception { +bool OverrideFunction(void *old_func, void *new_func, void **orig_old_func) { + *orig_old_func = NULL; + int res = __asan_mach_override_ptr_custom(old_func, new_func, + orig_old_func, + __interception_allocate_island, + __interception_deallocate_island); + return (res == 0) && (*orig_old_func != NULL); +} +} // namespace __interception + +#endif // __APPLE__ diff --git a/lib/asan/interception/interception_mac.h b/lib/asan/interception/interception_mac.h new file mode 100644 index 000000000..224d961ee --- /dev/null +++ b/lib/asan/interception/interception_mac.h @@ -0,0 +1,47 @@ +//===-- interception_mac.h --------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of AddressSanitizer, an address sanity checker. +// +// Mac-specific interception methods. +//===----------------------------------------------------------------------===// + +#ifdef __APPLE__ + +#if !defined(INCLUDED_FROM_INTERCEPTION_LIB) +# error "interception_mac.h should be included from interception.h only" +#endif + +#ifndef INTERCEPTION_MAC_H +#define INTERCEPTION_MAC_H + +#include <mach/mach_error.h> +#include <stddef.h> + +// Allocate memory for the escape island. This cannot be moved to +// mach_override, because each user of interceptors may specify its +// own memory range for escape islands. +extern "C" { +mach_error_t __interception_allocate_island(void **ptr, size_t unused_size, + void *unused_hint); +mach_error_t __interception_deallocate_island(void *ptr); +} // extern "C" + +namespace __interception { +// returns true if the old function existed. +bool OverrideFunction(void *old_func, void *new_func, void **orig_old_func); +} // namespace __interception + +# define OVERRIDE_FUNCTION_MAC(old_func, new_func) \ + ::__interception::OverrideFunction((void*)old_func, (void*)new_func, \ + (void**)&REAL(old_func)) +# define INTERCEPT_FUNCTION_MAC(func) OVERRIDE_FUNCTION_MAC(func, WRAP(func)) + +#endif // INTERCEPTION_MAC_H +#endif // __APPLE__ |