• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
17 #ifdef __ANDROID__
18 #include <android/log.h>
19 #else
20 #include <stdarg.h>
21 #include <iostream>
22 #endif
23 
24 #include <dlfcn.h>
25 #include <signal.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 
29 #include "sigchain.h"
30 
31 #if defined(__APPLE__)
32 #define _NSIG NSIG
33 #define sighandler_t sig_t
34 #endif
35 
36 namespace art {
37 
38 typedef int (*SigActionFnPtr)(int, const struct sigaction*, struct sigaction*);
39 
40 class SignalAction {
41  public:
SignalAction()42   SignalAction() : claimed_(false), uses_old_style_(false), special_handler_(nullptr) {
43   }
44 
45   // Claim the signal and keep the action specified.
Claim(const struct sigaction & action)46   void Claim(const struct sigaction& action) {
47     action_ = action;
48     claimed_ = true;
49   }
50 
51   // Unclaim the signal and restore the old action.
Unclaim(int signal)52   void Unclaim(int signal) {
53     claimed_ = false;
54     sigaction(signal, &action_, nullptr);        // Restore old action.
55   }
56 
57   // Get the action associated with this signal.
GetAction() const58   const struct sigaction& GetAction() const {
59     return action_;
60   }
61 
62   // Is the signal claimed?
IsClaimed() const63   bool IsClaimed() const {
64     return claimed_;
65   }
66 
67   // Change the recorded action to that specified.
68   // 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.
SetAction(const struct sigaction & action,bool oldstyle)71   void SetAction(const struct sigaction& action, bool oldstyle) {
72     action_ = action;
73     uses_old_style_ = oldstyle;
74   }
75 
OldStyle() const76   bool OldStyle() const {
77     return uses_old_style_;
78   }
79 
SetSpecialHandler(SpecialSignalHandlerFn fn)80   void SetSpecialHandler(SpecialSignalHandlerFn fn) {
81     special_handler_ = fn;
82   }
83 
GetSpecialHandler()84   SpecialSignalHandlerFn GetSpecialHandler() {
85     return special_handler_;
86   }
87 
88  private:
89   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.
93 };
94 
95 // User's signal handlers
96 static SignalAction user_sigactions[_NSIG];
97 static bool initialized;
98 static void* linked_sigaction_sym;
99 static void* linked_sigprocmask_sym;
100 
log(const char * format,...)101 static 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);
106 #ifdef __ANDROID__
107   __android_log_write(ANDROID_LOG_ERROR, "libsigchain", buf);
108 #else
109   std::cout << buf << "\n";
110 #endif
111   va_end(ap);
112 }
113 
CheckSignalValid(int signal)114 static void CheckSignalValid(int signal) {
115   if (signal <= 0 || signal >= _NSIG) {
116     log("Invalid signal %d", signal);
117     abort();
118   }
119 }
120 
121 // 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.
sigchainlib_managed_handler_sigaction(int sig,siginfo_t * info,void * context)123 static void sigchainlib_managed_handler_sigaction(int sig, siginfo_t* info, void* context) {
124   InvokeUserSignalHandler(sig, info, context);
125 }
126 
127 // Claim a signal chain for a particular signal.
ClaimSignalChain(int signal,struct sigaction * oldaction)128 extern "C" void ClaimSignalChain(int signal, struct sigaction* oldaction) {
129   CheckSignalValid(signal);
130 
131   user_sigactions[signal].Claim(*oldaction);
132 }
133 
UnclaimSignalChain(int signal)134 extern "C" void UnclaimSignalChain(int signal) {
135   CheckSignalValid(signal);
136 
137   user_sigactions[signal].Unclaim(signal);
138 }
139 
140 // Invoke the user's signal handler.
InvokeUserSignalHandler(int sig,siginfo_t * info,void * context)141 extern "C" void InvokeUserSignalHandler(int sig, siginfo_t* info, void* context) {
142   // 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 
150   // Do we have a managed handler? If so, run it first.
151   SpecialSignalHandlerFn managed = user_sigactions[sig].GetSpecialHandler();
152   if (managed != nullptr) {
153     sigset_t mask, old_mask;
154     sigfillset(&mask);
155     sigprocmask(SIG_BLOCK, &mask, &old_mask);
156     // Call the handler. If it succeeds, we're done.
157     if (managed(sig, info, context)) {
158       sigprocmask(SIG_SETMASK, &old_mask, nullptr);
159       return;
160     }
161     sigprocmask(SIG_SETMASK, &old_mask, nullptr);
162   }
163 
164   const struct sigaction& action = user_sigactions[sig].GetAction();
165   if (user_sigactions[sig].OldStyle()) {
166     if (action.sa_handler != nullptr) {
167       action.sa_handler(sig);
168     } else {
169       signal(sig, SIG_DFL);
170       raise(sig);
171     }
172   } else {
173     if (action.sa_sigaction != nullptr) {
174       sigset_t old_mask;
175       sigprocmask(SIG_BLOCK, &action.sa_mask, &old_mask);
176       action.sa_sigaction(sig, info, context);
177       sigprocmask(SIG_SETMASK, &old_mask, nullptr);
178     } else {
179       signal(sig, SIG_DFL);
180       raise(sig);
181     }
182   }
183 }
184 
EnsureFrontOfChain(int signal,struct sigaction * expected_action)185 extern "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 }
199 
sigaction(int signal,const struct sigaction * new_action,struct sigaction * old_action)200 extern "C" int sigaction(int signal, const struct sigaction* new_action, struct sigaction* old_action) {
201   // 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.
205   if (signal > 0 && signal < _NSIG && user_sigactions[signal].IsClaimed() &&
206       (new_action == nullptr || new_action->sa_handler != SIG_DFL)) {
207     struct sigaction saved_action = user_sigactions[signal].GetAction();
208     if (new_action != nullptr) {
209       user_sigactions[signal].SetAction(*new_action, false);
210     }
211     if (old_action != nullptr) {
212       *old_action = saved_action;
213     }
214     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 
220   if (linked_sigaction_sym == nullptr) {
221     // 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();
231   }
232   SigActionFnPtr linked_sigaction = reinterpret_cast<SigActionFnPtr>(linked_sigaction_sym);
233   return linked_sigaction(signal, new_action, old_action);
234 }
235 
signal(int signal,sighandler_t handler)236 extern "C" sighandler_t signal(int signal, sighandler_t handler) {
237   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.
247   if (signal > 0 && signal < _NSIG && user_sigactions[signal].IsClaimed() && handler != SIG_DFL) {
248     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 
256   if (linked_sigaction_sym == nullptr) {
257     // 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();
264   }
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 
sigprocmask(int how,const sigset_t * bionic_new_set,sigset_t * bionic_old_set)275 extern "C" int sigprocmask(int how, const sigset_t* bionic_new_set, sigset_t* bionic_old_set) {
276   const sigset_t* new_set_ptr = bionic_new_set;
277   sigset_t tmpset;
278   if (bionic_new_set != nullptr) {
279     tmpset = *bionic_new_set;
280 
281     if (how == SIG_BLOCK) {
282       // Don't allow claimed signals in the mask.  If a signal chain has been claimed
283       // we can't allow the user to block that signal.
284       for (int i = 0 ; i < _NSIG; ++i) {
285         if (user_sigactions[i].IsClaimed() && sigismember(&tmpset, i)) {
286           sigdelset(&tmpset, i);
287         }
288       }
289     }
290     new_set_ptr = &tmpset;
291   }
292 
293   if (linked_sigprocmask_sym == nullptr) {
294     // Perform lazy initialization.
295     InitializeSignalChain();
296   }
297 
298   if (linked_sigprocmask_sym == nullptr) {
299     log("Unable to find next sigprocmask in signal chain");
300     abort();
301   }
302 
303   typedef int (*SigProcMask)(int how, const sigset_t*, sigset_t*);
304   SigProcMask linked_sigprocmask= reinterpret_cast<SigProcMask>(linked_sigprocmask_sym);
305   return linked_sigprocmask(how, new_set_ptr, bionic_old_set);
306 }
307 
InitializeSignalChain()308 extern "C" void InitializeSignalChain() {
309   // Warning.
310   // Don't call this from within a signal context as it makes calls to
311   // dlsym.  Calling into the dynamic linker will result in locks being
312   // taken and if it so happens that a signal occurs while one of these
313   // locks is already taken, dlsym will block trying to reenter a
314   // mutex and we will never get out of it.
315   if (initialized) {
316     // Don't initialize twice.
317     return;
318   }
319   linked_sigaction_sym = dlsym(RTLD_NEXT, "sigaction");
320   if (linked_sigaction_sym == nullptr) {
321     linked_sigaction_sym = dlsym(RTLD_DEFAULT, "sigaction");
322     if (linked_sigaction_sym == nullptr ||
323         linked_sigaction_sym == reinterpret_cast<void*>(sigaction)) {
324       linked_sigaction_sym = nullptr;
325     }
326   }
327 
328   linked_sigprocmask_sym = dlsym(RTLD_NEXT, "sigprocmask");
329   if (linked_sigprocmask_sym == nullptr) {
330     linked_sigprocmask_sym = dlsym(RTLD_DEFAULT, "sigprocmask");
331     if (linked_sigprocmask_sym == nullptr ||
332         linked_sigprocmask_sym == reinterpret_cast<void*>(sigprocmask)) {
333       linked_sigprocmask_sym = nullptr;
334     }
335   }
336   initialized = true;
337 }
338 
SetSpecialSignalHandlerFn(int signal,SpecialSignalHandlerFn fn)339 extern "C" void SetSpecialSignalHandlerFn(int signal, SpecialSignalHandlerFn fn) {
340   CheckSignalValid(signal);
341 
342   // Set the managed_handler.
343   user_sigactions[signal].SetSpecialHandler(fn);
344 
345   // In case the chain isn't claimed, claim it for ourself so we can ensure the managed handler
346   // goes first.
347   if (!user_sigactions[signal].IsClaimed()) {
348     struct sigaction act, old_act;
349     act.sa_sigaction = sigchainlib_managed_handler_sigaction;
350     sigemptyset(&act.sa_mask);
351     act.sa_flags = SA_SIGINFO | SA_ONSTACK;
352 #if !defined(__APPLE__) && !defined(__mips__)
353     act.sa_restorer = nullptr;
354 #endif
355     if (sigaction(signal, &act, &old_act) != -1) {
356       user_sigactions[signal].Claim(old_act);
357     }
358   }
359 }
360 
361 }   // namespace art
362 
363