From 3bb58afb11d68578d6d9bbb35ebf22c33d3a4aee Mon Sep 17 00:00:00 2001 From: Andrey Drobyshev Date: Thu, 25 Apr 2019 12:20:00 +0300 Subject: libsanitizer: introduce calls forwarding mechanism. * 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 --- libsanitizer/sanitizer_common/Makefile.am | 3 +- libsanitizer/sanitizer_common/Makefile.in | 7 +- .../sanitizer_common/sanitizer_forward_calls.cc | 74 ++++++++++++++++++++++ .../sanitizer_common/sanitizer_forward_calls.h | 58 +++++++++++++++++ .../sanitizer_interface_internal.h | 9 +++ .../sanitizer_common/sanitizer_internal_defs.h | 10 +++ 6 files changed, 158 insertions(+), 3 deletions(-) create mode 100644 libsanitizer/sanitizer_common/sanitizer_forward_calls.cc create mode 100644 libsanitizer/sanitizer_common/sanitizer_forward_calls.h diff --git a/libsanitizer/sanitizer_common/Makefile.am b/libsanitizer/sanitizer_common/Makefile.am index 4996b9ec36b..4cb75245dbe 100644 --- a/libsanitizer/sanitizer_common/Makefile.am +++ b/libsanitizer/sanitizer_common/Makefile.am @@ -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) diff --git a/libsanitizer/sanitizer_common/Makefile.in b/libsanitizer/sanitizer_common/Makefile.in index 87eb3d3c3a3..05ef11f65aa 100644 --- a/libsanitizer/sanitizer_common/Makefile.in +++ b/libsanitizer/sanitizer_common/Makefile.in @@ -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 index 00000000000..ac996a6678f --- /dev/null +++ b/libsanitizer/sanitizer_common/sanitizer_forward_calls.cc @@ -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 index 00000000000..92c29bc1765 --- /dev/null +++ b/libsanitizer/sanitizer_common/sanitizer_forward_calls.h @@ -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 diff --git a/libsanitizer/sanitizer_common/sanitizer_interface_internal.h b/libsanitizer/sanitizer_common/sanitizer_interface_internal.h index 04b8226eee7..363af03854a 100644 --- a/libsanitizer/sanitizer_common/sanitizer_interface_internal.h +++ b/libsanitizer/sanitizer_common/sanitizer_interface_internal.h @@ -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 diff --git a/libsanitizer/sanitizer_common/sanitizer_internal_defs.h b/libsanitizer/sanitizer_common/sanitizer_internal_defs.h index b9c906669de..b9f076bdcd9 100644 --- a/libsanitizer/sanitizer_common/sanitizer_internal_defs.h +++ b/libsanitizer/sanitizer_common/sanitizer_internal_defs.h @@ -45,6 +45,16 @@ # 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 -- cgit v1.2.3