[compiler-rt] r348078 - Introduce a way to allow the ASan dylib on Darwin platforms to be loaded via `dlopen()`.

Dan Liew via llvm-commits llvm-commits at lists.llvm.org
Sat Dec 1 07:45:42 PST 2018


Author: delcypher
Date: Sat Dec  1 07:45:42 2018
New Revision: 348078

URL: http://llvm.org/viewvc/llvm-project?rev=348078&view=rev
Log:
Introduce a way to allow the ASan dylib on Darwin platforms to be loaded via `dlopen()`.

Summary:

The purpose of this option is provide a way for the ASan dylib
to be loaded via `dlopen()` without triggering most initialization
steps (e.g. shadow memory set up) that normally occur when the
ASan dylib is loaded.

This new functionality is exposed by

- A `SANITIZER_SUPPORTS_INIT_FOR_DLOPEN` macro which indicates if the
  feature is supported. This only true for Darwin currently.
- A `HandleDlopenInit()` function which should return true if the library
  is being loaded via `dlopen()` and
  `SANITIZER_SUPPORTS_INIT_FOR_DLOPEN` is supported. Platforms that
  support this may perform any initialization they wish inside this
  function.

Although disabling initialization is something that could potentially
apply to other sanitizers it appears to be unnecessary for other
sanitizers so this patch only makes the change for ASan.

rdar://problem/45284065

Reviewers: kubamracek, george.karpenkov, kcc, eugenis, krytarowski

Subscribers: #sanitizers, llvm-commits

Differential Revision: https://reviews.llvm.org/D54469

Added:
    compiler-rt/trunk/test/asan/TestCases/Darwin/init_for_dlopen.cc
Modified:
    compiler-rt/trunk/lib/asan/asan_fuchsia.cc
    compiler-rt/trunk/lib/asan/asan_internal.h
    compiler-rt/trunk/lib/asan/asan_linux.cc
    compiler-rt/trunk/lib/asan/asan_malloc_mac.cc
    compiler-rt/trunk/lib/asan/asan_rtems.cc
    compiler-rt/trunk/lib/asan/asan_rtl.cc
    compiler-rt/trunk/lib/asan/asan_win.cc
    compiler-rt/trunk/lib/sanitizer_common/sanitizer_platform.h
    compiler-rt/trunk/test/sanitizer_common/ios_commands/iossim_run.py

Modified: compiler-rt/trunk/lib/asan/asan_fuchsia.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_fuchsia.cc?rev=348078&r1=348077&r2=348078&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_fuchsia.cc (original)
+++ compiler-rt/trunk/lib/asan/asan_fuchsia.cc Sat Dec  1 07:45:42 2018
@@ -190,6 +190,13 @@ static void ThreadExitHook(void *hook, u
   AsanThread::TSDDtor(per_thread);
 }
 
+bool HandleDlopenInit() {
+  // Not supported on this platform.
+  static_assert(!SANITIZER_SUPPORTS_INIT_FOR_DLOPEN,
+                "Expected SANITIZER_SUPPORTS_INIT_FOR_DLOPEN to be false");
+  return false;
+}
+
 }  // namespace __asan
 
 // These are declared (in extern "C") by <zircon/sanitizer.h>.

Modified: compiler-rt/trunk/lib/asan/asan_internal.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_internal.h?rev=348078&r1=348077&r2=348078&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_internal.h (original)
+++ compiler-rt/trunk/lib/asan/asan_internal.h Sat Dec  1 07:45:42 2018
@@ -111,6 +111,11 @@ void *AsanDlSymNext(const char *sym);
 
 void ReserveShadowMemoryRange(uptr beg, uptr end, const char *name);
 
+// Returns `true` iff most of ASan init process should be skipped due to the
+// ASan library being loaded via `dlopen()`. Platforms may perform any
+// `dlopen()` specific initialization inside this function.
+bool HandleDlopenInit();
+
 // Add convenient macro for interface functions that may be represented as
 // weak hooks.
 #define ASAN_MALLOC_HOOK(ptr, size)                                   \

Modified: compiler-rt/trunk/lib/asan/asan_linux.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_linux.cc?rev=348078&r1=348077&r2=348078&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_linux.cc (original)
+++ compiler-rt/trunk/lib/asan/asan_linux.cc Sat Dec  1 07:45:42 2018
@@ -248,6 +248,13 @@ void *AsanDlSymNext(const char *sym) {
   return dlsym(RTLD_NEXT, sym);
 }
 
+bool HandleDlopenInit() {
+  // Not supported on this platform.
+  static_assert(!SANITIZER_SUPPORTS_INIT_FOR_DLOPEN,
+                "Expected SANITIZER_SUPPORTS_INIT_FOR_DLOPEN to be false");
+  return false;
+}
+
 } // namespace __asan
 
 #endif  // SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD ||

Modified: compiler-rt/trunk/lib/asan/asan_malloc_mac.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_malloc_mac.cc?rev=348078&r1=348077&r2=348078&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_malloc_mac.cc (original)
+++ compiler-rt/trunk/lib/asan/asan_malloc_mac.cc Sat Dec  1 07:45:42 2018
@@ -61,4 +61,25 @@ using namespace __asan;
 
 #include "sanitizer_common/sanitizer_malloc_mac.inc"
 
+namespace COMMON_MALLOC_NAMESPACE {
+bool HandleDlopenInit() {
+  static_assert(SANITIZER_SUPPORTS_INIT_FOR_DLOPEN,
+                "Expected SANITIZER_SUPPORTS_INIT_FOR_DLOPEN to be true");
+  // We have no reliable way of knowing how we are being loaded
+  // so make it a requirement on Apple platforms to set this environment
+  // variable to indicate that we want to perform initialization via
+  // dlopen().
+  auto init_str = GetEnv("APPLE_ASAN_INIT_FOR_DLOPEN");
+  if (!init_str)
+    return false;
+  if (internal_strncmp(init_str, "1", 1) != 0)
+    return false;
+  // When we are loaded via `dlopen()` path we still initialize the malloc zone
+  // so Symbolication clients (e.g. `leaks`) that load the ASan allocator can
+  // find an initialized malloc zone.
+  InitMallocZoneFields();
+  return true;
+}
+}  // namespace COMMON_MALLOC_NAMESPACE
+
 #endif

Modified: compiler-rt/trunk/lib/asan/asan_rtems.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_rtems.cc?rev=348078&r1=348077&r2=348078&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_rtems.cc (original)
+++ compiler-rt/trunk/lib/asan/asan_rtems.cc Sat Dec  1 07:45:42 2018
@@ -213,6 +213,12 @@ static void HandleExit() {
   }
 }
 
+bool HandleDlopenInit() {
+  // Not supported on this platform.
+  static_assert(!SANITIZER_SUPPORTS_INIT_FOR_DLOPEN,
+                "Expected SANITIZER_SUPPORTS_INIT_FOR_DLOPEN to be false");
+  return false;
+}
 }  // namespace __asan
 
 // These are declared (in extern "C") by <some_path/sanitizer.h>.

Modified: compiler-rt/trunk/lib/asan/asan_rtl.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_rtl.cc?rev=348078&r1=348077&r2=348078&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_rtl.cc (original)
+++ compiler-rt/trunk/lib/asan/asan_rtl.cc Sat Dec  1 07:45:42 2018
@@ -396,6 +396,14 @@ static void AsanInitInternal() {
   // initialization steps look at flags().
   InitializeFlags();
 
+  // Stop performing init at this point if we are being loaded via
+  // dlopen() and the platform supports it.
+  if (SANITIZER_SUPPORTS_INIT_FOR_DLOPEN && UNLIKELY(HandleDlopenInit())) {
+    asan_init_is_running = false;
+    VReport(1, "AddressSanitizer init is being performed for dlopen().\n");
+    return;
+  }
+
   AsanCheckIncompatibleRT();
   AsanCheckDynamicRTPrereqs();
   AvoidCVE_2016_2143();

Modified: compiler-rt/trunk/lib/asan/asan_win.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_win.cc?rev=348078&r1=348077&r2=348078&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_win.cc (original)
+++ compiler-rt/trunk/lib/asan/asan_win.cc Sat Dec  1 07:45:42 2018
@@ -322,6 +322,13 @@ int __asan_set_seh_filter() {
   return 0;
 }
 
+bool HandleDlopenInit() {
+  // Not supported on this platform.
+  static_assert(!SANITIZER_SUPPORTS_INIT_FOR_DLOPEN,
+                "Expected SANITIZER_SUPPORTS_INIT_FOR_DLOPEN to be false");
+  return false;
+}
+
 #if !ASAN_DYNAMIC
 // The CRT runs initializers in this order:
 // - C initializers, from XIA to XIZ

Modified: compiler-rt/trunk/lib/sanitizer_common/sanitizer_platform.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/sanitizer_platform.h?rev=348078&r1=348077&r2=348078&view=diff
==============================================================================
--- compiler-rt/trunk/lib/sanitizer_common/sanitizer_platform.h (original)
+++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_platform.h Sat Dec  1 07:45:42 2018
@@ -342,4 +342,13 @@
 #define SANITIZER_SYMBOLIZER_MARKUP 0
 #endif
 
+// Enable ability to support sanitizer initialization that is
+// compatible with the sanitizer library being loaded via
+// `dlopen()`.
+#if SANITIZER_MAC
+#define SANITIZER_SUPPORTS_INIT_FOR_DLOPEN 1
+#else
+#define SANITIZER_SUPPORTS_INIT_FOR_DLOPEN 0
+#endif
+
 #endif // SANITIZER_PLATFORM_H

Added: compiler-rt/trunk/test/asan/TestCases/Darwin/init_for_dlopen.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/asan/TestCases/Darwin/init_for_dlopen.cc?rev=348078&view=auto
==============================================================================
--- compiler-rt/trunk/test/asan/TestCases/Darwin/init_for_dlopen.cc (added)
+++ compiler-rt/trunk/test/asan/TestCases/Darwin/init_for_dlopen.cc Sat Dec  1 07:45:42 2018
@@ -0,0 +1,46 @@
+// RUN: %clangxx -g -O0 %s -o %t
+
+// Check that trying to dlopen() the ASan dylib fails.
+// We explictly set `abort_on_error=0` because
+// - By default the lit config sets this but we don't want this
+//   test to implicitly depend on this.
+// - It avoids requiring `--crash` to be passed to `not`.
+// RUN: APPLE_ASAN_INIT_FOR_DLOPEN=0 %env_asan_opts=abort_on_error=0 not \
+// RUN:   %run %t %shared_libasan 2>&1 | \
+// RUN:   FileCheck -check-prefix=CHECK-DL-OPEN-FAIL %s
+// RUN: env -u APPLE_ASAN_INIT_FOR_DLOPEN %env_asan_opts=abort_on_error=0 not \
+// RUN:   %run %t %shared_libasan 2>&1 | \
+// RUN:   FileCheck -check-prefix=CHECK-DL-OPEN-FAIL %s
+
+// Check that we can successfully dlopen the ASan dylib when we set the right
+// environment variable.
+// RUN: env APPLE_ASAN_INIT_FOR_DLOPEN=1 %run %t %shared_libasan 2>&1 | \
+// RUN:   FileCheck -check-prefix=CHECK-DL-OPEN-SUCCESS %s
+
+#include <dlfcn.h>
+#include <stdio.h>
+
+// CHECK-DL-OPEN-FAIL: ERROR: Interceptors are not working
+
+int main(int argc, char **argv) {
+  if (argc != 2) {
+    fprintf(stderr, "Usage: %s <dylib_path>\n", argv[0]);
+    return 1;
+  }
+  const char *dylib_path = argv[1];
+  void *handle = dlopen(dylib_path, RTLD_LAZY);
+  if (!handle) {
+    fprintf(stderr, "Failed to dlopen: %s\n", dlerror());
+    return 1;
+  }
+  // Make sure we can find a function we expect to be in the dylib.
+  void *fn = dlsym(handle, "__sanitizer_mz_size");
+  if (!fn) {
+    fprintf(stderr, "Failed to get symbol: %s\n", dlerror());
+    return 1;
+  }
+  // TODO(dliew): Actually call a function from the dylib that is safe to call.
+  // CHECK-DL-OPEN-SUCCESS: DONE
+  printf("DONE\n");
+  return 0;
+}

Modified: compiler-rt/trunk/test/sanitizer_common/ios_commands/iossim_run.py
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/sanitizer_common/ios_commands/iossim_run.py?rev=348078&r1=348077&r2=348078&view=diff
==============================================================================
--- compiler-rt/trunk/test/sanitizer_common/ios_commands/iossim_run.py (original)
+++ compiler-rt/trunk/test/sanitizer_common/ios_commands/iossim_run.py Sat Dec  1 07:45:42 2018
@@ -8,7 +8,7 @@ if not "SANITIZER_IOSSIM_TEST_DEVICE_IDE
 
 device_id = os.environ["SANITIZER_IOSSIM_TEST_DEVICE_IDENTIFIER"]
 
-for e in ["ASAN_OPTIONS", "TSAN_OPTIONS", "UBSAN_OPTIONS"]:
+for e in ["ASAN_OPTIONS", "TSAN_OPTIONS", "UBSAN_OPTIONS", "APPLE_ASAN_INIT_FOR_DLOPEN"]:
   if e in os.environ:
     os.environ["SIMCTL_CHILD_" + e] = os.environ[e]
 




More information about the llvm-commits mailing list