summaryrefslogtreecommitdiff
path: root/lib/asan
diff options
context:
space:
mode:
Diffstat (limited to 'lib/asan')
-rw-r--r--lib/asan/CMakeLists.txt51
-rw-r--r--lib/asan/asan_internal.h6
-rw-r--r--lib/asan/asan_linux.cc76
-rw-r--r--lib/asan/asan_mac.cc6
-rw-r--r--lib/asan/asan_rtl.cc18
-rw-r--r--lib/asan/asan_win.cc4
-rw-r--r--lib/asan/tests/CMakeLists.txt16
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)