summaryrefslogtreecommitdiff
path: root/lib/asan/asan_linux.cc
diff options
context:
space:
mode:
Diffstat (limited to 'lib/asan/asan_linux.cc')
-rw-r--r--lib/asan/asan_linux.cc76
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;