Skip to content

Commit 531acf9

Browse files
authored
Reapply "[sanitizer_common] AND signals in BlockSignals instead of deleting (llvm#113443)" for non-Android Linux only (llvm#115790)
The original patch (25fd366) was reverted in 083a5cd because it broke some buildbots. This revised patch makes two changes: - Reverts to *pre-llvm#98200* behavior for Android. This avoids a build breakage on Android. - Only define KeepUnblocked if SANITIZER_LINUX: this avoids a build breakage on solaris, which does not support internal_sigdelset. N.B. Other buildbot failures were non-sanitizer tests and are therefore unrelated. Original commit message: My earlier patch llvm#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. It also adds tests. Fixes llvm#113385
1 parent 02018cf commit 531acf9

File tree

3 files changed

+116
-16
lines changed

3 files changed

+116
-16
lines changed

Diff for: compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp

+39-16
Original file line numberDiff line numberDiff line change
@@ -164,33 +164,56 @@ void SetSigProcMask(__sanitizer_sigset_t *set, __sanitizer_sigset_t *oldset) {
164164
CHECK_EQ(0, internal_sigprocmask(SIG_SETMASK, set, oldset));
165165
}
166166

167+
# if SANITIZER_LINUX
168+
// Deletes the specified signal from newset, if it is not present in oldset
169+
// Equivalently: newset[signum] = newset[signum] & oldset[signum]
170+
static void KeepUnblocked(__sanitizer_sigset_t &newset,
171+
__sanitizer_sigset_t &oldset, int signum) {
172+
// FIXME: https://github.com/google/sanitizers/issues/1816
173+
if (SANITIZER_ANDROID || !internal_sigismember(&oldset, signum))
174+
internal_sigdelset(&newset, signum);
175+
}
176+
# endif
177+
167178
// Block asynchronous signals
168179
void BlockSignals(__sanitizer_sigset_t *oldset) {
169-
__sanitizer_sigset_t set;
170-
internal_sigfillset(&set);
171-
# if SANITIZER_LINUX && !SANITIZER_ANDROID
180+
__sanitizer_sigset_t newset;
181+
internal_sigfillset(&newset);
182+
183+
# if SANITIZER_LINUX
184+
__sanitizer_sigset_t currentset;
185+
186+
# if !SANITIZER_ANDROID
187+
// FIXME: https://github.com/google/sanitizers/issues/1816
188+
SetSigProcMask(NULL, &currentset);
189+
172190
// Glibc uses SIGSETXID signal during setuid call. If this signal is blocked
173191
// on any thread, setuid call hangs.
174192
// See test/sanitizer_common/TestCases/Linux/setuid.c.
175-
internal_sigdelset(&set, 33);
176-
# endif
177-
# if SANITIZER_LINUX
193+
KeepUnblocked(newset, currentset, 33);
194+
# endif // !SANITIZER_ANDROID
195+
178196
// Seccomp-BPF-sandboxed processes rely on SIGSYS to handle trapped syscalls.
179197
// If this signal is blocked, such calls cannot be handled and the process may
180198
// hang.
181-
internal_sigdelset(&set, 31);
199+
KeepUnblocked(newset, currentset, 31);
182200

201+
# if !SANITIZER_ANDROID
183202
// Don't block synchronous signals
184-
internal_sigdelset(&set, SIGSEGV);
185-
internal_sigdelset(&set, SIGBUS);
186-
internal_sigdelset(&set, SIGILL);
187-
internal_sigdelset(&set, SIGTRAP);
188-
internal_sigdelset(&set, SIGABRT);
189-
internal_sigdelset(&set, SIGFPE);
190-
internal_sigdelset(&set, SIGPIPE);
191-
# endif
203+
// but also don't unblock signals that the user had deliberately blocked.
204+
// FIXME: https://github.com/google/sanitizers/issues/1816
205+
KeepUnblocked(newset, currentset, SIGSEGV);
206+
KeepUnblocked(newset, currentset, SIGBUS);
207+
KeepUnblocked(newset, currentset, SIGILL);
208+
KeepUnblocked(newset, currentset, SIGTRAP);
209+
KeepUnblocked(newset, currentset, SIGABRT);
210+
KeepUnblocked(newset, currentset, SIGFPE);
211+
KeepUnblocked(newset, currentset, SIGPIPE);
212+
# endif //! SANITIZER_ANDROID
213+
214+
# endif // SANITIZER_LINUX
192215

193-
SetSigProcMask(&set, oldset);
216+
SetSigProcMask(&newset, oldset);
194217
}
195218

196219
ScopedBlockSignals::ScopedBlockSignals(__sanitizer_sigset_t *copy) {

Diff for: compiler-rt/lib/sanitizer_common/tests/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ set(SANITIZER_UNITTESTS
1515
sanitizer_array_ref_test.cpp
1616
sanitizer_atomic_test.cpp
1717
sanitizer_bitvector_test.cpp
18+
sanitizer_block_signals.cpp
1819
sanitizer_bvgraph_test.cpp
1920
sanitizer_chained_origin_depot_test.cpp
2021
sanitizer_common_test.cpp
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
//===-- sanitizer_block_signals.cpp ---------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// This file is a part of sanitizer_common unit tests.
10+
//
11+
//===----------------------------------------------------------------------===//
12+
#include <signal.h>
13+
#include <stdio.h>
14+
15+
#include "gtest/gtest.h"
16+
#include "sanitizer_common/sanitizer_linux.h"
17+
18+
namespace __sanitizer {
19+
20+
#if SANITIZER_LINUX && !SANITIZER_ANDROID
21+
volatile int received_sig = -1;
22+
23+
void signal_handler(int signum) { received_sig = signum; }
24+
25+
TEST(SanitizerCommon, NoBlockSignals) {
26+
// No signals blocked
27+
signal(SIGUSR1, signal_handler);
28+
raise(SIGUSR1);
29+
EXPECT_EQ(received_sig, SIGUSR1);
30+
31+
received_sig = -1;
32+
signal(SIGPIPE, signal_handler);
33+
raise(SIGPIPE);
34+
EXPECT_EQ(received_sig, SIGPIPE);
35+
}
36+
37+
TEST(SanitizerCommon, BlockSignalsPlain) {
38+
// ScopedBlockSignals; SIGUSR1 should be blocked but not SIGPIPE
39+
{
40+
__sanitizer_sigset_t sigset = {};
41+
ScopedBlockSignals block(&sigset);
42+
43+
received_sig = -1;
44+
signal(SIGUSR1, signal_handler);
45+
raise(SIGUSR1);
46+
EXPECT_EQ(received_sig, -1);
47+
48+
received_sig = -1;
49+
signal(SIGPIPE, signal_handler);
50+
raise(SIGPIPE);
51+
EXPECT_EQ(received_sig, SIGPIPE);
52+
}
53+
EXPECT_EQ(received_sig, SIGUSR1);
54+
}
55+
56+
TEST(SanitizerCommon, BlockSignalsExceptPipe) {
57+
// Manually block SIGPIPE; ScopedBlockSignals should not unblock this
58+
sigset_t block_sigset;
59+
sigemptyset(&block_sigset);
60+
sigaddset(&block_sigset, SIGPIPE);
61+
sigprocmask(SIG_BLOCK, &block_sigset, NULL);
62+
{
63+
__sanitizer_sigset_t sigset = {};
64+
ScopedBlockSignals block(&sigset);
65+
66+
received_sig = -1;
67+
signal(SIGPIPE, signal_handler);
68+
raise(SIGPIPE);
69+
EXPECT_EQ(received_sig, -1);
70+
}
71+
sigprocmask(SIG_UNBLOCK, &block_sigset, NULL);
72+
EXPECT_EQ(received_sig, SIGPIPE);
73+
}
74+
#endif // SANITIZER_LINUX && !SANITIZER_ANDROID
75+
76+
} // namespace __sanitizer

0 commit comments

Comments
 (0)