libsanitizer: introduce calls forwarding mechanism. 84/210784/10
authorAndrey Drobyshev <a.drobyshev@samsung.com>
Thu, 25 Apr 2019 09:20:00 +0000 (12:20 +0300)
committerDongkyun Son <dongkyun.s@samsung.com>
Sat, 27 Jul 2019 16:37:14 +0000 (16:37 +0000)
    * libsanitizer/sanitizer_common/Makefile.am: add file
    sanitizer_forward_calls.cc
    * libsanitizer/sanitizer_common/Makefile.in: regenerated
    * libsanitizer/sanitizer_common/sanitizer_forward_calls.cc: new file,
    implementation of calls forwarding interface
    * libsanitizer/sanitizer_common/sanitizer_forward_calls.h: new file,
    macro MAYBE_FORWARD_TO_REAL used in interceptors
    * libsanitizer/sanitizer_common/sanitizer_interface_internal.h:
    add declarations of interface functions for enabling/disabling
    interceptors
    * libsanitizer/sanitizer_common/sanitizer_internal_defs.h: add
    SANITIZER_CALLS_FORWARDING macro

Change-Id: I41367e63283798920a4cabc8a01f0192146b9057
Signed-off-by: Andrey Drobyshev <a.drobyshev@samsung.com>
libsanitizer/sanitizer_common/Makefile.am
libsanitizer/sanitizer_common/Makefile.in
libsanitizer/sanitizer_common/sanitizer_forward_calls.cc [new file with mode: 0644]
libsanitizer/sanitizer_common/sanitizer_forward_calls.h [new file with mode: 0644]
libsanitizer/sanitizer_common/sanitizer_interface_internal.h
libsanitizer/sanitizer_common/sanitizer_internal_defs.h

index 4996b9e..4cb7524 100644 (file)
@@ -61,7 +61,8 @@ sanitizer_common_files = \
        sanitizer_thread_registry.cc \
        sanitizer_tls_get_addr.cc \
        sanitizer_unwind_linux_libcdep.cc \
-       sanitizer_win.cc
+       sanitizer_win.cc \
+       sanitizer_forward_calls.cc
 
 
 libsanitizer_common_la_SOURCES = $(sanitizer_common_files) 
index 87eb3d3..05ef11f 100644 (file)
@@ -105,7 +105,8 @@ am__objects_1 = sanitizer_allocator.lo sanitizer_common.lo \
        sanitizer_symbolizer_posix_libcdep.lo \
        sanitizer_symbolizer_win.lo sanitizer_termination.lo \
        sanitizer_thread_registry.lo sanitizer_tls_get_addr.lo \
-       sanitizer_unwind_linux_libcdep.lo sanitizer_win.lo
+       sanitizer_unwind_linux_libcdep.lo sanitizer_win.lo \
+       sanitizer_forward_calls.lo
 am_libsanitizer_common_la_OBJECTS = $(am__objects_1)
 libsanitizer_common_la_OBJECTS = $(am_libsanitizer_common_la_OBJECTS)
 DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
@@ -344,7 +345,8 @@ sanitizer_common_files = \
        sanitizer_thread_registry.cc \
        sanitizer_tls_get_addr.cc \
        sanitizer_unwind_linux_libcdep.cc \
-       sanitizer_win.cc
+       sanitizer_win.cc \
+       sanitizer_forward_calls.cc
 
 libsanitizer_common_la_SOURCES = $(sanitizer_common_files) 
 EXTRA_libsanitizer_common_la_SOURCES = sanitizer_linux_mips64.S sanitizer_linux_x86_64.S
@@ -452,6 +454,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_deadlock_detector2.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_flag_parser.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_flags.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_forward_calls.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_libc.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_libignore.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_linux.Plo@am__quote@
diff --git a/libsanitizer/sanitizer_common/sanitizer_forward_calls.cc b/libsanitizer/sanitizer_common/sanitizer_forward_calls.cc
new file mode 100644 (file)
index 0000000..ac996a6
--- /dev/null
@@ -0,0 +1,74 @@
+//===-- sanitizer_forward_calls.cc ----------------------------------------===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Implementation of calls forwarding interface.
+// Used in applications to enable/disable forwarding calls from interceptors
+// to libc versions.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_forward_calls.h"
+#include "sanitizer_allocator_internal.h"
+#include "sanitizer_flags.h"
+
+#if SANITIZER_CALLS_FORWARDING
+
+namespace __sanitizer {
+// This flag controls the state of calls forwarding mechanism:
+// if unset, interceptors work as usual (they're "enabled");
+// if set, calls to interceptors are being forwarded to libc versions
+// (interceptors are "disabled").
+__attribute__((tls_model("initial-exec")))
+static THREADLOCAL bool *forward_flag;
+
+static bool *GetFlag()
+{
+  if (UNLIKELY(!forward_flag)) {
+    // We will not release the memory.
+    forward_flag = (bool *)InternalAlloc(sizeof(*forward_flag));
+    *forward_flag = !common_flags()->enable_interceptors;
+  }
+
+  return forward_flag;
+}
+
+static void SetForwardingCalls(bool val) {
+  *GetFlag() = val;
+}
+
+static bool GetForwardingCalls() {
+  return *GetFlag();
+}
+
+bool ForwardCalls() {
+  return __sanitizer::GetForwardingCalls();
+}
+} // namespace __sanitizer
+
+extern "C" {
+// "Enables" interceptors (disabling calls forwarding mechanism):
+// interceptors now work in usual mode.
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+void __sanitizer_enable_interceptors() {
+  __sanitizer::SetForwardingCalls(false);
+}
+
+// "Disables" interceptors (enabling calls forwarding mechanism):
+// interceptors become transparent and calls to them are forwarded to libc.
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+void __sanitizer_disable_interceptors() {
+  __sanitizer::SetForwardingCalls(true);
+}
+
+// Checks current state of calls forwarding mechanism: whether interceptors
+// enabled or not.
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+bool __sanitizer_interceptors_are_enabled() {
+  return !__sanitizer::ForwardCalls();
+}
+} // extern "C"
+
+#endif // SANITIZER_CALLS_FORWARDING
diff --git a/libsanitizer/sanitizer_common/sanitizer_forward_calls.h b/libsanitizer/sanitizer_common/sanitizer_forward_calls.h
new file mode 100644 (file)
index 0000000..92c29bc
--- /dev/null
@@ -0,0 +1,58 @@
+//===-- sanitizer_forward_calls.h -------------------------------*- C++ -*-===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// General calls forwarding interface. Used in interceptors.
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_FORWARD_CALLS_H
+#define SANITIZER_FORWARD_CALLS_H
+
+#include "sanitizer_common.h"
+#include "sanitizer_internal_defs.h"
+
+#if SANITIZER_CALLS_FORWARDING
+
+namespace __sanitizer {
+bool ForwardCalls();
+}
+
+// This macro checks whether calls forwarding mechanism is currently enabled
+// (flag sanitizer_forward_calls is set). If it is, we call the libc version,
+// which is REAL(func).
+// If REAL(func) is unset, i.e. this symbol hasn't been intercepted yet, we
+// first try to intercept it (via call to dlsym), then call the libc version.
+//
+// Note: as dlsym may use memory allocations internally, we enable interceptors
+// (i.e. disable calls forwarding) before and disable them after calling
+// INTERCEPT_FUNCTION, thus enforcing usage of ASan memory-related functions
+// and avoiding alloc-dealloc mismatch issues.
+#define MAYBE_FORWARD_TO_REAL(func, ...)                                \
+  do {                                                                  \
+    if (__sanitizer::ForwardCalls()) {                                  \
+        if (LIKELY(REAL(func)))                                         \
+          return REAL(func)(__VA_ARGS__);                               \
+        else {                                                          \
+          VReport(1, "WARNING: function '"#func"' wasn't"               \
+                     " intercepted; intercepting now\n");               \
+          __sanitizer_enable_interceptors();                            \
+          bool int_res = INTERCEPT_FUNCTION(func);                      \
+          __sanitizer_disable_interceptors();                           \
+          if (!int_res || !REAL(func))                                  \
+            VReport(1, "Failed to intercept function '"#func"'\n");     \
+          else                                                          \
+            return REAL(func)(__VA_ARGS__);                             \
+        }                                                               \
+      }                                                                 \
+  } while (0)
+
+#else
+
+#define MAYBE_FORWARD_TO_REAL(func, ...) {}
+
+#endif // SANITIZER_CALLS_FORWARDING
+
+#endif // SANITIZER_FORWARD_CALLS_H
index 04b8226..363af03 100644 (file)
@@ -67,6 +67,15 @@ extern "C" {
                                                char *module_name,
                                                __sanitizer::uptr module_name_len,
                                                __sanitizer::uptr *pc_offset);
+
+#if SANITIZER_CALLS_FORWARDING
+  SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+  void __sanitizer_enable_interceptors();
+  SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+  void __sanitizer_disable_interceptors();
+  SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+  bool __sanitizer_interceptors_are_enabled();
+#endif // SANITIZER_CALLS_FORWARDING
   } // extern "C"
 
 #endif  // SANITIZER_INTERFACE_INTERNAL_H
index b9c9066..b9f076b 100644 (file)
 # define SANITIZER_CAN_USE_PREINIT_ARRAY 0
 #endif
 
+#ifdef SANITIZER_SWITCHABLE_INTERCEPTORS
+# if SANITIZER_LINUX && !SANITIZER_ANDROID
+#  define SANITIZER_CALLS_FORWARDING 1
+# else
+#  error "This platform does not support switchable interceptors"
+# endif
+#else
+# define SANITIZER_CALLS_FORWARDING 0
+#endif // SANITIZER_SWITCHABLE_INTERCEPTORS
+
 // GCC does not understand __has_feature
 #if !defined(__has_feature)
 # define __has_feature(x) 0