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 = {
__anonbe4e550e0102() 73 .sc_sigaction = [](int, siginfo_t* info, void*) -> bool {
74 return info->si_value.sival_ptr;
75 },
__anonbe4e550e0202() 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(__riscv)
194 // Not exposed via headers, but the symbols are available if you declare them yourself.
195 extern "C" int sigblock(int);
TEST_F(SigchainTest,sigblock)196 TEST_F(SigchainTest, sigblock) {
197 TestSignalBlocking([]() {
198 int mask = ~0U;
199 ASSERT_EQ(0, sigblock(mask));
200 });
201 }
202 extern "C" int sigsetmask(int);
TEST_F(SigchainTest,sigsetmask)203 TEST_F(SigchainTest, sigsetmask) {
204 TestSignalBlocking([]() {
205 int mask = ~0U;
206 ASSERT_EQ(0, sigsetmask(mask));
207 });
208 }
209 #endif
210
211 #endif
212
213 // Make sure that we properly put ourselves back in front if we get circumvented.
TEST_F(SigchainTest,EnsureFrontOfChain)214 TEST_F(SigchainTest, EnsureFrontOfChain) {
215 #if defined(__BIONIC__)
216 constexpr char kLibcSoName[] = "libc.so";
217 #elif defined(__GNU_LIBRARY__) && __GNU_LIBRARY__ == 6
218 constexpr char kLibcSoName[] = "libc.so.6";
219 #elif defined(ANDROID_HOST_MUSL)
220 constexpr char kLibcSoName[] = "libc_musl.so";
221 #else
222 #error Unknown libc
223 #endif
224 void* libc = dlopen(kLibcSoName, RTLD_LAZY | RTLD_NOLOAD);
225 ASSERT_TRUE(libc);
226
227 auto libc_sigaction = reinterpret_cast<decltype(&sigaction)>(dlsym(libc, "sigaction"));
228 ASSERT_TRUE(libc_sigaction);
229
230 static sig_atomic_t called = 0;
231 struct sigaction action = {};
232 action.sa_flags = SA_SIGINFO;
233 action.sa_sigaction = [](int, siginfo_t*, void*) { called = 1; };
234
235 ASSERT_EQ(0, libc_sigaction(SIGSEGV, &action, nullptr));
236
237 // Try before EnsureFrontOfChain.
238 RaiseHandled();
239 ASSERT_EQ(1, called);
240 called = 0;
241
242 RaiseUnhandled();
243 ASSERT_EQ(1, called);
244 called = 0;
245
246 // ...and after.
247 art::EnsureFrontOfChain(SIGSEGV);
248 RaiseHandled();
249 ASSERT_EQ(0, called);
250
251 RaiseUnhandled();
252 ASSERT_EQ(1, called);
253 called = 0;
254 }
255
256 #if defined(__aarch64__)
257 // The test intentionally dereferences (tagged) null to trigger SIGSEGV.
258 // We need to disable HWASAN since it would catch the dereference first.
fault_address_tag_impl()259 DISABLE_HWASAN void fault_address_tag_impl() {
260 struct sigaction action = {};
261 action.sa_flags = SA_SIGINFO;
262 action.sa_sigaction = [](int, siginfo_t* siginfo, void*) {
263 _exit(reinterpret_cast<uintptr_t>(siginfo->si_addr) >> 56);
264 };
265 ASSERT_EQ(0, sigaction(SIGSEGV, &action, nullptr));
266
267 auto* tagged_null = reinterpret_cast<int*>(0x2bULL << 56);
268 EXPECT_EXIT(
269 { [[maybe_unused]] volatile int load = *tagged_null; }, testing::ExitedWithCode(0), "");
270
271 // Our sigaction implementation always implements the "clear unknown bits"
272 // semantics for oldact.sa_flags regardless of kernel version so we rely on it
273 // here to test for kernel support for SA_EXPOSE_TAGBITS.
274 action.sa_flags = SA_SIGINFO | SA_EXPOSE_TAGBITS;
275 ASSERT_EQ(0, sigaction(SIGSEGV, &action, nullptr));
276 ASSERT_EQ(0, sigaction(SIGSEGV, nullptr, &action));
277 if (action.sa_flags & SA_EXPOSE_TAGBITS) {
278 EXPECT_EXIT({ [[maybe_unused]] volatile int load = *tagged_null; },
279 testing::ExitedWithCode(0x2b),
280 "");
281 }
282 }
283 #endif
284
TEST_F(SigchainTest,fault_address_tag)285 TEST_F(SigchainTest, fault_address_tag) {
286 #define SA_EXPOSE_TAGBITS 0x00000800
287 #if defined(__aarch64__)
288 fault_address_tag_impl();
289 #else
290 GTEST_SKIP() << "arm64 only";
291 #endif
292 }
293