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   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