1 /*
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
29 #include <dlfcn.h>
30 #include <pthread.h>
31 #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__)
41 using sigset64_t = sigset_t;
42
sigemptyset64(sigset64_t * set)43 static int sigemptyset64(sigset64_t* set) {
44 return sigemptyset(set);
45 }
46
sigismember64(sigset64_t * set,int member)47 static int sigismember64(sigset64_t* set, int member) {
48 return sigismember(set, member);
49 }
50 #endif
51
RealSigprocmask(int how,const sigset64_t * new_sigset,sigset64_t * old_sigset)52 static 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.
54 return syscall(__NR_rt_sigprocmask, how, new_sigset, old_sigset, NSIG/8);
55 }
56
57 class SigchainTest : public ::testing::Test {
SetUp()58 void SetUp() final {
59 art::AddSpecialSignalHandlerFn(SIGSEGV, &action);
60 }
61
TearDown()62 void TearDown() final {
63 art::RemoveSpecialSignalHandlerFn(SIGSEGV, action.sc_sigaction);
64 }
65
66 art::SigchainAction action = {
__anonbddd807a0102() 67 .sc_sigaction = [](int, siginfo_t* info, void*) -> bool {
68 return info->si_value.sival_ptr;
69 },
__anonbddd807a0202() 70 .sc_mask = {},
71 .sc_flags = 0,
72 };
73
74 protected:
RaiseHandled()75 void RaiseHandled() {
76 sigval_t value;
77 value.sival_ptr = &value;
78 pthread_sigqueue(pthread_self(), SIGSEGV, value);
79 }
80
RaiseUnhandled()81 void RaiseUnhandled() {
82 sigval_t value;
83 value.sival_ptr = nullptr;
84 pthread_sigqueue(pthread_self(), SIGSEGV, value);
85 }
86 };
87
88
TestSignalBlocking(const std::function<void ()> & fn)89 static void TestSignalBlocking(const std::function<void()>& fn) {
90 // 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
TEST_F(SigchainTest,sigprocmask_setmask)102 TEST_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
TEST_F(SigchainTest,sigprocmask_block)110 TEST_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__)
TEST_F(SigchainTest,sigprocmask64_setmask)120 TEST_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
TEST_F(SigchainTest,sigprocmask64_block)128 TEST_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
TEST_F(SigchainTest,pthread_sigmask64_setmask)136 TEST_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
TEST_F(SigchainTest,pthread_sigmask64_block)144 TEST_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__)
TEST_F(SigchainTest,pthread_sigmask_setmask)155 TEST_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
TEST_F(SigchainTest,pthread_sigmask_block)163 TEST_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
TEST_F(SigchainTest,sigset_mask)171 TEST_F(SigchainTest, sigset_mask) {
172 TestSignalBlocking([]() {
173 sigset(SIGSEGV, SIG_HOLD);
174 });
175 }
176
TEST_F(SigchainTest,sighold)177 TEST_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.
185 extern "C" int sigblock(int);
186 extern "C" int sigsetmask(int);
187 #endif
188
TEST_F(SigchainTest,sigblock)189 TEST_F(SigchainTest, sigblock) {
190 TestSignalBlocking([]() {
191 int mask = ~0U;
192 ASSERT_EQ(0, sigblock(mask));
193 });
194 }
195
TEST_F(SigchainTest,sigsetmask)196 TEST_F(SigchainTest, sigsetmask) {
197 TestSignalBlocking([]() {
198 int mask = ~0U;
199 ASSERT_EQ(0, sigsetmask(mask));
200 });
201 }
202
203 #endif
204
205 // Make sure that we properly put ourselves back in front if we get circumvented.
TEST_F(SigchainTest,EnsureFrontOfChain)206 TEST_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";
211 #else
212 #error Unknown libc
213 #endif
214 void* libc = dlopen(kLibcSoName, RTLD_LAZY | RTLD_NOLOAD);
215 ASSERT_TRUE(libc);
216
217 auto libc_sigaction = reinterpret_cast<decltype(&sigaction)>(dlsym(libc, "sigaction"));
218 ASSERT_TRUE(libc_sigaction);
219
220 static sig_atomic_t called = 0;
221 struct sigaction action = {};
222 action.sa_flags = SA_SIGINFO;
223 action.sa_sigaction = [](int, siginfo_t*, void*) { called = 1; };
224
225 ASSERT_EQ(0, libc_sigaction(SIGSEGV, &action, nullptr));
226
227 // Try before EnsureFrontOfChain.
228 RaiseHandled();
229 ASSERT_EQ(1, called);
230 called = 0;
231
232 RaiseUnhandled();
233 ASSERT_EQ(1, called);
234 called = 0;
235
236 // ...and after.
237 art::EnsureFrontOfChain(SIGSEGV);
238 RaiseHandled();
239 ASSERT_EQ(0, called);
240
241 RaiseUnhandled();
242 ASSERT_EQ(1, called);
243 called = 0;
244 }
245
TEST_F(SigchainTest,fault_address_tag)246 TEST_F(SigchainTest, fault_address_tag) {
247 #define SA_EXPOSE_TAGBITS 0x00000800
248 #if defined(__aarch64__)
249 struct sigaction action = {};
250 action.sa_flags = SA_SIGINFO;
251 action.sa_sigaction = [](int, siginfo_t* siginfo, void*) {
252 _exit(reinterpret_cast<uintptr_t>(siginfo->si_addr) >> 56);
253 };
254 ASSERT_EQ(0, sigaction(SIGSEGV, &action, nullptr));
255
256 auto* tagged_null = reinterpret_cast<int*>(0x2bULL << 56);
257 EXPECT_EXIT({ volatile int load __attribute__((unused)) = *tagged_null; },
258 testing::ExitedWithCode(0), "");
259
260 // Our sigaction implementation always implements the "clear unknown bits"
261 // semantics for oldact.sa_flags regardless of kernel version so we rely on it
262 // here to test for kernel support for SA_EXPOSE_TAGBITS.
263 action.sa_flags = SA_SIGINFO | SA_EXPOSE_TAGBITS;
264 ASSERT_EQ(0, sigaction(SIGSEGV, &action, nullptr));
265 ASSERT_EQ(0, sigaction(SIGSEGV, nullptr, &action));
266 if (action.sa_flags & SA_EXPOSE_TAGBITS) {
267 EXPECT_EXIT({ volatile int load __attribute__((unused)) = *tagged_null; },
268 testing::ExitedWithCode(0x2b), "");
269 }
270 #else
271 GTEST_SKIP() << "arm64 only";
272 #endif
273 }
274