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 = {
__anon09b6ce300102() 73 .sc_sigaction = [](int, siginfo_t* info, void*) -> bool {
74 return info->si_value.sival_ptr;
75 },
__anon09b6ce300202() 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())
108 return;
109 ASSERT_EQ(0, RealSigprocmask(SIG_SETMASK, nullptr, &mask));
110 ASSERT_FALSE(sigismember64(&mask, SIGSEGV));
111 }
112
TEST_F(SigchainTest,sigprocmask_setmask)113 TEST_F(SigchainTest, sigprocmask_setmask) {
114 TestSignalBlocking([]() {
115 sigset_t mask;
116 sigfillset(&mask);
117 ASSERT_EQ(0, sigprocmask(SIG_SETMASK, &mask, nullptr));
118 });
119 }
120
TEST_F(SigchainTest,sigprocmask_block)121 TEST_F(SigchainTest, sigprocmask_block) {
122 TestSignalBlocking([]() {
123 sigset_t mask;
124 sigfillset(&mask);
125 ASSERT_EQ(0, sigprocmask(SIG_BLOCK, &mask, nullptr));
126 });
127 }
128
129 // bionic-only wide variants for LP32.
130 #if defined(__BIONIC__)
TEST_F(SigchainTest,sigprocmask64_setmask)131 TEST_F(SigchainTest, sigprocmask64_setmask) {
132 TestSignalBlocking([]() {
133 sigset64_t mask;
134 sigfillset64(&mask);
135 ASSERT_EQ(0, sigprocmask64(SIG_SETMASK, &mask, nullptr));
136 });
137 }
138
TEST_F(SigchainTest,sigprocmask64_block)139 TEST_F(SigchainTest, sigprocmask64_block) {
140 TestSignalBlocking([]() {
141 sigset64_t mask;
142 sigfillset64(&mask);
143 ASSERT_EQ(0, sigprocmask64(SIG_BLOCK, &mask, nullptr));
144 });
145 }
146
TEST_F(SigchainTest,pthread_sigmask64_setmask)147 TEST_F(SigchainTest, pthread_sigmask64_setmask) {
148 TestSignalBlocking([]() {
149 sigset64_t mask;
150 sigfillset64(&mask);
151 ASSERT_EQ(0, pthread_sigmask64(SIG_SETMASK, &mask, nullptr));
152 });
153 }
154
TEST_F(SigchainTest,pthread_sigmask64_block)155 TEST_F(SigchainTest, pthread_sigmask64_block) {
156 TestSignalBlocking([]() {
157 sigset64_t mask;
158 sigfillset64(&mask);
159 ASSERT_EQ(0, pthread_sigmask64(SIG_BLOCK, &mask, nullptr));
160 });
161 }
162 #endif
163
164 // glibc doesn't implement most of these in terms of sigprocmask, which we rely on.
165 #if defined(__BIONIC__)
TEST_F(SigchainTest,pthread_sigmask_setmask)166 TEST_F(SigchainTest, pthread_sigmask_setmask) {
167 TestSignalBlocking([]() {
168 sigset_t mask;
169 sigfillset(&mask);
170 ASSERT_EQ(0, pthread_sigmask(SIG_SETMASK, &mask, nullptr));
171 });
172 }
173
TEST_F(SigchainTest,pthread_sigmask_block)174 TEST_F(SigchainTest, pthread_sigmask_block) {
175 TestSignalBlocking([]() {
176 sigset_t mask;
177 sigfillset(&mask);
178 ASSERT_EQ(0, pthread_sigmask(SIG_BLOCK, &mask, nullptr));
179 });
180 }
181
TEST_F(SigchainTest,sigset_mask)182 TEST_F(SigchainTest, sigset_mask) {
183 TestSignalBlocking([]() {
184 sigset(SIGSEGV, SIG_HOLD);
185 });
186 }
187
TEST_F(SigchainTest,sighold)188 TEST_F(SigchainTest, sighold) {
189 TestSignalBlocking([]() {
190 sighold(SIGSEGV);
191 });
192 }
193
194 #if !defined(__riscv)
195 // Not exposed via headers, but the symbols are available if you declare them yourself.
196 extern "C" int sigblock(int);
TEST_F(SigchainTest,sigblock)197 TEST_F(SigchainTest, sigblock) {
198 TestSignalBlocking([]() {
199 int mask = ~0U;
200 ASSERT_EQ(0, sigblock(mask));
201 });
202 }
203 extern "C" int sigsetmask(int);
TEST_F(SigchainTest,sigsetmask)204 TEST_F(SigchainTest, sigsetmask) {
205 TestSignalBlocking([]() {
206 int mask = ~0U;
207 ASSERT_EQ(0, sigsetmask(mask));
208 });
209 }
210 #endif
211
212 #endif
213
214 // Make sure that we properly put ourselves back in front if we get circumvented.
TEST_F(SigchainTest,EnsureFrontOfChain)215 TEST_F(SigchainTest, EnsureFrontOfChain) {
216 #if defined(__BIONIC__)
217 constexpr char kLibcSoName[] = "libc.so";
218 #elif defined(__GNU_LIBRARY__) && __GNU_LIBRARY__ == 6
219 constexpr char kLibcSoName[] = "libc.so.6";
220 #elif defined(ANDROID_HOST_MUSL)
221 constexpr char kLibcSoName[] = "libc_musl.so";
222 #else
223 #error Unknown libc
224 #endif
225 void* libc = dlopen(kLibcSoName, RTLD_LAZY | RTLD_NOLOAD);
226 ASSERT_TRUE(libc);
227
228 auto libc_sigaction = reinterpret_cast<decltype(&sigaction)>(dlsym(libc, "sigaction"));
229 ASSERT_TRUE(libc_sigaction);
230
231 static sig_atomic_t called = 0;
232 struct sigaction action = {};
233 action.sa_flags = SA_SIGINFO;
234 action.sa_sigaction = [](int, siginfo_t*, void*) { called = 1; };
235
236 ASSERT_EQ(0, libc_sigaction(SIGSEGV, &action, nullptr));
237
238 // Try before EnsureFrontOfChain.
239 RaiseHandled();
240 ASSERT_EQ(1, called);
241 called = 0;
242
243 RaiseUnhandled();
244 ASSERT_EQ(1, called);
245 called = 0;
246
247 // ...and after.
248 art::EnsureFrontOfChain(SIGSEGV);
249 RaiseHandled();
250 ASSERT_EQ(0, called);
251
252 RaiseUnhandled();
253 ASSERT_EQ(1, called);
254 called = 0;
255 }
256
257 #if defined(__aarch64__)
258 // The test intentionally dereferences (tagged) null to trigger SIGSEGV.
259 // We need to disable HWASAN since it would catch the dereference first.
fault_address_tag_impl()260 DISABLE_HWASAN void fault_address_tag_impl() {
261 struct sigaction action = {};
262 action.sa_flags = SA_SIGINFO;
263 action.sa_sigaction = [](int, siginfo_t* siginfo, void*) {
264 _exit(reinterpret_cast<uintptr_t>(siginfo->si_addr) >> 56);
265 };
266 ASSERT_EQ(0, sigaction(SIGSEGV, &action, nullptr));
267
268 auto* tagged_null = reinterpret_cast<int*>(0x2bULL << 56);
269 EXPECT_EXIT(
270 { [[maybe_unused]] volatile int load = *tagged_null; }, ::testing::ExitedWithCode(0), "");
271
272 // Our sigaction implementation always implements the "clear unknown bits"
273 // semantics for oldact.sa_flags regardless of kernel version so we rely on it
274 // here to test for kernel support for SA_EXPOSE_TAGBITS.
275 action.sa_flags = SA_SIGINFO | SA_EXPOSE_TAGBITS;
276 ASSERT_EQ(0, sigaction(SIGSEGV, &action, nullptr));
277 ASSERT_EQ(0, sigaction(SIGSEGV, nullptr, &action));
278 if (action.sa_flags & SA_EXPOSE_TAGBITS) {
279 EXPECT_EXIT(
280 { [[maybe_unused]] volatile int load = *tagged_null; },
281 ::testing::ExitedWithCode(0x2b),
282 "");
283 }
284 }
285 #endif
286
TEST_F(SigchainTest,fault_address_tag)287 TEST_F(SigchainTest, fault_address_tag) {
288 #define SA_EXPOSE_TAGBITS 0x00000800
289 #if defined(__aarch64__)
290 fault_address_tag_impl();
291 #else
292 GTEST_SKIP() << "arm64 only";
293 #endif
294 }
295