[compiler-rt] 1377179 - sanitizer_common: initialize sanitizer runtimes lazily from signal interceptors

Dmitry Vyukov via llvm-commits llvm-commits at lists.llvm.org
Thu Jul 13 07:28:30 PDT 2023


Author: Dmitry Vyukov
Date: 2023-07-13T16:28:25+02:00
New Revision: 13771793965bcda8951d6bdda1ea4ace658eca11

URL: https://github.com/llvm/llvm-project/commit/13771793965bcda8951d6bdda1ea4ace658eca11
DIFF: https://github.com/llvm/llvm-project/commit/13771793965bcda8951d6bdda1ea4ace658eca11.diff

LOG: sanitizer_common: initialize sanitizer runtimes lazily from signal interceptors

Currently if a program calls sigaction very early (before non-lazy sanitizer
initialization, in particular if .preinit_array initialization is not enabled),
then sigaction will wrongly fail since the interceptor is not initialized yet.

In all other interceptors we do lazy runtime initialization for this reason,
but we don't do it in the signal interceptors.
Do lazy runtime initialization in signal interceptors as well.

Reviewed By: melver

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

Added: 
    compiler-rt/test/ubsan/TestCases/Misc/Linux/sigaction.cpp

Modified: 
    compiler-rt/lib/asan/asan_interceptors.cpp
    compiler-rt/lib/lsan/lsan_interceptors.cpp
    compiler-rt/lib/msan/msan_interceptors.cpp
    compiler-rt/lib/sanitizer_common/sanitizer_signal_interceptors.inc
    compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp
    compiler-rt/lib/ubsan/ubsan_signals_standalone.cpp
    compiler-rt/test/asan/lit.cfg.py
    compiler-rt/test/lit.common.cfg.py

Removed: 
    


################################################################################
diff  --git a/compiler-rt/lib/asan/asan_interceptors.cpp b/compiler-rt/lib/asan/asan_interceptors.cpp
index b7e162c25094eb..b9b82564b33035 100644
--- a/compiler-rt/lib/asan/asan_interceptors.cpp
+++ b/compiler-rt/lib/asan/asan_interceptors.cpp
@@ -194,6 +194,8 @@ static int munmap_interceptor(Munmap real_munmap, void *addr, SIZE_T length) {
   __lsan::ScopedInterceptorDisabler disabler
 #endif
 
+#define SIGNAL_INTERCEPTOR_ENTER() ENSURE_ASAN_INITED()
+
 #include "sanitizer_common/sanitizer_common_interceptors.inc"
 #include "sanitizer_common/sanitizer_signal_interceptors.inc"
 

diff  --git a/compiler-rt/lib/lsan/lsan_interceptors.cpp b/compiler-rt/lib/lsan/lsan_interceptors.cpp
index ade9dfdab40c46..fac6133ddf21b2 100644
--- a/compiler-rt/lib/lsan/lsan_interceptors.cpp
+++ b/compiler-rt/lib/lsan/lsan_interceptors.cpp
@@ -533,6 +533,7 @@ INTERCEPTOR(void, _exit, int status) {
 }
 
 #define COMMON_INTERCEPT_FUNCTION(name) INTERCEPT_FUNCTION(name)
+#define SIGNAL_INTERCEPTOR_ENTER() ENSURE_LSAN_INITED
 #include "sanitizer_common/sanitizer_signal_interceptors.inc"
 
 #endif  // SANITIZER_POSIX

diff  --git a/compiler-rt/lib/msan/msan_interceptors.cpp b/compiler-rt/lib/msan/msan_interceptors.cpp
index 18a54f888cfad3..f5e0d3cb9a6733 100644
--- a/compiler-rt/lib/msan/msan_interceptors.cpp
+++ b/compiler-rt/lib/msan/msan_interceptors.cpp
@@ -1441,6 +1441,8 @@ static int sigaction_impl(int signo, const __sanitizer_sigaction *act,
     return REAL(func)(signo, handler);                       \
   }
 
+#define SIGNAL_INTERCEPTOR_ENTER() ENSURE_MSAN_INITED()
+
 #include "sanitizer_common/sanitizer_signal_interceptors.inc"
 
 static int sigaction_impl(int signo, const __sanitizer_sigaction *act,

diff  --git a/compiler-rt/lib/sanitizer_common/sanitizer_signal_interceptors.inc b/compiler-rt/lib/sanitizer_common/sanitizer_signal_interceptors.inc
index 475e577d9982e8..94e4e2954a3b93 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_signal_interceptors.inc
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_signal_interceptors.inc
@@ -43,6 +43,7 @@ using namespace __sanitizer;
 
 #if SANITIZER_INTERCEPT_BSD_SIGNAL
 INTERCEPTOR(uptr, bsd_signal, int signum, uptr handler) {
+  SIGNAL_INTERCEPTOR_ENTER();
   if (GetHandleSignalMode(signum) == kHandleSignalExclusive) return 0;
   SIGNAL_INTERCEPTOR_SIGNAL_IMPL(bsd_signal, signum, handler);
 }
@@ -53,6 +54,7 @@ INTERCEPTOR(uptr, bsd_signal, int signum, uptr handler) {
 
 #if SANITIZER_INTERCEPT_SIGNAL_AND_SIGACTION
 INTERCEPTOR(uptr, signal, int signum, uptr handler) {
+  SIGNAL_INTERCEPTOR_ENTER();
   if (GetHandleSignalMode(signum) == kHandleSignalExclusive)
     return (uptr) nullptr;
   SIGNAL_INTERCEPTOR_SIGNAL_IMPL(signal, signum, handler);
@@ -61,6 +63,7 @@ INTERCEPTOR(uptr, signal, int signum, uptr handler) {
 
 INTERCEPTOR(int, sigaction_symname, int signum,
             const __sanitizer_sigaction *act, __sanitizer_sigaction *oldact) {
+  SIGNAL_INTERCEPTOR_ENTER();
   if (GetHandleSignalMode(signum) == kHandleSignalExclusive) {
     if (!oldact) return 0;
     act = nullptr;

diff  --git a/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp b/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp
index 44d20e7ca690d7..177e338bf28288 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp
+++ b/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp
@@ -2543,6 +2543,8 @@ static __sanitizer_sighandler_ptr signal_impl(int sig,
 #define SIGNAL_INTERCEPTOR_SIGNAL_IMPL(func, signo, handler) \
   { return (uptr)signal_impl(signo, (__sanitizer_sighandler_ptr)handler); }
 
+#define SIGNAL_INTERCEPTOR_ENTER() LazyInitialize(cur_thread_init())
+
 #include "sanitizer_common/sanitizer_signal_interceptors.inc"
 
 int sigaction_impl(int sig, const __sanitizer_sigaction *act,

diff  --git a/compiler-rt/lib/ubsan/ubsan_signals_standalone.cpp b/compiler-rt/lib/ubsan/ubsan_signals_standalone.cpp
index 2c91db8ca39748..354f847fab7138 100644
--- a/compiler-rt/lib/ubsan/ubsan_signals_standalone.cpp
+++ b/compiler-rt/lib/ubsan/ubsan_signals_standalone.cpp
@@ -34,7 +34,12 @@ void InitializeDeadlySignals() {}
 
 #else
 
+namespace __ubsan {
+void InitializeDeadlySignals();
+} // namespace __ubsan
+
 #define COMMON_INTERCEPT_FUNCTION(name) INTERCEPT_FUNCTION(name)
+#define SIGNAL_INTERCEPTOR_ENTER() __ubsan::InitializeDeadlySignals()
 #include "sanitizer_common/sanitizer_signal_interceptors.inc"
 
 // TODO(yln): Temporary workaround. Will be removed.

diff  --git a/compiler-rt/test/asan/lit.cfg.py b/compiler-rt/test/asan/lit.cfg.py
index e245a61ef918cd..d9303466021250 100644
--- a/compiler-rt/test/asan/lit.cfg.py
+++ b/compiler-rt/test/asan/lit.cfg.py
@@ -18,41 +18,6 @@ def get_required_attr(config, attr_name):
         )
     return attr_value
 
-
-def push_dynamic_library_lookup_path(config, new_path):
-    if platform.system() == "Windows":
-        dynamic_library_lookup_var = "PATH"
-    elif platform.system() == "Darwin":
-        dynamic_library_lookup_var = "DYLD_LIBRARY_PATH"
-    else:
-        dynamic_library_lookup_var = "LD_LIBRARY_PATH"
-
-    new_ld_library_path = os.path.pathsep.join(
-        (new_path, config.environment.get(dynamic_library_lookup_var, ""))
-    )
-    config.environment[dynamic_library_lookup_var] = new_ld_library_path
-
-    if platform.system() == "FreeBSD":
-        dynamic_library_lookup_var = "LD_32_LIBRARY_PATH"
-        new_ld_32_library_path = os.path.pathsep.join(
-            (new_path, config.environment.get(dynamic_library_lookup_var, ""))
-        )
-        config.environment[dynamic_library_lookup_var] = new_ld_32_library_path
-
-    if platform.system() == "SunOS":
-        dynamic_library_lookup_var = "LD_LIBRARY_PATH_32"
-        new_ld_library_path_32 = os.path.pathsep.join(
-            (new_path, config.environment.get(dynamic_library_lookup_var, ""))
-        )
-        config.environment[dynamic_library_lookup_var] = new_ld_library_path_32
-
-        dynamic_library_lookup_var = "LD_LIBRARY_PATH_64"
-        new_ld_library_path_64 = os.path.pathsep.join(
-            (new_path, config.environment.get(dynamic_library_lookup_var, ""))
-        )
-        config.environment[dynamic_library_lookup_var] = new_ld_library_path_64
-
-
 # Setup config name.
 config.name = "AddressSanitizer" + config.name_suffix
 
@@ -285,15 +250,6 @@ def build_invocation(compile_flags):
 ):
     config.available_features.add("leak-detection")
 
-# Set LD_LIBRARY_PATH to pick dynamic runtime up properly.
-push_dynamic_library_lookup_path(config, config.compiler_rt_libdir)
-
-# GCC-ASan uses dynamic runtime by default.
-if config.compiler_id == "GNU":
-    gcc_dir = os.path.dirname(config.clang)
-    libasan_dir = os.path.join(gcc_dir, "..", "lib" + config.bits)
-    push_dynamic_library_lookup_path(config, libasan_dir)
-
 # Add the RT libdir to PATH directly so that we can successfully run the gtest
 # binary to list its tests.
 if config.host_os == "Windows" and config.asan_dynamic:

diff  --git a/compiler-rt/test/lit.common.cfg.py b/compiler-rt/test/lit.common.cfg.py
index 24473f38b9a4c3..3b42da17b0affb 100644
--- a/compiler-rt/test/lit.common.cfg.py
+++ b/compiler-rt/test/lit.common.cfg.py
@@ -76,6 +76,40 @@ def get_path_from_clang(args, allow_failure):
     return None
 
 
+def push_dynamic_library_lookup_path(config, new_path):
+    if platform.system() == "Windows":
+        dynamic_library_lookup_var = "PATH"
+    elif platform.system() == "Darwin":
+        dynamic_library_lookup_var = "DYLD_LIBRARY_PATH"
+    else:
+        dynamic_library_lookup_var = "LD_LIBRARY_PATH"
+
+    new_ld_library_path = os.path.pathsep.join(
+        (new_path, config.environment.get(dynamic_library_lookup_var, ""))
+    )
+    config.environment[dynamic_library_lookup_var] = new_ld_library_path
+
+    if platform.system() == "FreeBSD":
+        dynamic_library_lookup_var = "LD_32_LIBRARY_PATH"
+        new_ld_32_library_path = os.path.pathsep.join(
+            (new_path, config.environment.get(dynamic_library_lookup_var, ""))
+        )
+        config.environment[dynamic_library_lookup_var] = new_ld_32_library_path
+
+    if platform.system() == "SunOS":
+        dynamic_library_lookup_var = "LD_LIBRARY_PATH_32"
+        new_ld_library_path_32 = os.path.pathsep.join(
+            (new_path, config.environment.get(dynamic_library_lookup_var, ""))
+        )
+        config.environment[dynamic_library_lookup_var] = new_ld_library_path_32
+
+        dynamic_library_lookup_var = "LD_LIBRARY_PATH_64"
+        new_ld_library_path_64 = os.path.pathsep.join(
+            (new_path, config.environment.get(dynamic_library_lookup_var, ""))
+        )
+        config.environment[dynamic_library_lookup_var] = new_ld_library_path_64
+
+
 # Choose between lit's internal shell pipeline runner and a real shell.  If
 # LIT_USE_INTERNAL_SHELL is in the environment, we use that as an override.
 use_lit_shell = os.environ.get("LIT_USE_INTERNAL_SHELL")
@@ -895,3 +929,12 @@ def is_windows_lto_supported():
 # related is likely to cause issues with sanitizer tests, because it may
 # preempt something we're looking to trap (e.g. _FORTIFY_SOURCE vs our ASAN).
 config.environment["CLANG_NO_DEFAULT_CONFIG"] = "1"
+
+# Set LD_LIBRARY_PATH to pick dynamic runtime up properly.
+push_dynamic_library_lookup_path(config, config.compiler_rt_libdir)
+
+# GCC-ASan uses dynamic runtime by default.
+if config.compiler_id == "GNU":
+    gcc_dir = os.path.dirname(config.clang)
+    libasan_dir = os.path.join(gcc_dir, "..", "lib" + config.bits)
+    push_dynamic_library_lookup_path(config, libasan_dir)

diff  --git a/compiler-rt/test/ubsan/TestCases/Misc/Linux/sigaction.cpp b/compiler-rt/test/ubsan/TestCases/Misc/Linux/sigaction.cpp
new file mode 100644
index 00000000000000..95e0cef324efe8
--- /dev/null
+++ b/compiler-rt/test/ubsan/TestCases/Misc/Linux/sigaction.cpp
@@ -0,0 +1,21 @@
+// RUN: %clangxx -fsanitize=undefined -shared-libsan %s -o %t && %run %t 2>&1 | FileCheck %s
+
+// Ensure ubsan runtime/interceptors are lazily initialized if called early.
+
+#include <assert.h>
+#include <signal.h>
+#include <stdio.h>
+
+__attribute__((constructor(0))) void ctor() {
+  fprintf(stderr, "INIT\n");
+  struct sigaction old;
+  assert(!sigaction(SIGSEGV, nullptr, &old));
+};
+
+int main() {
+  fprintf(stderr, "DONE\n");
+  return 0;
+}
+
+// CHECK: INIT
+// CHECK: DONE


        


More information about the llvm-commits mailing list