[compiler-rt] r272676 - [sanitizer][esan] Add internal_sigaction_syscall

Derek Bruening via llvm-commits llvm-commits at lists.llvm.org
Tue Jun 14 08:15:38 PDT 2016


Author: bruening
Date: Tue Jun 14 10:15:38 2016
New Revision: 272676

URL: http://llvm.org/viewvc/llvm-project?rev=272676&view=rev
Log:
[sanitizer][esan] Add internal_sigaction_syscall

Summary:
Adds a version of sigaction that uses a raw system call, to avoid circular
dependencies and support calling sigaction prior to setting up
interceptors.  The new sigaction relies on an assembly sigreturn routine
for its restorer, which is Linux x86_64-only for now.

Uses the new sigaction to initialize the working set tool's shadow fault
handler prior to libc interceptor being set up.  This is required to
support instrumentation invoked during interceptor setup, which happens
with an instrumented tcmalloc or other allocator compiled with esan.

Adds a test that emulates an instrumented allocator.

Reviewers: aizatsky

Subscribers: vitalybuka, tberghammer, zhaoqin, danalbert, kcc, srhines, eugenis, llvm-commits, kubabrecka

Differential Revision: http://reviews.llvm.org/D21083

Added:
    compiler-rt/trunk/lib/sanitizer_common/sanitizer_linux_x86_64.S
    compiler-rt/trunk/test/esan/TestCases/workingset-early-fault.c   (with props)
Modified:
    compiler-rt/trunk/lib/esan/esan.cpp
    compiler-rt/trunk/lib/esan/esan_interceptors.cpp
    compiler-rt/trunk/lib/esan/working_set.cpp
    compiler-rt/trunk/lib/esan/working_set.h
    compiler-rt/trunk/lib/sanitizer_common/CMakeLists.txt
    compiler-rt/trunk/lib/sanitizer_common/sanitizer_linux.cc
    compiler-rt/trunk/lib/sanitizer_common/sanitizer_linux.h

Modified: compiler-rt/trunk/lib/esan/esan.cpp
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/esan/esan.cpp?rev=272676&r1=272675&r2=272676&view=diff
==============================================================================
--- compiler-rt/trunk/lib/esan/esan.cpp (original)
+++ compiler-rt/trunk/lib/esan/esan.cpp Tue Jun 14 10:15:38 2016
@@ -197,6 +197,9 @@ void initializeLibrary(ToolType Tool) {
   }
 
   initializeShadow();
+  if (__esan_which_tool == ESAN_WorkingSet)
+    initializeShadowWorkingSet();
+
   initializeInterceptors();
 
   if (__esan_which_tool == ESAN_CacheFrag) {

Modified: compiler-rt/trunk/lib/esan/esan_interceptors.cpp
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/esan/esan_interceptors.cpp?rev=272676&r1=272675&r2=272676&view=diff
==============================================================================
--- compiler-rt/trunk/lib/esan/esan_interceptors.cpp (original)
+++ compiler-rt/trunk/lib/esan/esan_interceptors.cpp Tue Jun 14 10:15:38 2016
@@ -17,6 +17,7 @@
 #include "interception/interception.h"
 #include "sanitizer_common/sanitizer_common.h"
 #include "sanitizer_common/sanitizer_libc.h"
+#include "sanitizer_common/sanitizer_linux.h"
 #include "sanitizer_common/sanitizer_stacktrace.h"
 
 using namespace __esan; // NOLINT
@@ -397,6 +398,11 @@ INTERCEPTOR(int, sigaction, int signum,
 // This is required to properly use internal_sigaction.
 namespace __sanitizer {
 int real_sigaction(int signum, const void *act, void *oldact) {
+  if (REAL(sigaction) == nullptr) {
+    // With an instrumented allocator, this is called during interceptor init
+    // and we need a raw syscall solution.
+    return internal_sigaction_syscall(signum, act, oldact);
+  }
   return REAL(sigaction)(signum, (const struct sigaction *)act,
                          (struct sigaction *)oldact);
 }

Modified: compiler-rt/trunk/lib/esan/working_set.cpp
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/esan/working_set.cpp?rev=272676&r1=272675&r2=272676&view=diff
==============================================================================
--- compiler-rt/trunk/lib/esan/working_set.cpp (original)
+++ compiler-rt/trunk/lib/esan/working_set.cpp Tue Jun 14 10:15:38 2016
@@ -182,10 +182,13 @@ static void takeSample(void *Arg) {
   }
 }
 
-void initializeWorkingSet() {
+// Initialization that must be done before any instrumented code is executed.
+void initializeShadowWorkingSet() {
   CHECK(getFlags()->cache_line_size == CacheLineSize);
   registerMemoryFaultHandler();
+}
 
+void initializeWorkingSet() {
   if (getFlags()->record_snapshots) {
     for (u32 i = 0; i < NumFreq; ++i)
       SizePerFreq[i].initialize(CircularBufferSizes[i]);

Modified: compiler-rt/trunk/lib/esan/working_set.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/esan/working_set.h?rev=272676&r1=272675&r2=272676&view=diff
==============================================================================
--- compiler-rt/trunk/lib/esan/working_set.h (original)
+++ compiler-rt/trunk/lib/esan/working_set.h Tue Jun 14 10:15:38 2016
@@ -21,6 +21,7 @@
 namespace __esan {
 
 void initializeWorkingSet();
+void initializeShadowWorkingSet();
 int finalizeWorkingSet();
 void processRangeAccessWorkingSet(uptr PC, uptr Addr, SIZE_T Size,
                                   bool IsWrite);

Modified: compiler-rt/trunk/lib/sanitizer_common/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/CMakeLists.txt?rev=272676&r1=272675&r2=272676&view=diff
==============================================================================
--- compiler-rt/trunk/lib/sanitizer_common/CMakeLists.txt (original)
+++ compiler-rt/trunk/lib/sanitizer_common/CMakeLists.txt Tue Jun 14 10:15:38 2016
@@ -34,6 +34,11 @@ set(SANITIZER_SOURCES_NOTERMINATION
   sanitizer_thread_registry.cc
   sanitizer_win.cc)
 
+if(UNIX AND NOT APPLE)
+  list(APPEND SANITIZER_SOURCES_NOTERMINATION
+    sanitizer_linux_x86_64.S)
+endif()
+
 set(SANITIZER_SOURCES
   ${SANITIZER_SOURCES_NOTERMINATION} sanitizer_termination.cc)
 
@@ -133,6 +138,17 @@ append_list_if(SANITIZER_LIMIT_FRAME_SIZ
 append_list_if(COMPILER_RT_HAS_WGLOBAL_CONSTRUCTORS_FLAG -Wglobal-constructors
                SANITIZER_CFLAGS)
 
+if (LLVM_ENABLE_PEDANTIC AND UNIX AND NOT APPLE)
+  # With -pedantic, our .S files raise warnings about empty macro arguments
+  # from __USER_LABEL_PREFIX__ being an empty arg to GLUE().  Unfortunately,
+  # there is no simple way to test for an empty define, nor to disable just
+  # that warning or to disable -pedantic.  There is also no simple way to
+  # remove -pedantic from just this file (we'd have to remove from
+  # CMAKE_C*_FLAGS and re-add as a source property to all the non-.S files).
+  set_source_files_properties(sanitizer_linux_x86_64.S
+    PROPERTIES COMPILE_FLAGS "-w")
+endif ()
+
 if(APPLE)
   set(OS_OPTION OS ${SANITIZER_COMMON_SUPPORTED_OS})
 endif()

Modified: compiler-rt/trunk/lib/sanitizer_common/sanitizer_linux.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/sanitizer_linux.cc?rev=272676&r1=272675&r2=272676&view=diff
==============================================================================
--- compiler-rt/trunk/lib/sanitizer_common/sanitizer_linux.cc (original)
+++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_linux.cc Tue Jun 14 10:15:38 2016
@@ -99,6 +99,12 @@ const int FUTEX_WAKE = 1;
 # define SANITIZER_LINUX_USES_64BIT_SYSCALLS 0
 #endif
 
+#if defined(__x86_64__)
+extern "C" {
+extern void internal_sigreturn();
+}
+#endif
+
 namespace __sanitizer {
 
 #if SANITIZER_LINUX && defined(__x86_64__)
@@ -616,7 +622,8 @@ int internal_fork() {
 
 #if SANITIZER_LINUX
 #define SA_RESTORER 0x04000000
-// Doesn't set sa_restorer, use with caution (see below).
+// Doesn't set sa_restorer if the caller did not set it, so use with caution
+//(see below).
 int internal_sigaction_norestorer(int signum, const void *act, void *oldact) {
   __sanitizer_kernel_sigaction_t k_act, k_oldact;
   internal_memset(&k_act, 0, sizeof(__sanitizer_kernel_sigaction_t));
@@ -660,6 +667,23 @@ int internal_sigaction_norestorer(int si
   }
   return result;
 }
+
+// Invokes sigaction via a raw syscall with a restorer, but does not support
+// all platforms yet.
+// We disable for Go simply because we have not yet added to buildgo.sh.
+#if defined(__x86_64__) && !SANITIZER_GO
+int internal_sigaction_syscall(int signum, const void *act, void *oldact) {
+  __sanitizer_sigaction u_adjust;
+  internal_memcpy(&u_adjust, act, sizeof(u_adjust));
+#if !SANITIZER_ANDROID || !SANITIZER_MIPS32
+    if (u_adjust.sa_restorer == nullptr) {
+      u_adjust.sa_restorer = internal_sigreturn;
+    }
+#endif
+    return internal_sigaction_norestorer(signum, (const void *)&u_adjust,
+                                         oldact);
+}
+#endif // defined(__x86_64__) && !SANITIZER_GO
 #endif  // SANITIZER_LINUX
 
 uptr internal_sigprocmask(int how, __sanitizer_sigset_t *set,

Modified: compiler-rt/trunk/lib/sanitizer_common/sanitizer_linux.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/sanitizer_linux.h?rev=272676&r1=272675&r2=272676&view=diff
==============================================================================
--- compiler-rt/trunk/lib/sanitizer_common/sanitizer_linux.h (original)
+++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_linux.h Tue Jun 14 10:15:38 2016
@@ -42,6 +42,10 @@ uptr internal_prctl(int option, uptr arg
 // (like the process-wide error reporting SEGV handler) must use
 // internal_sigaction instead.
 int internal_sigaction_norestorer(int signum, const void *act, void *oldact);
+#if defined(__x86_64__) && !SANITIZER_GO
+// Uses a raw system call to avoid interceptors.
+int internal_sigaction_syscall(int signum, const void *act, void *oldact);
+#endif
 void internal_sigdelset(__sanitizer_sigset_t *set, int signum);
 #if defined(__x86_64__) || defined(__mips__) || defined(__aarch64__) \
   || defined(__powerpc64__) || defined(__s390__)

Added: compiler-rt/trunk/lib/sanitizer_common/sanitizer_linux_x86_64.S
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/sanitizer_linux_x86_64.S?rev=272676&view=auto
==============================================================================
--- compiler-rt/trunk/lib/sanitizer_common/sanitizer_linux_x86_64.S (added)
+++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_linux_x86_64.S Tue Jun 14 10:15:38 2016
@@ -0,0 +1,25 @@
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+
+// Avoid being marked as needing an executable stack:
+#if defined(__linux__) && defined(__ELF__)
+.section .note.GNU-stack,"",%progbits
+#endif
+
+// Further contents are x86_64-only:
+#if defined(__linux__) && defined(__x86_64__)
+
+#include "../builtins/assembly.h"
+
+// If the "naked" function attribute were supported for x86 we could
+// do this via inline asm.
+.text
+.balign 4
+DEFINE_COMPILERRT_FUNCTION(internal_sigreturn)
+        mov           $0xf,             %eax    // 0xf == SYS_rt_sigreturn
+        mov           %rcx,             %r10
+        syscall
+        ret                                     // Won't normally reach here.
+END_COMPILERRT_FUNCTION(internal_sigreturn)
+
+#endif // defined(__linux__) && defined(__x86_64__)

Added: compiler-rt/trunk/test/esan/TestCases/workingset-early-fault.c
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/esan/TestCases/workingset-early-fault.c?rev=272676&view=auto
==============================================================================
--- compiler-rt/trunk/test/esan/TestCases/workingset-early-fault.c (added)
+++ compiler-rt/trunk/test/esan/TestCases/workingset-early-fault.c Tue Jun 14 10:15:38 2016
@@ -0,0 +1,33 @@
+// Test shadow faults during esan initialization as well as
+// faults during dlsym's calloc during interceptor init.
+//
+// RUN: %clang_esan_wset %s -o %t
+// RUN: %run %t 2>&1 | FileCheck %s
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+// Our goal is to emulate an instrumented allocator, whose calloc
+// invoked from dlsym will trigger shadow faults, to test an
+// early shadow fault during esan interceptor init.
+// We do this by replacing calloc:
+void *calloc(size_t size, size_t n) {
+  // Unfortunately we can't print anything to make the test
+  // ensure we got here b/c the sanitizer interceptors can't
+  // handle that during interceptor init.
+
+  // Ensure we trigger a shadow write fault:
+  int x[16];
+  x[0] = size;
+  // Now just emulate calloc.
+  void *res = malloc(size*n);
+  memset(res, 0, size*n);
+  return res;
+}
+
+int main(int argc, char **argv) {
+  printf("all done\n");
+  return 0;
+}
+// CHECK: all done

Propchange: compiler-rt/trunk/test/esan/TestCases/workingset-early-fault.c
------------------------------------------------------------------------------
    svn:eol-style = LF




More information about the llvm-commits mailing list