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 = {
__anon960f7bc30102() 67 .sc_sigaction = [](int, siginfo_t* info, void*) -> bool {
68 return info->si_value.sival_ptr;
69 },
__anon960f7bc30202() 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 static sig_atomic_t called = 0;
218 struct sigaction action = {};
219 action.sa_flags = SA_SIGINFO;
220 action.sa_sigaction = [](int, siginfo_t*, void*) { called = 1; };
221
222 ASSERT_EQ(0, sigaction(SIGSEGV, &action, nullptr));
223
224 // Try before EnsureFrontOfChain.
225 RaiseHandled();
226 ASSERT_EQ(0, called);
227
228 RaiseUnhandled();
229 ASSERT_EQ(1, called);
230 called = 0;
231
232 // ...and after.
233 art::EnsureFrontOfChain(SIGSEGV);
234 ASSERT_EQ(0, called);
235 called = 0;
236
237 RaiseUnhandled();
238 ASSERT_EQ(1, called);
239 called = 0;
240 }
241