Skip to content

Commit 10465f9

Browse files
thurstondnikic
authored andcommitted
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 (cherry picked from commit 531acf9)
1 parent c7892d0 commit 10465f9

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
@@ -160,33 +160,56 @@ void SetSigProcMask(__sanitizer_sigset_t *set, __sanitizer_sigset_t *oldset) {
160160
CHECK_EQ(0, internal_sigprocmask(SIG_SETMASK, set, oldset));
161161
}
162162

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

197+
# if !SANITIZER_ANDROID
179198
// Don't block synchronous signals
180-
internal_sigdelset(&set, SIGSEGV);
181-
internal_sigdelset(&set, SIGBUS);
182-
internal_sigdelset(&set, SIGILL);
183-
internal_sigdelset(&set, SIGTRAP);
184-
internal_sigdelset(&set, SIGABRT);
185-
internal_sigdelset(&set, SIGFPE);
186-
internal_sigdelset(&set, SIGPIPE);
187-
# endif
199+
// but also don't unblock signals that the user had deliberately blocked.
200+
// FIXME: https://github.com/google/sanitizers/issues/1816
201+
KeepUnblocked(newset, currentset, SIGSEGV);
202+
KeepUnblocked(newset, currentset, SIGBUS);
203+
KeepUnblocked(newset, currentset, SIGILL);
204+
KeepUnblocked(newset, currentset, SIGTRAP);
205+
KeepUnblocked(newset, currentset, SIGABRT);
206+
KeepUnblocked(newset, currentset, SIGFPE);
207+
KeepUnblocked(newset, currentset, SIGPIPE);
208+
# endif //! SANITIZER_ANDROID
209+
210+
# endif // SANITIZER_LINUX
188211

189-
SetSigProcMask(&set, oldset);
212+
SetSigProcMask(&newset, oldset);
190213
}
191214

192215
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)