[compiler-rt] [sanitizer_common] AND signals in BlockSignals instead of deleting (PR #113443)

Vitaly Buka via llvm-commits llvm-commits at lists.llvm.org
Fri Oct 25 13:14:00 PDT 2024


https://github.com/vitalybuka updated https://github.com/llvm/llvm-project/pull/113443

>From 0672505f025c23c22f1aea75c69b557216d2c9a2 Mon Sep 17 00:00:00 2001
From: Thurston Dang <thurston at google.com>
Date: Wed, 23 Oct 2024 11:04:27 +0000
Subject: [PATCH 1/2] [sanitizer_common] AND signals in BlockSignals instead of
 deleting

My earlier patch https://github.com/llvm/llvm-project/pull/98200 caused a regression because it unconditionally unblocked synchronous signals, even if the user program had deliberately blocked them. This patch fixes the issue by checking the current signal mask, as suggested by Vitaly.

Fixes #113385
---
 .../lib/sanitizer_common/sanitizer_linux.cpp  | 36 ++++++++++++-------
 1 file changed, 24 insertions(+), 12 deletions(-)

diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp
index 33107eb0b42993..1f74abfb39b31e 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp
@@ -164,33 +164,45 @@ void SetSigProcMask(__sanitizer_sigset_t *set, __sanitizer_sigset_t *oldset) {
   CHECK_EQ(0, internal_sigprocmask(SIG_SETMASK, set, oldset));
 }
 
+// Deletes the specified signal from newset, if it is not present in oldset
+// Equivalently: newset[signum] = newset[signum] & oldset[signum]
+void internal_sigandset_individual(__sanitizer_sigset_t *newset,
+                                   __sanitizer_sigset_t *oldset, int signum) {
+  if (!internal_sigismember(oldset, signum))
+    internal_sigdelset(newset, signum);
+}
+
 // Block asynchronous signals
 void BlockSignals(__sanitizer_sigset_t *oldset) {
-  __sanitizer_sigset_t set;
-  internal_sigfillset(&set);
+  __sanitizer_sigset_t currentset;
+  SetSigProcMask(NULL, &currentset);
+
+  __sanitizer_sigset_t newset;
+  internal_sigfillset(&newset);
 #  if SANITIZER_LINUX && !SANITIZER_ANDROID
   // Glibc uses SIGSETXID signal during setuid call. If this signal is blocked
   // on any thread, setuid call hangs.
   // See test/sanitizer_common/TestCases/Linux/setuid.c.
-  internal_sigdelset(&set, 33);
+  internal_sigdelset(&newset, 33);
 #  endif
 #  if SANITIZER_LINUX
   // Seccomp-BPF-sandboxed processes rely on SIGSYS to handle trapped syscalls.
   // If this signal is blocked, such calls cannot be handled and the process may
   // hang.
-  internal_sigdelset(&set, 31);
+  internal_sigdelset(&newset, 31);
 
   // Don't block synchronous signals
-  internal_sigdelset(&set, SIGSEGV);
-  internal_sigdelset(&set, SIGBUS);
-  internal_sigdelset(&set, SIGILL);
-  internal_sigdelset(&set, SIGTRAP);
-  internal_sigdelset(&set, SIGABRT);
-  internal_sigdelset(&set, SIGFPE);
-  internal_sigdelset(&set, SIGPIPE);
+  // but also don't unblock signals that the user had deliberately blocked.
+  internal_sigandset_individual(&newset, &currentset, SIGSEGV);
+  internal_sigandset_individual(&newset, &currentset, SIGBUS);
+  internal_sigandset_individual(&newset, &currentset, SIGILL);
+  internal_sigandset_individual(&newset, &currentset, SIGTRAP);
+  internal_sigandset_individual(&newset, &currentset, SIGABRT);
+  internal_sigandset_individual(&newset, &currentset, SIGFPE);
+  internal_sigandset_individual(&newset, &currentset, SIGPIPE);
 #  endif
 
-  SetSigProcMask(&set, oldset);
+  SetSigProcMask(&newset, oldset);
 }
 
 ScopedBlockSignals::ScopedBlockSignals(__sanitizer_sigset_t *copy) {

>From d510d43f8b8c416c6ed851d930ce83c121252457 Mon Sep 17 00:00:00 2001
From: Vitaly Buka <vitalybuka at gmail.com>
Date: Fri, 25 Oct 2024 13:13:52 -0700
Subject: [PATCH 2/2] Rename and use for all signals

---
 .../lib/sanitizer_common/sanitizer_linux.cpp  | 22 +++++++++----------
 1 file changed, 11 insertions(+), 11 deletions(-)

diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp
index 1f74abfb39b31e..111591d6f63c60 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp
@@ -166,8 +166,8 @@ void SetSigProcMask(__sanitizer_sigset_t *set, __sanitizer_sigset_t *oldset) {
 
 // Deletes the specified signal from newset, if it is not present in oldset
 // Equivalently: newset[signum] = newset[signum] & oldset[signum]
-void internal_sigandset_individual(__sanitizer_sigset_t *newset,
-                                   __sanitizer_sigset_t *oldset, int signum) {
+static void KeepUnblocked(__sanitizer_sigset_t &newset,
+                          __sanitizer_sigset_t &oldset, int signum) {
   if (!internal_sigismember(oldset, signum))
     internal_sigdelset(newset, signum);
 }
@@ -183,23 +183,23 @@ void BlockSignals(__sanitizer_sigset_t *oldset) {
   // Glibc uses SIGSETXID signal during setuid call. If this signal is blocked
   // on any thread, setuid call hangs.
   // See test/sanitizer_common/TestCases/Linux/setuid.c.
-  internal_sigdelset(&newset, 33);
+  KeepUnblocked(&newset, &currentset, 33);
 #  endif
 #  if SANITIZER_LINUX
   // Seccomp-BPF-sandboxed processes rely on SIGSYS to handle trapped syscalls.
   // If this signal is blocked, such calls cannot be handled and the process may
   // hang.
-  internal_sigdelset(&newset, 31);
+  KeepUnblocked(&newset, &currentset, 31);
 
   // Don't block synchronous signals
   // but also don't unblock signals that the user had deliberately blocked.
-  internal_sigandset_individual(&newset, &currentset, SIGSEGV);
-  internal_sigandset_individual(&newset, &currentset, SIGBUS);
-  internal_sigandset_individual(&newset, &currentset, SIGILL);
-  internal_sigandset_individual(&newset, &currentset, SIGTRAP);
-  internal_sigandset_individual(&newset, &currentset, SIGABRT);
-  internal_sigandset_individual(&newset, &currentset, SIGFPE);
-  internal_sigandset_individual(&newset, &currentset, SIGPIPE);
+  KeepUnblocked(&newset, &currentset, SIGSEGV);
+  KeepUnblocked(&newset, &currentset, SIGBUS);
+  KeepUnblocked(&newset, &currentset, SIGILL);
+  KeepUnblocked(&newset, &currentset, SIGTRAP);
+  KeepUnblocked(&newset, &currentset, SIGABRT);
+  KeepUnblocked(&newset, &currentset, SIGFPE);
+  KeepUnblocked(&newset, &currentset, SIGPIPE);
 #  endif
 
   SetSigProcMask(&newset, oldset);



More information about the llvm-commits mailing list