blob: c1efecd19dd1f14ba02a4bd7324c1c53f02d094d [file] [log] [blame]
Dave Allisonf4b80bc2014-05-14 15:41:25 -07001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Bilyan Borisovbb661c02016-04-04 16:27:32 +010017#ifdef ART_TARGET_ANDROID
Dave Allisonf4b80bc2014-05-14 15:41:25 -070018#include <android/log.h>
Dave Allison69dfe512014-07-11 17:11:58 +000019#else
20#include <stdarg.h>
21#include <iostream>
22#endif
23
Dave Allisonf4b80bc2014-05-14 15:41:25 -070024#include <dlfcn.h>
25#include <signal.h>
26#include <stdio.h>
27#include <stdlib.h>
28
Dave Allisoncefcea82014-09-16 10:01:01 -070029#include "sigchain.h"
30
Dave Allison69dfe512014-07-11 17:11:58 +000031#if defined(__APPLE__)
32#define _NSIG NSIG
Dave Allison38680092014-08-29 12:29:34 -070033#define sighandler_t sig_t
Dave Allison69dfe512014-07-11 17:11:58 +000034#endif
35
Dave Allisonf4b80bc2014-05-14 15:41:25 -070036namespace art {
37
Mathieu Chartierd0004802014-10-15 16:59:47 -070038typedef int (*SigActionFnPtr)(int, const struct sigaction*, struct sigaction*);
39
Dave Allisonf4b80bc2014-05-14 15:41:25 -070040class SignalAction {
41 public:
Andreas Gampe03c2cc82015-05-22 18:31:50 -070042 SignalAction() : claimed_(false), uses_old_style_(false), special_handler_(nullptr) {
Dave Allisonf4b80bc2014-05-14 15:41:25 -070043 }
44
45 // Claim the signal and keep the action specified.
46 void Claim(const struct sigaction& action) {
47 action_ = action;
48 claimed_ = true;
49 }
50
51 // Unclaim the signal and restore the old action.
52 void Unclaim(int signal) {
Dave Allison1f8ef6f2014-08-20 17:38:41 -070053 claimed_ = false;
Mathieu Chartier2cebb242015-04-21 16:50:40 -070054 sigaction(signal, &action_, nullptr); // Restore old action.
Dave Allisonf4b80bc2014-05-14 15:41:25 -070055 }
56
57 // Get the action associated with this signal.
58 const struct sigaction& GetAction() const {
59 return action_;
60 }
61
62 // Is the signal claimed?
63 bool IsClaimed() const {
64 return claimed_;
65 }
66
67 // Change the recorded action to that specified.
Dave Allison91a83662014-08-28 16:12:40 -070068 // If oldstyle is true then this action is from an older style signal()
69 // call as opposed to sigaction(). In this case the sa_handler is
70 // used when invoking the user's handler.
71 void SetAction(const struct sigaction& action, bool oldstyle) {
Dave Allisonf4b80bc2014-05-14 15:41:25 -070072 action_ = action;
Dave Allison91a83662014-08-28 16:12:40 -070073 uses_old_style_ = oldstyle;
74 }
75
76 bool OldStyle() const {
77 return uses_old_style_;
Dave Allisonf4b80bc2014-05-14 15:41:25 -070078 }
79
Andreas Gampe03c2cc82015-05-22 18:31:50 -070080 void SetSpecialHandler(SpecialSignalHandlerFn fn) {
81 special_handler_ = fn;
82 }
83
84 SpecialSignalHandlerFn GetSpecialHandler() {
85 return special_handler_;
86 }
87
Dave Allisonf4b80bc2014-05-14 15:41:25 -070088 private:
Andreas Gampe03c2cc82015-05-22 18:31:50 -070089 struct sigaction action_; // Action to be performed.
90 bool claimed_; // Whether signal is claimed or not.
91 bool uses_old_style_; // Action is created using signal(). Use sa_handler.
92 SpecialSignalHandlerFn special_handler_; // A special handler executed before user handlers.
Dave Allisonf4b80bc2014-05-14 15:41:25 -070093};
94
95// User's signal handlers
96static SignalAction user_sigactions[_NSIG];
Dave Allisoncefcea82014-09-16 10:01:01 -070097static bool initialized;
98static void* linked_sigaction_sym;
99static void* linked_sigprocmask_sym;
Dave Allisonf4b80bc2014-05-14 15:41:25 -0700100
101static void log(const char* format, ...) {
102 char buf[256];
103 va_list ap;
104 va_start(ap, format);
105 vsnprintf(buf, sizeof(buf), format, ap);
Bilyan Borisovbb661c02016-04-04 16:27:32 +0100106#ifdef ART_TARGET_ANDROID
Dave Allisonf4b80bc2014-05-14 15:41:25 -0700107 __android_log_write(ANDROID_LOG_ERROR, "libsigchain", buf);
Dave Allison69dfe512014-07-11 17:11:58 +0000108#else
109 std::cout << buf << "\n";
110#endif
Dave Allisonf4b80bc2014-05-14 15:41:25 -0700111 va_end(ap);
112}
113
114static void CheckSignalValid(int signal) {
115 if (signal <= 0 || signal >= _NSIG) {
116 log("Invalid signal %d", signal);
117 abort();
118 }
119}
120
Andreas Gampe03c2cc82015-05-22 18:31:50 -0700121// Sigchainlib's own handler so we can ensure a managed handler is called first even if nobody
122// claimed a chain. Simply forward to InvokeUserSignalHandler.
123static void sigchainlib_managed_handler_sigaction(int sig, siginfo_t* info, void* context) {
124 InvokeUserSignalHandler(sig, info, context);
125}
126
Dave Allisonf4b80bc2014-05-14 15:41:25 -0700127// Claim a signal chain for a particular signal.
Dmitriy Ivanovf57874d2014-10-07 13:43:23 -0700128extern "C" void ClaimSignalChain(int signal, struct sigaction* oldaction) {
Dave Allisonf4b80bc2014-05-14 15:41:25 -0700129 CheckSignalValid(signal);
Andreas Gampe03c2cc82015-05-22 18:31:50 -0700130
Dave Allisonf4b80bc2014-05-14 15:41:25 -0700131 user_sigactions[signal].Claim(*oldaction);
132}
133
Dmitriy Ivanovf57874d2014-10-07 13:43:23 -0700134extern "C" void UnclaimSignalChain(int signal) {
Dave Allisonf4b80bc2014-05-14 15:41:25 -0700135 CheckSignalValid(signal);
136
137 user_sigactions[signal].Unclaim(signal);
138}
139
140// Invoke the user's signal handler.
Dmitriy Ivanovf57874d2014-10-07 13:43:23 -0700141extern "C" void InvokeUserSignalHandler(int sig, siginfo_t* info, void* context) {
Dave Allisonf4b80bc2014-05-14 15:41:25 -0700142 // Check the arguments.
143 CheckSignalValid(sig);
144
145 // The signal must have been claimed in order to get here. Check it.
146 if (!user_sigactions[sig].IsClaimed()) {
147 abort();
148 }
149
Andreas Gampe03c2cc82015-05-22 18:31:50 -0700150 // Do we have a managed handler? If so, run it first.
151 SpecialSignalHandlerFn managed = user_sigactions[sig].GetSpecialHandler();
152 if (managed != nullptr) {
jgu210d6f0262015-09-22 03:47:43 -0400153 sigset_t mask, old_mask;
154 sigfillset(&mask);
155 sigprocmask(SIG_BLOCK, &mask, &old_mask);
Andreas Gampe03c2cc82015-05-22 18:31:50 -0700156 // Call the handler. If it succeeds, we're done.
157 if (managed(sig, info, context)) {
jgu210d6f0262015-09-22 03:47:43 -0400158 sigprocmask(SIG_SETMASK, &old_mask, nullptr);
Andreas Gampe03c2cc82015-05-22 18:31:50 -0700159 return;
160 }
jgu210d6f0262015-09-22 03:47:43 -0400161 sigprocmask(SIG_SETMASK, &old_mask, nullptr);
Andreas Gampe03c2cc82015-05-22 18:31:50 -0700162 }
163
Dave Allisonf4b80bc2014-05-14 15:41:25 -0700164 const struct sigaction& action = user_sigactions[sig].GetAction();
Dave Allison91a83662014-08-28 16:12:40 -0700165 if (user_sigactions[sig].OldStyle()) {
Mathieu Chartier2cebb242015-04-21 16:50:40 -0700166 if (action.sa_handler != nullptr) {
Dave Allisonf4b80bc2014-05-14 15:41:25 -0700167 action.sa_handler(sig);
Dave Allison69dfe512014-07-11 17:11:58 +0000168 } else {
Dmitriy Ivanova3164b92015-04-01 11:08:45 -0700169 signal(sig, SIG_DFL);
170 raise(sig);
Dave Allisonf4b80bc2014-05-14 15:41:25 -0700171 }
172 } else {
Mathieu Chartier2cebb242015-04-21 16:50:40 -0700173 if (action.sa_sigaction != nullptr) {
jgu210d6f0262015-09-22 03:47:43 -0400174 sigset_t old_mask;
175 sigprocmask(SIG_BLOCK, &action.sa_mask, &old_mask);
Dave Allisonf4b80bc2014-05-14 15:41:25 -0700176 action.sa_sigaction(sig, info, context);
jgu210d6f0262015-09-22 03:47:43 -0400177 sigprocmask(SIG_SETMASK, &old_mask, nullptr);
Dave Allison69dfe512014-07-11 17:11:58 +0000178 } else {
Dmitriy Ivanova3164b92015-04-01 11:08:45 -0700179 signal(sig, SIG_DFL);
180 raise(sig);
Dave Allisonf4b80bc2014-05-14 15:41:25 -0700181 }
182 }
183}
184
Mathieu Chartierd0004802014-10-15 16:59:47 -0700185extern "C" void EnsureFrontOfChain(int signal, struct sigaction* expected_action) {
186 CheckSignalValid(signal);
187 // Read the current action without looking at the chain, it should be the expected action.
188 SigActionFnPtr linked_sigaction = reinterpret_cast<SigActionFnPtr>(linked_sigaction_sym);
189 struct sigaction current_action;
190 linked_sigaction(signal, nullptr, &current_action);
191 // If the sigactions don't match then we put the current action on the chain and make ourself as
192 // the main action.
193 if (current_action.sa_sigaction != expected_action->sa_sigaction) {
194 log("Warning: Unexpected sigaction action found %p\n", current_action.sa_sigaction);
195 user_sigactions[signal].Claim(current_action);
196 linked_sigaction(signal, expected_action, nullptr);
197 }
198}
Dave Allisonf4b80bc2014-05-14 15:41:25 -0700199
Dmitriy Ivanovf57874d2014-10-07 13:43:23 -0700200extern "C" int sigaction(int signal, const struct sigaction* new_action, struct sigaction* old_action) {
Dave Allisonf4b80bc2014-05-14 15:41:25 -0700201 // If this signal has been claimed as a signal chain, record the user's
202 // action but don't pass it on to the kernel.
203 // Note that we check that the signal number is in range here. An out of range signal
204 // number should behave exactly as the libc sigaction.
Dmitriy Ivanov34a0c202015-04-02 18:30:22 -0700205 if (signal > 0 && signal < _NSIG && user_sigactions[signal].IsClaimed() &&
206 (new_action == nullptr || new_action->sa_handler != SIG_DFL)) {
Dmitriy Ivanovc01683b2015-01-06 14:55:26 -0800207 struct sigaction saved_action = user_sigactions[signal].GetAction();
Mathieu Chartier2cebb242015-04-21 16:50:40 -0700208 if (new_action != nullptr) {
Dave Allison91a83662014-08-28 16:12:40 -0700209 user_sigactions[signal].SetAction(*new_action, false);
Dave Allisonf4b80bc2014-05-14 15:41:25 -0700210 }
Mathieu Chartier2cebb242015-04-21 16:50:40 -0700211 if (old_action != nullptr) {
Dmitriy Ivanovc01683b2015-01-06 14:55:26 -0800212 *old_action = saved_action;
213 }
Dave Allisonf4b80bc2014-05-14 15:41:25 -0700214 return 0;
215 }
216
217 // Will only get here if the signal chain has not been claimed. We want
218 // to pass the sigaction on to the kernel via the real sigaction in libc.
219
Dave Allisonf4b80bc2014-05-14 15:41:25 -0700220 if (linked_sigaction_sym == nullptr) {
Dave Allisoncefcea82014-09-16 10:01:01 -0700221 // Perform lazy initialization.
222 // This will only occur outside of a signal context since we have
223 // not been initialized and therefore cannot be within the ART
224 // runtime.
225 InitializeSignalChain();
226 }
227
228 if (linked_sigaction_sym == nullptr) {
229 log("Unable to find next sigaction in signal chain");
230 abort();
Dave Allisonf4b80bc2014-05-14 15:41:25 -0700231 }
Mathieu Chartierd0004802014-10-15 16:59:47 -0700232 SigActionFnPtr linked_sigaction = reinterpret_cast<SigActionFnPtr>(linked_sigaction_sym);
Dave Allisonf4b80bc2014-05-14 15:41:25 -0700233 return linked_sigaction(signal, new_action, old_action);
234}
235
Dimitry Ivanov82b67b92016-08-01 11:19:03 -0700236static sighandler_t signal_impl(int signal, sighandler_t handler) {
Dave Allison91a83662014-08-28 16:12:40 -0700237 struct sigaction sa;
238 sigemptyset(&sa.sa_mask);
239 sa.sa_handler = handler;
240 sa.sa_flags = SA_RESTART;
241 sighandler_t oldhandler;
242
243 // If this signal has been claimed as a signal chain, record the user's
244 // action but don't pass it on to the kernel.
245 // Note that we check that the signal number is in range here. An out of range signal
246 // number should behave exactly as the libc sigaction.
Dmitriy Ivanov34a0c202015-04-02 18:30:22 -0700247 if (signal > 0 && signal < _NSIG && user_sigactions[signal].IsClaimed() && handler != SIG_DFL) {
Dave Allison91a83662014-08-28 16:12:40 -0700248 oldhandler = reinterpret_cast<sighandler_t>(user_sigactions[signal].GetAction().sa_handler);
249 user_sigactions[signal].SetAction(sa, true);
250 return oldhandler;
251 }
252
253 // Will only get here if the signal chain has not been claimed. We want
254 // to pass the sigaction on to the kernel via the real sigaction in libc.
255
Dave Allison91a83662014-08-28 16:12:40 -0700256 if (linked_sigaction_sym == nullptr) {
Dave Allisoncefcea82014-09-16 10:01:01 -0700257 // Perform lazy initialization.
258 InitializeSignalChain();
259 }
260
261 if (linked_sigaction_sym == nullptr) {
262 log("Unable to find next sigaction in signal chain");
263 abort();
Dave Allison91a83662014-08-28 16:12:40 -0700264 }
265
266 typedef int (*SigAction)(int, const struct sigaction*, struct sigaction*);
267 SigAction linked_sigaction = reinterpret_cast<SigAction>(linked_sigaction_sym);
268 if (linked_sigaction(signal, &sa, &sa) == -1) {
269 return SIG_ERR;
270 }
271
272 return reinterpret_cast<sighandler_t>(sa.sa_handler);
273}
274
Dimitry Ivanov82b67b92016-08-01 11:19:03 -0700275extern "C" sighandler_t signal(int signal, sighandler_t handler) {
276 return signal_impl(signal, handler);
277}
278
279#if !defined(__LP64__)
280extern "C" sighandler_t bsd_signal(int signal, sighandler_t handler) {
281 return signal_impl(signal, handler);
282}
283#endif
284
Dmitriy Ivanovf57874d2014-10-07 13:43:23 -0700285extern "C" int sigprocmask(int how, const sigset_t* bionic_new_set, sigset_t* bionic_old_set) {
Dave Allisonf4b80bc2014-05-14 15:41:25 -0700286 const sigset_t* new_set_ptr = bionic_new_set;
287 sigset_t tmpset;
Mathieu Chartier2cebb242015-04-21 16:50:40 -0700288 if (bionic_new_set != nullptr) {
Dave Allisonf4b80bc2014-05-14 15:41:25 -0700289 tmpset = *bionic_new_set;
290
291 if (how == SIG_BLOCK) {
292 // Don't allow claimed signals in the mask. If a signal chain has been claimed
293 // we can't allow the user to block that signal.
294 for (int i = 0 ; i < _NSIG; ++i) {
295 if (user_sigactions[i].IsClaimed() && sigismember(&tmpset, i)) {
Dmitriy Ivanova3164b92015-04-01 11:08:45 -0700296 sigdelset(&tmpset, i);
Dave Allisonf4b80bc2014-05-14 15:41:25 -0700297 }
298 }
299 }
300 new_set_ptr = &tmpset;
301 }
302
Dave Allisonf4b80bc2014-05-14 15:41:25 -0700303 if (linked_sigprocmask_sym == nullptr) {
Dave Allisoncefcea82014-09-16 10:01:01 -0700304 // Perform lazy initialization.
305 InitializeSignalChain();
306 }
307
308 if (linked_sigprocmask_sym == nullptr) {
309 log("Unable to find next sigprocmask in signal chain");
310 abort();
Dave Allisonf4b80bc2014-05-14 15:41:25 -0700311 }
312
313 typedef int (*SigProcMask)(int how, const sigset_t*, sigset_t*);
314 SigProcMask linked_sigprocmask= reinterpret_cast<SigProcMask>(linked_sigprocmask_sym);
315 return linked_sigprocmask(how, new_set_ptr, bionic_old_set);
316}
Dave Allisoncefcea82014-09-16 10:01:01 -0700317
Dmitriy Ivanovf57874d2014-10-07 13:43:23 -0700318extern "C" void InitializeSignalChain() {
Dave Allisoncefcea82014-09-16 10:01:01 -0700319 // Warning.
320 // Don't call this from within a signal context as it makes calls to
321 // dlsym. Calling into the dynamic linker will result in locks being
322 // taken and if it so happens that a signal occurs while one of these
323 // locks is already taken, dlsym will block trying to reenter a
324 // mutex and we will never get out of it.
325 if (initialized) {
326 // Don't initialize twice.
327 return;
328 }
329 linked_sigaction_sym = dlsym(RTLD_NEXT, "sigaction");
330 if (linked_sigaction_sym == nullptr) {
331 linked_sigaction_sym = dlsym(RTLD_DEFAULT, "sigaction");
332 if (linked_sigaction_sym == nullptr ||
Dmitriy Ivanova3164b92015-04-01 11:08:45 -0700333 linked_sigaction_sym == reinterpret_cast<void*>(sigaction)) {
334 linked_sigaction_sym = nullptr;
Dave Allisoncefcea82014-09-16 10:01:01 -0700335 }
336 }
337
338 linked_sigprocmask_sym = dlsym(RTLD_NEXT, "sigprocmask");
339 if (linked_sigprocmask_sym == nullptr) {
340 linked_sigprocmask_sym = dlsym(RTLD_DEFAULT, "sigprocmask");
341 if (linked_sigprocmask_sym == nullptr ||
342 linked_sigprocmask_sym == reinterpret_cast<void*>(sigprocmask)) {
Dmitriy Ivanova3164b92015-04-01 11:08:45 -0700343 linked_sigprocmask_sym = nullptr;
Dave Allisoncefcea82014-09-16 10:01:01 -0700344 }
345 }
346 initialized = true;
347}
Mathieu Chartierd0004802014-10-15 16:59:47 -0700348
Andreas Gampe03c2cc82015-05-22 18:31:50 -0700349extern "C" void SetSpecialSignalHandlerFn(int signal, SpecialSignalHandlerFn fn) {
350 CheckSignalValid(signal);
351
352 // Set the managed_handler.
353 user_sigactions[signal].SetSpecialHandler(fn);
354
355 // In case the chain isn't claimed, claim it for ourself so we can ensure the managed handler
356 // goes first.
357 if (!user_sigactions[signal].IsClaimed()) {
jgu210c7c55c2015-07-24 13:40:33 +0800358 struct sigaction act, old_act;
359 act.sa_sigaction = sigchainlib_managed_handler_sigaction;
360 sigemptyset(&act.sa_mask);
361 act.sa_flags = SA_SIGINFO | SA_ONSTACK;
Andreas Gampe03c2cc82015-05-22 18:31:50 -0700362#if !defined(__APPLE__) && !defined(__mips__)
jgu210c7c55c2015-07-24 13:40:33 +0800363 act.sa_restorer = nullptr;
Andreas Gampe03c2cc82015-05-22 18:31:50 -0700364#endif
jgu210c7c55c2015-07-24 13:40:33 +0800365 if (sigaction(signal, &act, &old_act) != -1) {
366 user_sigactions[signal].Claim(old_act);
367 }
Andreas Gampe03c2cc82015-05-22 18:31:50 -0700368 }
369}
370
Dave Allisonf4b80bc2014-05-14 15:41:25 -0700371} // namespace art
372