• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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