• 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 = {
__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