[compiler-rt] r274672 - [esan|wset] Ensure SIGSEGV is not blocked

Derek Bruening via llvm-commits llvm-commits at lists.llvm.org
Wed Jul 6 14:04:49 PDT 2016


Author: bruening
Date: Wed Jul  6 16:04:48 2016
New Revision: 274672

URL: http://llvm.org/viewvc/llvm-project?rev=274672&view=rev
Log:
[esan|wset] Ensure SIGSEGV is not blocked

Summary:
Adds interception of sigprocmask and pthread_sigmask to esan so that the
working set tool can prevent SIGSEGV from being blocked.  A blocked SIGSEGV
results in crashes due to our lazy shadow page allocation scheme.

Adds new sanitizer helper functions internal_sigemptyset and
internal_sigismember.

Adds a test to workingset-signal-posix.cpp.

Reviewers: aizatsky

Subscribers: vitalybuka, zhaoqin, kcc, eugenis, llvm-commits, kubabrecka

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

Modified:
    compiler-rt/trunk/lib/esan/esan.cpp
    compiler-rt/trunk/lib/esan/esan.h
    compiler-rt/trunk/lib/esan/esan_interceptors.cpp
    compiler-rt/trunk/lib/esan/working_set.h
    compiler-rt/trunk/lib/esan/working_set_posix.cpp
    compiler-rt/trunk/lib/sanitizer_common/sanitizer_linux.cc
    compiler-rt/trunk/lib/sanitizer_common/sanitizer_posix.h
    compiler-rt/trunk/test/esan/TestCases/workingset-signal-posix.cpp

Modified: compiler-rt/trunk/lib/esan/esan.cpp
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/esan/esan.cpp?rev=274672&r1=274671&r2=274672&view=diff
==============================================================================
--- compiler-rt/trunk/lib/esan/esan.cpp (original)
+++ compiler-rt/trunk/lib/esan/esan.cpp Wed Jul  6 16:04:48 2016
@@ -85,6 +85,12 @@ bool processSigaction(int SigNum, const
   return true;
 }
 
+bool processSigprocmask(int How, void *Set, void *OldSet) {
+  if (__esan_which_tool == ESAN_WorkingSet)
+    return processWorkingSetSigprocmask(How, Set, OldSet);
+  return true;
+}
+
 #if SANITIZER_DEBUG
 static bool verifyShadowScheme() {
   // Sanity checks for our shadow mapping scheme.

Modified: compiler-rt/trunk/lib/esan/esan.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/esan/esan.h?rev=274672&r1=274671&r2=274672&view=diff
==============================================================================
--- compiler-rt/trunk/lib/esan/esan.h (original)
+++ compiler-rt/trunk/lib/esan/esan.h Wed Jul  6 16:04:48 2016
@@ -51,6 +51,7 @@ uptr checkMmapResult(uptr Addr, SIZE_T S
 // The return value indicates whether to call the real version or not.
 bool processSignal(int SigNum, void (*Handler)(int), void (**Result)(int));
 bool processSigaction(int SigNum, const void *Act, void *OldAct);
+bool processSigprocmask(int How, void *Set, void *OldSet);
 
 } // namespace __esan
 

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=274672&r1=274671&r2=274672&view=diff
==============================================================================
--- compiler-rt/trunk/lib/esan/esan_interceptors.cpp (original)
+++ compiler-rt/trunk/lib/esan/esan_interceptors.cpp Wed Jul  6 16:04:48 2016
@@ -42,6 +42,9 @@ using namespace __esan; // NOLINT
 // intercept malloc soon ourselves and can then remove this undef.
 #undef SANITIZER_INTERCEPT_REALPATH
 
+// We provide our own version:
+#undef SANITIZER_INTERCEPT_SIGPROCMASK
+
 #define COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED (!EsanIsInitialized)
 
 #define COMMON_INTERCEPT_FUNCTION(name) INTERCEPT_FUNCTION(name)
@@ -420,6 +423,40 @@ int real_sigaction(int signum, const voi
 #define ESAN_MAYBE_INTERCEPT_SIGACTION
 #endif
 
+#if SANITIZER_LINUX
+INTERCEPTOR(int, sigprocmask, int how, __sanitizer_sigset_t *set,
+            __sanitizer_sigset_t *oldset) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, sigprocmask, how, set, oldset);
+  int res = 0;
+  if (processSigprocmask(how, set, oldset))
+    res = REAL(sigprocmask)(how, set, oldset);
+  if (!res && oldset)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, oldset, sizeof(*oldset));
+  return res;
+}
+#define ESAN_MAYBE_INTERCEPT_SIGPROCMASK INTERCEPT_FUNCTION(sigprocmask)
+#else
+#define ESAN_MAYBE_INTERCEPT_SIGPROCMASK
+#endif
+
+#if !SANITIZER_WINDOWS
+INTERCEPTOR(int, pthread_sigmask, int how, __sanitizer_sigset_t *set,
+            __sanitizer_sigset_t *oldset) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, pthread_sigmask, how, set, oldset);
+  int res = 0;
+  if (processSigprocmask(how, set, oldset))
+    res = REAL(sigprocmask)(how, set, oldset);
+  if (!res && oldset)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, oldset, sizeof(*oldset));
+  return res;
+}
+#define ESAN_MAYBE_INTERCEPT_PTHREAD_SIGMASK INTERCEPT_FUNCTION(pthread_sigmask)
+#else
+#define ESAN_MAYBE_INTERCEPT_PTHREAD_SIGMASK
+#endif
+
 //===----------------------------------------------------------------------===//
 // Malloc interceptors
 //===----------------------------------------------------------------------===//
@@ -493,6 +530,8 @@ void initializeInterceptors() {
 
   ESAN_MAYBE_INTERCEPT_SIGNAL;
   ESAN_MAYBE_INTERCEPT_SIGACTION;
+  ESAN_MAYBE_INTERCEPT_SIGPROCMASK;
+  ESAN_MAYBE_INTERCEPT_PTHREAD_SIGMASK;
 
   INTERCEPT_FUNCTION(calloc);
   INTERCEPT_FUNCTION(free);

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=274672&r1=274671&r2=274672&view=diff
==============================================================================
--- compiler-rt/trunk/lib/esan/working_set.h (original)
+++ compiler-rt/trunk/lib/esan/working_set.h Wed Jul  6 16:04:48 2016
@@ -31,6 +31,7 @@ void registerMemoryFaultHandler();
 bool processWorkingSetSignal(int SigNum, void (*Handler)(int),
                              void (**Result)(int));
 bool processWorkingSetSigaction(int SigNum, const void *Act, void *OldAct);
+bool processWorkingSetSigprocmask(int How, void *Set, void *OldSet);
 
 } // namespace __esan
 

Modified: compiler-rt/trunk/lib/esan/working_set_posix.cpp
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/esan/working_set_posix.cpp?rev=274672&r1=274671&r2=274672&view=diff
==============================================================================
--- compiler-rt/trunk/lib/esan/working_set_posix.cpp (original)
+++ compiler-rt/trunk/lib/esan/working_set_posix.cpp Wed Jul  6 16:04:48 2016
@@ -55,6 +55,21 @@ bool processWorkingSetSigaction(int SigN
   return true;
 }
 
+bool processWorkingSetSigprocmask(int How, void *Set, void *OldSet) {
+  VPrintf(2, "%s\n", __FUNCTION__);
+  // All we need to do is ensure that SIGSEGV is not blocked.
+  // FIXME: we are not fully transparent as we do not pretend that
+  // SIGSEGV is still blocked on app queries: that would require
+  // per-thread mask tracking.
+  if (Set && (How == SIG_BLOCK || How == SIG_SETMASK)) {
+    if (internal_sigismember((__sanitizer_sigset_t *)Set, SIGSEGV)) {
+      VPrintf(1, "%s: removing SIGSEGV from the blocked set\n", __FUNCTION__);
+      internal_sigdelset((__sanitizer_sigset_t *)Set, SIGSEGV);
+    }
+  }
+  return true;
+}
+
 static void reinstateDefaultHandler(int SigNum) {
   __sanitizer_sigaction SigAct;
   internal_memset(&SigAct, 0, sizeof(SigAct));
@@ -95,8 +110,14 @@ void registerMemoryFaultHandler() {
   // FIXME: This could result in problems with emulating the app's signal
   // handling if the app relies on an alternate stack for SIGSEGV.
 
-  // We assume SIGSEGV is not blocked and won't be blocked by the app, so
-  // we leave the mask alone.
+  // We require that SIGSEGV is not blocked.  We use a sigprocmask
+  // interceptor to ensure that in the future.  Here we ensure it for
+  // the current thread.  We assume there are no other threads at this
+  // point during initialization, or that at least they do not block
+  // SIGSEGV.
+  __sanitizer_sigset_t SigSet;
+  internal_sigemptyset(&SigSet);
+  internal_sigprocmask(SIG_BLOCK, &SigSet, nullptr);
 
   __sanitizer_sigaction SigAct;
   internal_memset(&SigAct, 0, sizeof(SigAct));

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=274672&r1=274671&r2=274672&view=diff
==============================================================================
--- compiler-rt/trunk/lib/sanitizer_common/sanitizer_linux.cc (original)
+++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_linux.cc Wed Jul  6 16:04:48 2016
@@ -705,6 +705,10 @@ void internal_sigfillset(__sanitizer_sig
   internal_memset(set, 0xff, sizeof(*set));
 }
 
+void internal_sigemptyset(__sanitizer_sigset_t *set) {
+  internal_memset(set, 0, sizeof(*set));
+}
+
 #if SANITIZER_LINUX
 void internal_sigdelset(__sanitizer_sigset_t *set, int signum) {
   signum -= 1;
@@ -715,6 +719,16 @@ void internal_sigdelset(__sanitizer_sigs
   const uptr bit = signum % (sizeof(k_set->sig[0]) * 8);
   k_set->sig[idx] &= ~(1 << bit);
 }
+
+bool internal_sigismember(__sanitizer_sigset_t *set, int signum) {
+  signum -= 1;
+  CHECK_GE(signum, 0);
+  CHECK_LT(signum, sizeof(*set) * 8);
+  __sanitizer_kernel_sigset_t *k_set = (__sanitizer_kernel_sigset_t *)set;
+  const uptr idx = signum / (sizeof(k_set->sig[0]) * 8);
+  const uptr bit = signum % (sizeof(k_set->sig[0]) * 8);
+  return k_set->sig[idx] & (1 << bit);
+}
 #endif  // SANITIZER_LINUX
 
 // ThreadLister implementation.

Modified: compiler-rt/trunk/lib/sanitizer_common/sanitizer_posix.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/sanitizer_posix.h?rev=274672&r1=274671&r2=274672&view=diff
==============================================================================
--- compiler-rt/trunk/lib/sanitizer_common/sanitizer_posix.h (original)
+++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_posix.h Wed Jul  6 16:04:48 2016
@@ -82,6 +82,8 @@ int my_pthread_attr_getstack(void *attr,
 // order for internal_sigaction() to bypass interceptors.
 int internal_sigaction(int signum, const void *act, void *oldact);
 void internal_sigfillset(__sanitizer_sigset_t *set);
+void internal_sigemptyset(__sanitizer_sigset_t *set);
+bool internal_sigismember(__sanitizer_sigset_t *set, int signum);
 
 uptr internal_execve(const char *filename, char *const argv[],
                      char *const envp[]);

Modified: compiler-rt/trunk/test/esan/TestCases/workingset-signal-posix.cpp
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/esan/TestCases/workingset-signal-posix.cpp?rev=274672&r1=274671&r2=274672&view=diff
==============================================================================
--- compiler-rt/trunk/test/esan/TestCases/workingset-signal-posix.cpp (original)
+++ compiler-rt/trunk/test/esan/TestCases/workingset-signal-posix.cpp Wed Jul  6 16:04:48 2016
@@ -1,11 +1,12 @@
 // RUN: %clang_esan_wset -O0 %s -o %t 2>&1
 // RUN: %run %t 2>&1 | FileCheck %s
 
+#include <assert.h>
+#include <setjmp.h>
+#include <signal.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <signal.h>
-#include <setjmp.h>
-#include <assert.h>
+#include <sys/mman.h>
 
 sigjmp_buf mark;
 
@@ -51,10 +52,24 @@ int main(int argc, char **argv) {
   assert(Res == 0);
   assert(SigAct.sa_sigaction == SigactionHandler);
 
+  // Test blocking SIGSEGV and raising a shadow fault.
+  sigset_t Set;
+  sigemptyset(&Set);
+  sigaddset(&Set, SIGSEGV);
+  Res = sigprocmask(SIG_BLOCK, &Set, NULL);
+  // Make a large enough mapping that its start point will be before any
+  // prior library-region shadow access.
+  char *buf = (char *)mmap(0, 640*1024, PROT_READ | PROT_WRITE,
+                           MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+  buf[0] = 4;
+  munmap(buf, 640*1024);
+  fprintf(stderr, "Past blocked-SIGSEGV shadow fault\n");
+
   return 0;
 }
 // CHECK:      Handling SIGSEGV for signal
 // CHECK-NEXT: Past longjmp for signal
 // CHECK-NEXT: Handling SIGSEGV for sigaction
 // CHECK-NEXT: Past longjmp for sigaction
-// CHECK:      {{.*}} EfficiencySanitizer: the total working set size: {{[0-9][0-9][0-9]}} Bytes ({{[0-9][0-9]}} cache lines)
+// CHECK-NEXT: Past blocked-SIGSEGV shadow fault
+// CHECK:      {{.*}} EfficiencySanitizer: the total working set size: {{[0-9]+}} Bytes ({{[0-9][0-9]}} cache lines)




More information about the llvm-commits mailing list