diff options
author | Alexey Samsonov <samsonov@google.com> | 2014-04-01 13:16:30 +0000 |
---|---|---|
committer | Alexey Samsonov <samsonov@google.com> | 2014-04-01 13:16:30 +0000 |
commit | d6535ea4c4d49078a93735b315b8518fb692a592 (patch) | |
tree | e114342968d294d188587a94d6dea587a66e3f19 /lib/asan/asan_linux.cc | |
parent | f9470a30623dab95050c32e10576d706b13675dd (diff) |
[ASan] Optional support for dynamic ASan runtime on Linux.
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
Diffstat (limited to 'lib/asan/asan_linux.cc')
-rw-r--r-- | lib/asan/asan_linux.cc | 76 |
1 files changed, 75 insertions, 1 deletions
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; |