diff options
Diffstat (limited to 'lib/asan')
-rw-r--r-- | lib/asan/CMakeLists.txt | 51 | ||||
-rw-r--r-- | lib/asan/asan_internal.h | 6 | ||||
-rw-r--r-- | lib/asan/asan_linux.cc | 76 | ||||
-rw-r--r-- | lib/asan/asan_mac.cc | 6 | ||||
-rw-r--r-- | lib/asan/asan_rtl.cc | 18 | ||||
-rw-r--r-- | lib/asan/asan_win.cc | 4 | ||||
-rw-r--r-- | lib/asan/tests/CMakeLists.txt | 16 |
7 files changed, 171 insertions, 6 deletions
diff --git a/lib/asan/CMakeLists.txt b/lib/asan/CMakeLists.txt index d1c0d801c..88647b841 100644 --- a/lib/asan/CMakeLists.txt +++ b/lib/asan/CMakeLists.txt @@ -21,7 +21,6 @@ set(ASAN_SOURCES asan_new_delete.cc asan_poisoning.cc asan_posix.cc - asan_preinit.cc asan_report.cc asan_rtl.cc asan_stack.cc @@ -29,6 +28,9 @@ set(ASAN_SOURCES asan_thread.cc asan_win.cc) +set(ASAN_PREINIT_SOURCES + asan_preinit.cc) + include_directories(..) if(ANDROID) @@ -46,6 +48,17 @@ if(ANDROID) ASAN_LOW_MEMORY=1) endif() +set(ASAN_DYNAMIC_DEFINITIONS + ${ASAN_COMMON_DEFINITIONS} ASAN_DYNAMIC=1) + +set(ASAN_DYNAMIC_CFLAGS ${ASAN_CFLAGS}) +append_if(COMPILER_RT_HAS_FTLS_MODEL_INITIAL_EXEC + -ftls-model=initial-exec ASAN_DYNAMIC_CFLAGS) + +set(ASAN_DYNAMIC_LIBS stdc++ m c) +append_if(COMPILER_RT_HAS_LIBPTHREAD pthread ASAN_DYNAMIC_LIBS) +append_if(COMPILER_RT_HAS_LIBDL dl ASAN_DYNAMIC_LIBS) + if (NOT MSVC) set(ASAN_ASM_SOURCES asan_asm_instrumentation.S) set_source_files_properties(${ASAN_ASM_SOURCES} PROPERTIES LANGUAGE C) @@ -71,6 +84,14 @@ else() add_compiler_rt_object_library(RTAsan ${arch} SOURCES ${ASAN_SOURCES} CFLAGS ${ASAN_CFLAGS} DEFS ${ASAN_COMMON_DEFINITIONS}) + add_compiler_rt_object_library(RTAsan_preinit ${arch} + SOURCES ${ASAN_PREINIT_SOURCES} CFLAGS ${ASAN_CFLAGS} + DEFS ${ASAN_COMMON_DEFINITIONS}) + if (COMPILER_RT_BUILD_SHARED_ASAN) + add_compiler_rt_object_library(RTAsan_dynamic ${arch} + SOURCES ${ASAN_SOURCES} CFLAGS ${ASAN_DYNAMIC_CFLAGS} + DEFS ${ASAN_DYNAMIC_DEFINITIONS}) + endif() endforeach() endif() @@ -103,21 +124,41 @@ elseif(ANDROID) else() # Build separate libraries for each target. foreach(arch ${ASAN_SUPPORTED_ARCH}) - set(ASAN_RUNTIME_OBJECTS - $<TARGET_OBJECTS:RTAsan.${arch}> + set(ASAN_COMMON_RUNTIME_OBJECTS $<TARGET_OBJECTS:RTInterception.${arch}> $<TARGET_OBJECTS:RTSanitizerCommon.${arch}> $<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>) if (NOT WIN32) # We can't build Leak Sanitizer on Windows yet. - list(APPEND ASAN_RUNTIME_OBJECTS $<TARGET_OBJECTS:RTLSanCommon.${arch}>) + list(APPEND ASAN_COMMON_RUNTIME_OBJECTS + $<TARGET_OBJECTS:RTLSanCommon.${arch}>) endif() add_compiler_rt_runtime(clang_rt.asan-${arch} ${arch} STATIC - SOURCES ${ASAN_RUNTIME_OBJECTS} + SOURCES $<TARGET_OBJECTS:RTAsan_preinit.${arch}> + $<TARGET_OBJECTS:RTAsan.${arch}> + ${ASAN_COMMON_RUNTIME_OBJECTS} CFLAGS ${ASAN_CFLAGS} DEFS ${ASAN_COMMON_DEFINITIONS}) add_dependencies(asan clang_rt.asan-${arch}) + + if (COMPILER_RT_BUILD_SHARED_ASAN) + add_compiler_rt_runtime(clang_rt.asan-preinit-${arch} ${arch} STATIC + SOURCES $<TARGET_OBJECTS:RTAsan_preinit.${arch}> + CFLAGS ${ASAN_CFLAGS} + DEFS ${ASAN_COMMON_DEFINITIONS}) + add_dependencies(asan clang_rt.asan-preinit-${arch}) + + add_compiler_rt_runtime(clang_rt.asan-dynamic-${arch} ${arch} SHARED + OUTPUT_NAME clang_rt.asan-${arch} + SOURCES $<TARGET_OBJECTS:RTAsan_dynamic.${arch}> + ${ASAN_COMMON_RUNTIME_OBJECTS} + CFLAGS ${ASAN_DYNAMIC_CFLAGS} + DEFS ${ASAN_DYNAMIC_DEFINITIONS}) + target_link_libraries(clang_rt.asan-dynamic-${arch} ${ASAN_DYNAMIC_LIBS}) + add_dependencies(asan clang_rt.asan-dynamic-${arch}) + endif() + if (UNIX AND NOT ${arch} STREQUAL "i386") add_sanitizer_rt_symbols(clang_rt.asan-${arch} asan.syms.extra) add_dependencies(asan clang_rt.asan-${arch}-symbols) diff --git a/lib/asan/asan_internal.h b/lib/asan/asan_internal.h index 4dbcae193..4934d6cd7 100644 --- a/lib/asan/asan_internal.h +++ b/lib/asan/asan_internal.h @@ -49,6 +49,10 @@ # define ASAN_USE_PREINIT_ARRAY (SANITIZER_LINUX && !SANITIZER_ANDROID) #endif +#ifndef ASAN_DYNAMIC +# define ASAN_DYNAMIC 0 +#endif + // All internal functions in asan reside inside the __asan namespace // to avoid namespace collisions with the user programs. // Seperate namespace also makes it simpler to distinguish the asan run-time @@ -69,6 +73,8 @@ void ReplaceSystemMalloc(); // asan_linux.cc / asan_mac.cc / asan_win.cc void *AsanDoesNotSupportStaticLinkage(); +void AsanCheckDynamicRTPrereqs(); +void AsanCheckIncompatibleRT(); void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp); void AsanOnSIGSEGV(int, void *siginfo, void *context); diff --git a/lib/asan/asan_linux.cc b/lib/asan/asan_linux.cc index 5529f56bd..c6085aa7b 100644 --- a/lib/asan/asan_linux.cc +++ b/lib/asan/asan_linux.cc @@ -35,8 +35,11 @@ #if SANITIZER_ANDROID #include <ucontext.h> +extern "C" void* _DYNAMIC; #else #include <sys/ucontext.h> +#include <dlfcn.h> +#include <link.h> #endif // x86_64 FreeBSD 9.2 and older define 64-bit register names in both 64-bit @@ -50,7 +53,17 @@ # endif #endif -extern "C" void* _DYNAMIC; +typedef enum { + ASAN_RT_VERSION_UNDEFINED = 0, + ASAN_RT_VERSION_DYNAMIC, + ASAN_RT_VERSION_STATIC, +} asan_rt_version_t; + +// FIXME: perhaps also store abi version here? +extern "C" { +SANITIZER_INTERFACE_ATTRIBUTE +asan_rt_version_t __asan_rt_version; +} namespace __asan { @@ -63,6 +76,67 @@ void *AsanDoesNotSupportStaticLinkage() { return &_DYNAMIC; // defined in link.h } +static int FindFirstDSOCallback(struct dl_phdr_info *info, size_t size, + void *data) { + // Continue until the first dynamic library is found + if (!info->dlpi_name || info->dlpi_name[0] == 0) + return 0; + + *(const char **)data = info->dlpi_name; + return 1; +} + +static bool IsDynamicRTName(const char *libname) { + return internal_strstr(libname, "libclang_rt.asan") || + internal_strstr(libname, "libasan.so"); +} + +void AsanCheckDynamicRTPrereqs() { + // FIXME: can we do something like this for Android? +#if !SANITIZER_ANDROID + // Ensure that dynamic RT is the first DSO in the list + const char *first_dso_name = 0; + dl_iterate_phdr(FindFirstDSOCallback, &first_dso_name); + if (first_dso_name && !IsDynamicRTName(first_dso_name)) { + Report("ASan runtime does not come first in initial library list; " + "you should either link runtime to your application or " + "manually preload it with LD_PRELOAD.\n"); + Die(); + } +#endif +} + +void AsanCheckIncompatibleRT() { +#if !SANITIZER_ANDROID + if (ASAN_DYNAMIC) { + if (__asan_rt_version == ASAN_RT_VERSION_UNDEFINED) { + __asan_rt_version = ASAN_RT_VERSION_DYNAMIC; + } else if (__asan_rt_version != ASAN_RT_VERSION_DYNAMIC) { + Report("Your application is linked against " + "incompatible ASan runtimes.\n"); + Die(); + } + } else { + // Ensure that dynamic runtime is not present. We should detect it + // as early as possible, otherwise ASan interceptors could bind to + // the functions in dynamic ASan runtime instead of the functions in + // system libraries, causing crashes later in ASan initialization. + MemoryMappingLayout proc_maps(/*cache_enabled*/true); + char filename[128]; + while (proc_maps.Next(0, 0, 0, filename, sizeof(filename), 0)) { + if (IsDynamicRTName(filename)) { + Report("Your application is linked against " + "incompatible ASan runtimes.\n"); + Die(); + } + } + + CHECK_NE(__asan_rt_version, ASAN_RT_VERSION_DYNAMIC); + __asan_rt_version = ASAN_RT_VERSION_STATIC; + } +#endif +} + void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) { #if defined(__arm__) ucontext_t *ucontext = (ucontext_t*)context; diff --git a/lib/asan/asan_mac.cc b/lib/asan/asan_mac.cc index 0428a1845..9f2fabd69 100644 --- a/lib/asan/asan_mac.cc +++ b/lib/asan/asan_mac.cc @@ -199,6 +199,12 @@ void *AsanDoesNotSupportStaticLinkage() { return 0; } +// No-op. Mac does not support static linkage anyway. +void AsanCheckDynamicRTPrereqs() {} + +// No-op. Mac does not support static linkage anyway. +void AsanCheckIncompatibleRT() {} + bool AsanInterceptsSignal(int signum) { return (signum == SIGSEGV || signum == SIGBUS) && common_flags()->handle_segv; diff --git a/lib/asan/asan_rtl.cc b/lib/asan/asan_rtl.cc index 631b5c955..2d93a8897 100644 --- a/lib/asan/asan_rtl.cc +++ b/lib/asan/asan_rtl.cc @@ -637,6 +637,23 @@ void AsanInitFromRtl() { AsanInitInternal(); } +#if ASAN_DYNAMIC +// Initialize runtime in case it's LD_PRELOAD-ed into unsanitized executable +// (and thus normal initializer from .preinit_array haven't run). + +class AsanInitializer { +public: // NOLINT + AsanInitializer() { + AsanCheckIncompatibleRT(); + AsanCheckDynamicRTPrereqs(); + if (!asan_inited) + __asan_init(); + } +}; + +static AsanInitializer asan_initializer; +#endif // ASAN_DYNAMIC + } // namespace __asan // ---------------------- Interface ---------------- {{{1 @@ -688,6 +705,7 @@ void NOINLINE __asan_set_death_callback(void (*callback)(void)) { // Initialize as requested from instrumented application code. // We use this call as a trigger to wake up ASan from deactivated state. void __asan_init() { + AsanCheckIncompatibleRT(); AsanActivate(); AsanInitInternal(); } diff --git a/lib/asan/asan_win.cc b/lib/asan/asan_win.cc index 54fec2b14..da26e989a 100644 --- a/lib/asan/asan_win.cc +++ b/lib/asan/asan_win.cc @@ -70,6 +70,10 @@ void *AsanDoesNotSupportStaticLinkage() { return 0; } +void AsanCheckDynamicRTPrereqs() { UNIMPLEMENTED(); } + +void AsanCheckIncompatibleRT() {} + void AsanPlatformThreadInit() { // Nothing here for now. } diff --git a/lib/asan/tests/CMakeLists.txt b/lib/asan/tests/CMakeLists.txt index e01d6ea8a..e85cfaf88 100644 --- a/lib/asan/tests/CMakeLists.txt +++ b/lib/asan/tests/CMakeLists.txt @@ -66,10 +66,16 @@ if(NOT ANDROID) list(APPEND ASAN_UNITTEST_INSTRUMENTED_LINKFLAGS -fsanitize=address) endif() +set(ASAN_DYNAMIC_UNITTEST_INSTRUMENTED_LINKFLAGS + ${ASAN_UNITTEST_INSTRUMENTED_LINKFLAGS} + -shared-libasan) + set(ASAN_UNITTEST_NOINST_LINKFLAGS ${ASAN_UNITTEST_COMMON_LINKFLAGS} -lm) append_if(COMPILER_RT_HAS_LIBDL -ldl ASAN_UNITTEST_NOINST_LINKFLAGS) append_if(COMPILER_RT_HAS_LIBPTHREAD -lpthread ASAN_UNITTEST_NOINST_LINKFLAGS) +append_if(COMPILER_RT_HAS_LIBPTHREAD -lpthread + ASAN_DYNAMIC_UNITTEST_INSTRUMENTED_LINKFLAGS) # Compile source for the given architecture, using compiler # options in ${ARGN}, and add it to the object list. @@ -154,6 +160,11 @@ macro(add_asan_tests_for_arch arch) add_asan_test(AsanUnitTests "Asan-${arch}-Test" ${arch} OBJECTS ${ASAN_INST_TEST_OBJECTS} LINKFLAGS ${ASAN_UNITTEST_INSTRUMENTED_LINKFLAGS}) + if(COMPILER_RT_BUILD_SHARED_ASAN) + add_asan_test(AsanUnitTests "Asan-${arch}-Dynamic-Test" ${arch} + OBJECTS ${ASAN_INST_TEST_OBJECTS} + LINKFLAGS ${ASAN_DYNAMIC_UNITTEST_INSTRUMENTED_LINKFLAGS}) + endif() # Add static ASan runtime that will be linked with uninstrumented tests. set(ASAN_TEST_RUNTIME RTAsanTest.${arch}) @@ -194,6 +205,11 @@ macro(add_asan_tests_for_arch arch) add_asan_test(AsanBenchmarks "Asan-${arch}-Benchmark" ${arch} OBJECTS ${ASAN_BENCHMARKS_OBJECTS} LINKFLAGS ${ASAN_UNITTEST_INSTRUMENTED_LINKFLAGS}) + if(COMPILER_RT_BUILD_SHARED_ASAN) + add_asan_test(AsanBenchmarks "Asan-${arch}-Dynamic-Benchmark" ${arch} + OBJECTS ${ASAN_BENCHMARKS_OBJECTS} + LINKFLAGS ${ASAN_DYNAMIC_UNITTEST_INSTRUMENTED_LINKFLAGS}) + endif() endmacro() if(COMPILER_RT_CAN_EXECUTE_TESTS) |