Skip to content
This repository has been archived by the owner on Apr 23, 2020. It is now read-only.

Commit

Permalink
[ASan] Optional support for dynamic ASan runtime on Linux.
Browse files Browse the repository at this point in the history
Based on http://llvm-reviews.chandlerc.com/D3042 by Yuri Gribov!


git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@205308 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
Alexey Samsonov committed Apr 1, 2014
1 parent f9470a3 commit d6535ea
Show file tree
Hide file tree
Showing 23 changed files with 345 additions and 24 deletions.
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,8 @@ option(COMPILER_RT_DEBUG "Build runtimes with full debug info" OFF)
# COMPILER_RT_DEBUG_PYBOOL is used by lit.common.configured.in.
pythonize_bool(COMPILER_RT_DEBUG)

option(COMPILER_RT_BUILD_SHARED_ASAN "Build shared version of AddressSanitizer runtime" OFF)

#================================
# Setup Compiler Flags
#================================
Expand Down
6 changes: 5 additions & 1 deletion cmake/Modules/AddCompilerRT.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ endmacro()
# DEFS <compile definitions>)
macro(add_compiler_rt_runtime name arch type)
if(CAN_TARGET_${arch})
parse_arguments(LIB "SOURCES;CFLAGS;DEFS" "" ${ARGN})
parse_arguments(LIB "SOURCES;CFLAGS;DEFS;OUTPUT_NAME" "" ${ARGN})
add_library(${name} ${type} ${LIB_SOURCES})
# Setup compile flags and definitions.
set_target_compile_flags(${name}
Expand All @@ -58,6 +58,10 @@ macro(add_compiler_rt_runtime name arch type)
set_target_properties(${name} PROPERTIES
ARCHIVE_OUTPUT_DIRECTORY ${COMPILER_RT_LIBRARY_OUTPUT_DIR}
LIBRARY_OUTPUT_DIRECTORY ${COMPILER_RT_LIBRARY_OUTPUT_DIR})
if (LIB_OUTPUT_NAME)
set_target_properties(${name} PROPERTIES
OUTPUT_NAME ${LIB_OUTPUT_NAME})
endif()
# Add installation command.
install(TARGETS ${name}
ARCHIVE DESTINATION ${COMPILER_RT_LIBRARY_INSTALL_DIR}
Expand Down
1 change: 1 addition & 0 deletions cmake/config-ix.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ check_cxx_compiler_flag(-fno-rtti COMPILER_RT_HAS_FNO_RTTI_FLAG)
check_cxx_compiler_flag(-ffreestanding COMPILER_RT_HAS_FFREESTANDING_FLAG)
check_cxx_compiler_flag("-Werror -fno-function-sections" COMPILER_RT_HAS_FNO_FUNCTION_SECTIONS_FLAG)
check_cxx_compiler_flag(-std=c++11 COMPILER_RT_HAS_STD_CXX11_FLAG)
check_cxx_compiler_flag(-ftls-model=initial-exec COMPILER_RT_HAS_FTLS_MODEL_INITIAL_EXEC)

check_cxx_compiler_flag(/GR COMPILER_RT_HAS_GR_FLAG)
check_cxx_compiler_flag(/GS COMPILER_RT_HAS_GS_FLAG)
Expand Down
51 changes: 46 additions & 5 deletions lib/asan/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,16 @@ 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
asan_stats.cc
asan_thread.cc
asan_win.cc)

set(ASAN_PREINIT_SOURCES
asan_preinit.cc)

include_directories(..)

if(ANDROID)
Expand All @@ -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)
Expand All @@ -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()

Expand Down Expand Up @@ -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)
Expand Down
6 changes: 6 additions & 0 deletions lib/asan/asan_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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);
Expand Down
76 changes: 75 additions & 1 deletion lib/asan/asan_linux.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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 {

Expand All @@ -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;
Expand Down
6 changes: 6 additions & 0 deletions lib/asan/asan_mac.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
18 changes: 18 additions & 0 deletions lib/asan/asan_rtl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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();
}
4 changes: 4 additions & 0 deletions lib/asan/asan_win.cc
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@ void *AsanDoesNotSupportStaticLinkage() {
return 0;
}

void AsanCheckDynamicRTPrereqs() { UNIMPLEMENTED(); }

void AsanCheckIncompatibleRT() {}

void AsanPlatformThreadInit() {
// Nothing here for now.
}
Expand Down
16 changes: 16 additions & 0 deletions lib/asan/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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})
Expand Down Expand Up @@ -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)
Expand Down
Loading

0 comments on commit d6535ea

Please sign in to comment.