blob: d879f5ac8599c4b2a0cb89dcae07977df061ec4c [file] [log] [blame]
Josh Gao1eac77e2018-02-26 15:54:41 -08001/*
2 * Copyright (C) 2018 The Android Open Source Project
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in
12 * the documentation and/or other materials provided with the
13 * distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
18 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
22 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
25 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
Josh Gao3bef5272018-09-04 14:33:23 -070029#include <dlfcn.h>
30#include <pthread.h>
Josh Gao1eac77e2018-02-26 15:54:41 -080031#include <signal.h>
32#include <sys/syscall.h>
33
34#include <functional>
35
36#include <gtest/gtest.h>
37
38#include "sigchain.h"
39
40#if !defined(__BIONIC__)
Andreas Gampec55bb392018-09-21 00:02:02 +000041using sigset64_t = sigset_t;
Josh Gao1eac77e2018-02-26 15:54:41 -080042
43static int sigemptyset64(sigset64_t* set) {
44 return sigemptyset(set);
45}
46
47static int sigismember64(sigset64_t* set, int member) {
48 return sigismember(set, member);
49}
50#endif
51
52static int RealSigprocmask(int how, const sigset64_t* new_sigset, sigset64_t* old_sigset) {
53 // glibc's sigset_t is overly large, so sizeof(*new_sigset) doesn't work.
Goran Jakovljevic247ff372018-03-07 10:34:05 +010054 return syscall(__NR_rt_sigprocmask, how, new_sigset, old_sigset, NSIG/8);
Josh Gao1eac77e2018-02-26 15:54:41 -080055}
56
57class SigchainTest : public ::testing::Test {
58 void SetUp() final {
59 art::AddSpecialSignalHandlerFn(SIGSEGV, &action);
60 }
61
62 void TearDown() final {
63 art::RemoveSpecialSignalHandlerFn(SIGSEGV, action.sc_sigaction);
64 }
65
66 art::SigchainAction action = {
Josh Gao3bef5272018-09-04 14:33:23 -070067 .sc_sigaction = [](int, siginfo_t* info, void*) -> bool {
68 return info->si_value.sival_ptr;
69 },
Josh Gao1eac77e2018-02-26 15:54:41 -080070 .sc_mask = {},
71 .sc_flags = 0,
72 };
Josh Gao3bef5272018-09-04 14:33:23 -070073
74 protected:
75 void RaiseHandled() {
Colin Cross073885c2021-09-14 14:35:15 -070076 sigval value;
Josh Gao3bef5272018-09-04 14:33:23 -070077 value.sival_ptr = &value;
78 pthread_sigqueue(pthread_self(), SIGSEGV, value);
79 }
80
81 void RaiseUnhandled() {
Colin Cross073885c2021-09-14 14:35:15 -070082 sigval value;
Josh Gao3bef5272018-09-04 14:33:23 -070083 value.sival_ptr = nullptr;
84 pthread_sigqueue(pthread_self(), SIGSEGV, value);
85 }
Josh Gao1eac77e2018-02-26 15:54:41 -080086};
87
88
Andreas Gampebc802de2018-06-20 17:24:11 -070089static void TestSignalBlocking(const std::function<void()>& fn) {
Josh Gao1eac77e2018-02-26 15:54:41 -080090 // Unblock SIGSEGV, make sure it stays unblocked.
91 sigset64_t mask;
92 sigemptyset64(&mask);
93 ASSERT_EQ(0, RealSigprocmask(SIG_SETMASK, &mask, nullptr)) << strerror(errno);
94
95 fn();
96
97 if (testing::Test::HasFatalFailure()) return;
98 ASSERT_EQ(0, RealSigprocmask(SIG_SETMASK, nullptr, &mask));
99 ASSERT_FALSE(sigismember64(&mask, SIGSEGV));
100}
101
102TEST_F(SigchainTest, sigprocmask_setmask) {
103 TestSignalBlocking([]() {
104 sigset_t mask;
105 sigfillset(&mask);
106 ASSERT_EQ(0, sigprocmask(SIG_SETMASK, &mask, nullptr));
107 });
108}
109
110TEST_F(SigchainTest, sigprocmask_block) {
111 TestSignalBlocking([]() {
112 sigset_t mask;
113 sigfillset(&mask);
114 ASSERT_EQ(0, sigprocmask(SIG_BLOCK, &mask, nullptr));
115 });
116}
117
118// bionic-only wide variants for LP32.
119#if defined(__BIONIC__)
120TEST_F(SigchainTest, sigprocmask64_setmask) {
121 TestSignalBlocking([]() {
122 sigset64_t mask;
123 sigfillset64(&mask);
124 ASSERT_EQ(0, sigprocmask64(SIG_SETMASK, &mask, nullptr));
125 });
126}
127
128TEST_F(SigchainTest, sigprocmask64_block) {
129 TestSignalBlocking([]() {
130 sigset64_t mask;
131 sigfillset64(&mask);
132 ASSERT_EQ(0, sigprocmask64(SIG_BLOCK, &mask, nullptr));
133 });
134}
135
136TEST_F(SigchainTest, pthread_sigmask64_setmask) {
137 TestSignalBlocking([]() {
138 sigset64_t mask;
139 sigfillset64(&mask);
140 ASSERT_EQ(0, pthread_sigmask64(SIG_SETMASK, &mask, nullptr));
141 });
142}
143
144TEST_F(SigchainTest, pthread_sigmask64_block) {
145 TestSignalBlocking([]() {
146 sigset64_t mask;
147 sigfillset64(&mask);
148 ASSERT_EQ(0, pthread_sigmask64(SIG_BLOCK, &mask, nullptr));
149 });
150}
151#endif
152
153// glibc doesn't implement most of these in terms of sigprocmask, which we rely on.
154#if defined(__BIONIC__)
155TEST_F(SigchainTest, pthread_sigmask_setmask) {
156 TestSignalBlocking([]() {
157 sigset_t mask;
158 sigfillset(&mask);
159 ASSERT_EQ(0, pthread_sigmask(SIG_SETMASK, &mask, nullptr));
160 });
161}
162
163TEST_F(SigchainTest, pthread_sigmask_block) {
164 TestSignalBlocking([]() {
165 sigset_t mask;
166 sigfillset(&mask);
167 ASSERT_EQ(0, pthread_sigmask(SIG_BLOCK, &mask, nullptr));
168 });
169}
170
171TEST_F(SigchainTest, sigset_mask) {
172 TestSignalBlocking([]() {
173 sigset(SIGSEGV, SIG_HOLD);
174 });
175}
176
177TEST_F(SigchainTest, sighold) {
178 TestSignalBlocking([]() {
179 sighold(SIGSEGV);
180 });
181}
182
183#if defined(__BIONIC__)
184// Not exposed via headers, but the symbols are available if you declare them yourself.
185extern "C" int sigblock(int);
186extern "C" int sigsetmask(int);
187#endif
188
189TEST_F(SigchainTest, sigblock) {
190 TestSignalBlocking([]() {
191 int mask = ~0U;
192 ASSERT_EQ(0, sigblock(mask));
193 });
194}
195
196TEST_F(SigchainTest, sigsetmask) {
197 TestSignalBlocking([]() {
198 int mask = ~0U;
199 ASSERT_EQ(0, sigsetmask(mask));
200 });
201}
202
203#endif
Josh Gao3bef5272018-09-04 14:33:23 -0700204
205// Make sure that we properly put ourselves back in front if we get circumvented.
206TEST_F(SigchainTest, EnsureFrontOfChain) {
207#if defined(__BIONIC__)
208 constexpr char kLibcSoName[] = "libc.so";
209#elif defined(__GNU_LIBRARY__) && __GNU_LIBRARY__ == 6
210 constexpr char kLibcSoName[] = "libc.so.6";
Colin Cross073885c2021-09-14 14:35:15 -0700211#elif defined(ANDROID_HOST_MUSL)
212 constexpr char kLibcSoName[] = "libc_musl.so";
Josh Gao3bef5272018-09-04 14:33:23 -0700213#else
214 #error Unknown libc
215#endif
216 void* libc = dlopen(kLibcSoName, RTLD_LAZY | RTLD_NOLOAD);
217 ASSERT_TRUE(libc);
218
Josh Gao25e60fc2021-03-23 14:18:01 -0700219 auto libc_sigaction = reinterpret_cast<decltype(&sigaction)>(dlsym(libc, "sigaction"));
220 ASSERT_TRUE(libc_sigaction);
221
Josh Gao3bef5272018-09-04 14:33:23 -0700222 static sig_atomic_t called = 0;
223 struct sigaction action = {};
224 action.sa_flags = SA_SIGINFO;
225 action.sa_sigaction = [](int, siginfo_t*, void*) { called = 1; };
226
Josh Gao25e60fc2021-03-23 14:18:01 -0700227 ASSERT_EQ(0, libc_sigaction(SIGSEGV, &action, nullptr));
Josh Gao3bef5272018-09-04 14:33:23 -0700228
229 // Try before EnsureFrontOfChain.
230 RaiseHandled();
Josh Gao25e60fc2021-03-23 14:18:01 -0700231 ASSERT_EQ(1, called);
232 called = 0;
Josh Gao3bef5272018-09-04 14:33:23 -0700233
234 RaiseUnhandled();
235 ASSERT_EQ(1, called);
236 called = 0;
237
238 // ...and after.
239 art::EnsureFrontOfChain(SIGSEGV);
Nicolas Geoffray4dcd2382021-03-12 15:41:30 +0000240 RaiseHandled();
Josh Gao3bef5272018-09-04 14:33:23 -0700241 ASSERT_EQ(0, called);
Josh Gao3bef5272018-09-04 14:33:23 -0700242
243 RaiseUnhandled();
244 ASSERT_EQ(1, called);
245 called = 0;
246}
Peter Collingbournecfc6e9d2020-11-13 10:54:13 -0800247
248TEST_F(SigchainTest, fault_address_tag) {
249#define SA_EXPOSE_TAGBITS 0x00000800
250#if defined(__aarch64__)
251 struct sigaction action = {};
252 action.sa_flags = SA_SIGINFO;
253 action.sa_sigaction = [](int, siginfo_t* siginfo, void*) {
254 _exit(reinterpret_cast<uintptr_t>(siginfo->si_addr) >> 56);
255 };
256 ASSERT_EQ(0, sigaction(SIGSEGV, &action, nullptr));
257
258 auto* tagged_null = reinterpret_cast<int*>(0x2bULL << 56);
259 EXPECT_EXIT({ volatile int load __attribute__((unused)) = *tagged_null; },
260 testing::ExitedWithCode(0), "");
261
262 // Our sigaction implementation always implements the "clear unknown bits"
263 // semantics for oldact.sa_flags regardless of kernel version so we rely on it
264 // here to test for kernel support for SA_EXPOSE_TAGBITS.
265 action.sa_flags = SA_SIGINFO | SA_EXPOSE_TAGBITS;
266 ASSERT_EQ(0, sigaction(SIGSEGV, &action, nullptr));
267 ASSERT_EQ(0, sigaction(SIGSEGV, nullptr, &action));
268 if (action.sa_flags & SA_EXPOSE_TAGBITS) {
269 EXPECT_EXIT({ volatile int load __attribute__((unused)) = *tagged_null; },
270 testing::ExitedWithCode(0x2b), "");
271 }
272#else
273 GTEST_SKIP() << "arm64 only";
274#endif
275}