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(__clang__) && __has_feature(hwaddress_sanitizer)
41 #define DISABLE_HWASAN __attribute__((no_sanitize("hwaddress")))
42 #else
43 #define DISABLE_HWASAN
44 #endif
45
46 #if !defined(__BIONIC__)
47 using sigset64_t = sigset_t;
48
sigemptyset64(sigset64_t * set)49 static int sigemptyset64(sigset64_t* set) {
50 return sigemptyset(set);
51 }
52
sigismember64(sigset64_t * set,int member)53 static int sigismember64(sigset64_t* set, int member) {
54 return sigismember(set, member);
55 }
56 #endif
57
RealSigprocmask(int how,const sigset64_t * new_sigset,sigset64_t * old_sigset)58 static int RealSigprocmask(int how, const sigset64_t* new_sigset, sigset64_t* old_sigset) {
59 // glibc's sigset_t is overly large, so sizeof(*new_sigset) doesn't work.
60 return syscall(__NR_rt_sigprocmask, how, new_sigset, old_sigset, NSIG/8);
61 }
62
63 class SigchainTest : public ::testing::Test {
SetUp()64 void SetUp() final {
65 art::AddSpecialSignalHandlerFn(SIGSEGV, &action);
66 }
67
TearDown()68 void TearDown() final {
69 art::RemoveSpecialSignalHandlerFn(SIGSEGV, action.sc_sigaction);
70 }
71
72 art::SigchainAction action = {
__anonb177a6ff0102() 73 .sc_sigaction = [](int, siginfo_t* info, void*) -> bool {
74 return info->si_value.sival_ptr;
75 },
__anonb177a6ff0202() 76 .sc_mask = {},
77 .sc_flags = 0,
78 };
79
80 protected:
RaiseHandled()81 void RaiseHandled() {
82 sigval value;
83 value.sival_ptr = &value;
84 // pthread_sigqueue would guarantee the signal is delivered to this
85 // thread, but it is a nonstandard extension and does not exist in
86 // musl. Gtest is single threaded, and these tests don't create any
87 // threads, so sigqueue can be used and will deliver to this thread.
88 sigqueue(getpid(), SIGSEGV, value);
89 }
90
RaiseUnhandled()91 void RaiseUnhandled() {
92 sigval value;
93 value.sival_ptr = nullptr;
94 sigqueue(getpid(), SIGSEGV, value);
95 }
96 };
97
98
TestSignalBlocking(const std::function<void ()> & fn)99 static void TestSignalBlocking(const std::function<void()>& fn) {
100 // Unblock SIGSEGV, make sure it stays unblocked.
101 sigset64_t mask;
102 sigemptyset64(&mask);
103 ASSERT_EQ(0, RealSigprocmask(SIG_SETMASK, &mask, nullptr)) << strerror(errno);
104
105 fn();
106
107 if (testing::Test::HasFatalFailure()) return;
108 ASSERT_EQ(0, RealSigprocmask(SIG_SETMASK, nullptr, &mask));
109 ASSERT_FALSE(sigismember64(&mask, SIGSEGV));
110 }
111
TEST_F(SigchainTest,sigprocmask_setmask)112 TEST_F(SigchainTest, sigprocmask_setmask) {
113 TestSignalBlocking([]() {
114 sigset_t mask;
115 sigfillset(&mask);
116 ASSERT_EQ(0, sigprocmask(SIG_SETMASK, &mask, nullptr));
117 });
118 }
119
TEST_F(SigchainTest,sigprocmask_block)120 TEST_F(SigchainTest, sigprocmask_block) {
121 TestSignalBlocking([]() {
122 sigset_t mask;
123 sigfillset(&mask);
124 ASSERT_EQ(0, sigprocmask(SIG_BLOCK, &mask, nullptr));
125 });
126 }
127
128 // bionic-only wide variants for LP32.
129 #if defined(__BIONIC__)
TEST_F(SigchainTest,sigprocmask64_setmask)130 TEST_F(SigchainTest, sigprocmask64_setmask) {
131 TestSignalBlocking([]() {
132 sigset64_t mask;
133 sigfillset64(&mask);
134 ASSERT_EQ(0, sigprocmask64(SIG_SETMASK, &mask, nullptr));
135 });
136 }
137
TEST_F(SigchainTest,sigprocmask64_block)138 TEST_F(SigchainTest, sigprocmask64_block) {
139 TestSignalBlocking([]() {
140 sigset64_t mask;
141 sigfillset64(&mask);
142 ASSERT_EQ(0, sigprocmask64(SIG_BLOCK, &mask, nullptr));
143 });
144 }
145
TEST_F(SigchainTest,pthread_sigmask64_setmask)146 TEST_F(SigchainTest, pthread_sigmask64_setmask) {
147 TestSignalBlocking([]() {
148 sigset64_t mask;
149 sigfillset64(&mask);
150 ASSERT_EQ(0, pthread_sigmask64(SIG_SETMASK, &mask, nullptr));
151 });
152 }
153
TEST_F(SigchainTest,pthread_sigmask64_block)154 TEST_F(SigchainTest, pthread_sigmask64_block) {
155 TestSignalBlocking([]() {
156 sigset64_t mask;
157 sigfillset64(&mask);
158 ASSERT_EQ(0, pthread_sigmask64(SIG_BLOCK, &mask, nullptr));
159 });
160 }
161 #endif
162
163 // glibc doesn't implement most of these in terms of sigprocmask, which we rely on.
164 #if defined(__BIONIC__)
TEST_F(SigchainTest,pthread_sigmask_setmask)165 TEST_F(SigchainTest, pthread_sigmask_setmask) {
166 TestSignalBlocking([]() {
167 sigset_t mask;
168 sigfillset(&mask);
169 ASSERT_EQ(0, pthread_sigmask(SIG_SETMASK, &mask, nullptr));
170 });
171 }
172
TEST_F(SigchainTest,pthread_sigmask_block)173 TEST_F(SigchainTest, pthread_sigmask_block) {
174 TestSignalBlocking([]() {
175 sigset_t mask;
176 sigfillset(&mask);
177 ASSERT_EQ(0, pthread_sigmask(SIG_BLOCK, &mask, nullptr));
178 });
179 }
180
TEST_F(SigchainTest,sigset_mask)181 TEST_F(SigchainTest, sigset_mask) {
182 TestSignalBlocking([]() {
183 sigset(SIGSEGV, SIG_HOLD);
184 });
185 }
186
TEST_F(SigchainTest,sighold)187 TEST_F(SigchainTest, sighold) {
188 TestSignalBlocking([]() {
189 sighold(SIGSEGV);
190 });
191 }
192
193 #if defined(__BIONIC__)
194 // Not exposed via headers, but the symbols are available if you declare them yourself.
195 extern "C" int sigblock(int);
196 extern "C" int sigsetmask(int);
197 #endif
198
TEST_F(SigchainTest,sigblock)199 TEST_F(SigchainTest, sigblock) {
200 TestSignalBlocking([]() {
201 int mask = ~0U;
202 ASSERT_EQ(0, sigblock(mask));
203 });
204 }
205
TEST_F(SigchainTest,sigsetmask)206 TEST_F(SigchainTest, sigsetmask) {
207 TestSignalBlocking([]() {
208 int mask = ~0U;
209 ASSERT_EQ(0, sigsetmask(mask));
210 });
211 }
212
213 #endif
214
215 // Make sure that we properly put ourselves back in front if we get circumvented.
TEST_F(SigchainTest,EnsureFrontOfChain)216 TEST_F(SigchainTest, EnsureFrontOfChain) {
217 #if defined(__BIONIC__)
218 constexpr char kLibcSoName[] = "libc.so";
219 #elif defined(__GNU_LIBRARY__) && __GNU_LIBRARY__ == 6
220 constexpr char kLibcSoName[] = "libc.so.6";
221 #elif defined(ANDROID_HOST_MUSL)
222 constexpr char kLibcSoName[] = "libc_musl.so";
223 #else
224 #error Unknown libc
225 #endif
226 void* libc = dlopen(kLibcSoName, RTLD_LAZY | RTLD_NOLOAD);
227 ASSERT_TRUE(libc);
228
229 auto libc_sigaction = reinterpret_cast<decltype(&sigaction)>(dlsym(libc, "sigaction"));
230 ASSERT_TRUE(libc_sigaction);
231
232 static sig_atomic_t called = 0;
233 struct sigaction action = {};
234 action.sa_flags = SA_SIGINFO;
235 action.sa_sigaction = [](int, siginfo_t*, void*) { called = 1; };
236
237 ASSERT_EQ(0, libc_sigaction(SIGSEGV, &action, nullptr));
238
239 // Try before EnsureFrontOfChain.
240 RaiseHandled();
241 ASSERT_EQ(1, called);
242 called = 0;
243
244 RaiseUnhandled();
245 ASSERT_EQ(1, called);
246 called = 0;
247
248 // ...and after.
249 art::EnsureFrontOfChain(SIGSEGV);
250 RaiseHandled();
251 ASSERT_EQ(0, called);
252
253 RaiseUnhandled();
254 ASSERT_EQ(1, called);
255 called = 0;
256 }
257
258 #if defined(__aarch64__)
259 // The test intentionally dereferences (tagged) null to trigger SIGSEGV.
260 // We need to disable HWASAN since it would catch the dereference first.
fault_address_tag_impl()261 DISABLE_HWASAN void fault_address_tag_impl() {
262 struct sigaction action = {};
263 action.sa_flags = SA_SIGINFO;
264 action.sa_sigaction = [](int, siginfo_t* siginfo, void*) {
265 _exit(reinterpret_cast<uintptr_t>(siginfo->si_addr) >> 56);
266 };
267 ASSERT_EQ(0, sigaction(SIGSEGV, &action, nullptr));
268
269 auto* tagged_null = reinterpret_cast<int*>(0x2bULL << 56);
270 EXPECT_EXIT({ volatile int load __attribute__((unused)) = *tagged_null; },
271 testing::ExitedWithCode(0), "");
272
273 // Our sigaction implementation always implements the "clear unknown bits"
274 // semantics for oldact.sa_flags regardless of kernel version so we rely on it
275 // here to test for kernel support for SA_EXPOSE_TAGBITS.
276 action.sa_flags = SA_SIGINFO | SA_EXPOSE_TAGBITS;
277 ASSERT_EQ(0, sigaction(SIGSEGV, &action, nullptr));
278 ASSERT_EQ(0, sigaction(SIGSEGV, nullptr, &action));
279 if (action.sa_flags & SA_EXPOSE_TAGBITS) {
280 EXPECT_EXIT({ volatile int load __attribute__((unused)) = *tagged_null; },
281 testing::ExitedWithCode(0x2b), "");
282 }
283 }
284 #endif
285
TEST_F(SigchainTest,fault_address_tag)286 TEST_F(SigchainTest, fault_address_tag) {
287 #define SA_EXPOSE_TAGBITS 0x00000800
288 #if defined(__aarch64__)
289 fault_address_tag_impl();
290 #else
291 GTEST_SKIP() << "arm64 only";
292 #endif
293 }
294