[compiler-rt] r228392 - [compiler-rt] Make MaybeReexec properly process DYLD_INSERT_LIBRARIES when using non-absolute paths

Kuba Brecka kuba.brecka at gmail.com
Fri Feb 6 04:07:31 PST 2015


Author: kuba.brecka
Date: Fri Feb  6 06:07:29 2015
New Revision: 228392

URL: http://llvm.org/viewvc/llvm-project?rev=228392&view=rev
Log:
[compiler-rt] Make MaybeReexec properly process DYLD_INSERT_LIBRARIES when using non-absolute paths

MaybeReexec() in asan_mac.cc checks for presence of the ASan dylib in DYLD_INSERT_LIBRARIES, and if it is there, it will process this env. var. and remove the dylib from its value, so that spawned children don't have this variable set. However, the current implementation only works when using a canonical absolute path to the dylib, it fails to remove the dylib for example when using @executable_path.

This patch changes the processing of DYLD_INSERT_LIBRARIES to comparing values only based on filenames (ignoring directories).

Reviewed at http://reviews.llvm.org/D7160


Added:
    compiler-rt/trunk/test/asan/TestCases/Darwin/dyld_insert_libraries_remove.cc
Modified:
    compiler-rt/trunk/lib/asan/asan_mac.cc
    compiler-rt/trunk/lib/sanitizer_common/sanitizer_libc.cc
    compiler-rt/trunk/lib/sanitizer_common/sanitizer_libc.h

Modified: compiler-rt/trunk/lib/asan/asan_mac.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_mac.cc?rev=228392&r1=228391&r2=228392&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_mac.cc (original)
+++ compiler-rt/trunk/lib/asan/asan_mac.cc Fri Feb  6 06:07:29 2015
@@ -112,8 +112,10 @@ void MaybeReexec() {
   uptr old_env_len = dyld_insert_libraries ?
       internal_strlen(dyld_insert_libraries) : 0;
   uptr fname_len = internal_strlen(info.dli_fname);
+  const char *dylib_name = StripModuleName(info.dli_fname);
+  uptr dylib_name_len = internal_strlen(dylib_name);
   if (!dyld_insert_libraries ||
-      !REAL(strstr)(dyld_insert_libraries, StripModuleName(info.dli_fname))) {
+      !REAL(strstr)(dyld_insert_libraries, dylib_name)) {
     // DYLD_INSERT_LIBRARIES is not set or does not contain the runtime
     // library.
     char program_name[1024];
@@ -148,56 +150,65 @@ void MaybeReexec() {
            "possibly because of sandbox restrictions. Make sure to launch the "
            "executable with:\n%s=%s\n", kDyldInsertLibraries, new_env);
     CHECK("execv failed" && 0);
-  } else {
-    // DYLD_INSERT_LIBRARIES is set and contains the runtime library.
-    if (old_env_len == fname_len) {
-      // It's just the runtime library name - fine to unset the variable.
-      LeakyResetEnv(kDyldInsertLibraries, NULL);
+  }
+
+  // DYLD_INSERT_LIBRARIES is set and contains the runtime library. Let's remove
+  // the dylib from the environment variable, because interceptors are installed
+  // and we don't want our children to inherit the variable.
+
+  uptr env_name_len = internal_strlen(kDyldInsertLibraries);
+  // Allocate memory to hold the previous env var name, its value, the '='
+  // sign and the '\0' char.
+  char *new_env = (char*)allocator_for_env.Allocate(
+      old_env_len + 2 + env_name_len);
+  CHECK(new_env);
+  internal_memset(new_env, '\0', old_env_len + 2 + env_name_len);
+  internal_strncpy(new_env, kDyldInsertLibraries, env_name_len);
+  new_env[env_name_len] = '=';
+  char *new_env_pos = new_env + env_name_len + 1;
+
+  // Iterate over colon-separated pieces of |dyld_insert_libraries|.
+  char *piece_start = dyld_insert_libraries;
+  char *piece_end = NULL;
+  char *old_env_end = dyld_insert_libraries + old_env_len;
+  do {
+    if (piece_start[0] == ':') piece_start++;
+    piece_end = REAL(strchr)(piece_start, ':');
+    if (!piece_end) piece_end = dyld_insert_libraries + old_env_len;
+    if ((uptr)(piece_start - dyld_insert_libraries) > old_env_len) break;
+    uptr piece_len = piece_end - piece_start;
+
+    char *filename_start =
+        (char *)internal_memrchr(piece_start, '/', piece_len);
+    uptr filename_len = piece_len;
+    if (filename_start) {
+      filename_start += 1;
+      filename_len = piece_len - (filename_start - piece_start);
     } else {
-      uptr env_name_len = internal_strlen(kDyldInsertLibraries);
-      // Allocate memory to hold the previous env var name, its value, the '='
-      // sign and the '\0' char.
-      char *new_env = (char*)allocator_for_env.Allocate(
-          old_env_len + 2 + env_name_len);
-      CHECK(new_env);
-      internal_memset(new_env, '\0', old_env_len + 2 + env_name_len);
-      internal_strncpy(new_env, kDyldInsertLibraries, env_name_len);
-      new_env[env_name_len] = '=';
-      char *new_env_pos = new_env + env_name_len + 1;
-
-      // Iterate over colon-separated pieces of |dyld_insert_libraries|.
-      char *piece_start = dyld_insert_libraries;
-      char *piece_end = NULL;
-      char *old_env_end = dyld_insert_libraries + old_env_len;
-      do {
-        if (piece_start[0] == ':') piece_start++;
-        piece_end =  REAL(strchr)(piece_start, ':');
-        if (!piece_end) piece_end = dyld_insert_libraries + old_env_len;
-        if ((uptr)(piece_start - dyld_insert_libraries) > old_env_len) break;
-        uptr piece_len = piece_end - piece_start;
-
-        // If the current piece isn't the runtime library name,
-        // append it to new_env.
-        if ((piece_len != fname_len) ||
-            (internal_strncmp(piece_start, info.dli_fname, fname_len) != 0)) {
-          if (new_env_pos != new_env + env_name_len + 1) {
-            new_env_pos[0] = ':';
-            new_env_pos++;
-          }
-          internal_strncpy(new_env_pos, piece_start, piece_len);
-        }
-        // Move on to the next piece.
-        new_env_pos += piece_len;
-        piece_start = piece_end;
-      } while (piece_start < old_env_end);
-
-      // Can't use setenv() here, because it requires the allocator to be
-      // initialized.
-      // FIXME: instead of filtering DYLD_INSERT_LIBRARIES here, do it in
-      // a separate function called after InitializeAllocator().
-      LeakyResetEnv(kDyldInsertLibraries, new_env);
+      filename_start = piece_start;
     }
-  }
+
+    // If the current piece isn't the runtime library name,
+    // append it to new_env.
+    if ((dylib_name_len != filename_len) ||
+        (internal_memcmp(filename_start, dylib_name, dylib_name_len) != 0)) {
+      if (new_env_pos != new_env + env_name_len + 1) {
+        new_env_pos[0] = ':';
+        new_env_pos++;
+      }
+      internal_strncpy(new_env_pos, piece_start, piece_len);
+      new_env_pos += piece_len;
+    }
+    // Move on to the next piece.
+    piece_start = piece_end;
+  } while (piece_start < old_env_end);
+
+  // Can't use setenv() here, because it requires the allocator to be
+  // initialized.
+  // FIXME: instead of filtering DYLD_INSERT_LIBRARIES here, do it in
+  // a separate function called after InitializeAllocator().
+  if (new_env_pos == new_env + env_name_len + 1) new_env = NULL;
+  LeakyResetEnv(kDyldInsertLibraries, new_env);
 }
 
 // No-op. Mac does not support static linkage anyway.

Modified: compiler-rt/trunk/lib/sanitizer_common/sanitizer_libc.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/sanitizer_libc.cc?rev=228392&r1=228391&r2=228392&view=diff
==============================================================================
--- compiler-rt/trunk/lib/sanitizer_common/sanitizer_libc.cc (original)
+++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_libc.cc Fri Feb  6 06:07:29 2015
@@ -28,6 +28,15 @@ void *internal_memchr(const void *s, int
   return 0;
 }
 
+void *internal_memrchr(const void *s, int c, uptr n) {
+  const char *t = (const char *)s;
+  void *res = nullptr;
+  for (uptr i = 0; i < n; ++i, ++t) {
+    if (*t == c) res = reinterpret_cast<void *>(const_cast<char *>(t));
+  }
+  return res;
+}
+
 int internal_memcmp(const void* s1, const void* s2, uptr n) {
   const char *t1 = (const char *)s1;
   const char *t2 = (const char *)s2;

Modified: compiler-rt/trunk/lib/sanitizer_common/sanitizer_libc.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/sanitizer_libc.h?rev=228392&r1=228391&r2=228392&view=diff
==============================================================================
--- compiler-rt/trunk/lib/sanitizer_common/sanitizer_libc.h (original)
+++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_libc.h Fri Feb  6 06:07:29 2015
@@ -26,6 +26,7 @@ namespace __sanitizer {
 // String functions
 s64 internal_atoll(const char *nptr);
 void *internal_memchr(const void *s, int c, uptr n);
+void *internal_memrchr(const void *s, int c, uptr n);
 int internal_memcmp(const void* s1, const void* s2, uptr n);
 void *internal_memcpy(void *dest, const void *src, uptr n);
 void *internal_memmove(void *dest, const void *src, uptr n);

Added: compiler-rt/trunk/test/asan/TestCases/Darwin/dyld_insert_libraries_remove.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/asan/TestCases/Darwin/dyld_insert_libraries_remove.cc?rev=228392&view=auto
==============================================================================
--- compiler-rt/trunk/test/asan/TestCases/Darwin/dyld_insert_libraries_remove.cc (added)
+++ compiler-rt/trunk/test/asan/TestCases/Darwin/dyld_insert_libraries_remove.cc Fri Feb  6 06:07:29 2015
@@ -0,0 +1,39 @@
+// Check that when launching with DYLD_INSERT_LIBRARIES, we properly remove
+// the ASan dylib from the environment variable (both when using an absolute
+// or relative path) and also that the other dylibs are left untouched.
+
+// RUN: mkdir -p %T/dyld_insert_libraries_remove
+// RUN: cp `%clang_asan %s -fsanitize=address -### 2>&1 \
+// RUN:   | grep "libclang_rt.asan_osx_dynamic.dylib" \
+// RUN:   | sed -e 's/.*"\(.*libclang_rt.asan_osx_dynamic.dylib\)".*/\1/'` \
+// RUN:   %T/dyld_insert_libraries_remove/libclang_rt.asan_osx_dynamic.dylib
+
+// RUN: %clangxx_asan %s -o %T/dyld_insert_libraries_remove/a.out
+// RUN: %clangxx -DSHARED_LIB %s \
+// RUN:     -dynamiclib -o %T/dyld_insert_libraries_remove/dummy-so.dylib
+
+// RUN: ( cd %T/dyld_insert_libraries_remove && \
+// RUN:   DYLD_INSERT_LIBRARIES=@executable_path/libclang_rt.asan_osx_dynamic.dylib:dummy-so.dylib \
+// RUN:   %run ./a.out 2>&1 ) | FileCheck %s || exit 1
+
+// RUN: ( cd %T/dyld_insert_libraries_remove && \
+// RUN:   DYLD_INSERT_LIBRARIES=libclang_rt.asan_osx_dynamic.dylib:dummy-so.dylib \
+// RUN:   %run ./a.out 2>&1 ) | FileCheck %s || exit 1
+
+// RUN: ( cd %T/dyld_insert_libraries_remove && \
+// RUN:   DYLD_INSERT_LIBRARIES=%T/dyld_insert_libraries_remove/libclang_rt.asan_osx_dynamic.dylib:dummy-so.dylib \
+// RUN:   %run ./a.out 2>&1 ) | FileCheck %s || exit 1
+
+#if !defined(SHARED_LIB)
+#include <stdio.h>
+#include <stdlib.h>
+
+int main() {
+  const char kEnvName[] = "DYLD_INSERT_LIBRARIES";
+  printf("%s=%s\n", kEnvName, getenv(kEnvName));
+  // CHECK: {{DYLD_INSERT_LIBRARIES=dummy-so.dylib}}
+  return 0;
+}
+#else  // SHARED_LIB
+void foo() {}
+#endif  // SHARED_LIB





More information about the llvm-commits mailing list