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 HAVE_ANDROID_OS
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 HAVE_ANDROID_OS
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 // Call the handler. If it succeeds, we're done.
154 if (managed(sig, info, context)) {
155 return;
156 }
157 }
158
159 const struct sigaction& action = user_sigactions[sig].GetAction();
160 if (user_sigactions[sig].OldStyle()) {
161 if (action.sa_handler != nullptr) {
162 action.sa_handler(sig);
163 } else {
164 signal(sig, SIG_DFL);
165 raise(sig);
166 }
167 } else {
168 if (action.sa_sigaction != nullptr) {
169 action.sa_sigaction(sig, info, context);
170 } else {
171 signal(sig, SIG_DFL);
172 raise(sig);
173 }
174 }
175 }
176
EnsureFrontOfChain(int signal,struct sigaction * expected_action)177 extern "C" void EnsureFrontOfChain(int signal, struct sigaction* expected_action) {
178 CheckSignalValid(signal);
179 // Read the current action without looking at the chain, it should be the expected action.
180 SigActionFnPtr linked_sigaction = reinterpret_cast<SigActionFnPtr>(linked_sigaction_sym);
181 struct sigaction current_action;
182 linked_sigaction(signal, nullptr, ¤t_action);
183 // If the sigactions don't match then we put the current action on the chain and make ourself as
184 // the main action.
185 if (current_action.sa_sigaction != expected_action->sa_sigaction) {
186 log("Warning: Unexpected sigaction action found %p\n", current_action.sa_sigaction);
187 user_sigactions[signal].Claim(current_action);
188 linked_sigaction(signal, expected_action, nullptr);
189 }
190 }
191
sigaction(int signal,const struct sigaction * new_action,struct sigaction * old_action)192 extern "C" int sigaction(int signal, const struct sigaction* new_action, struct sigaction* old_action) {
193 // If this signal has been claimed as a signal chain, record the user's
194 // action but don't pass it on to the kernel.
195 // Note that we check that the signal number is in range here. An out of range signal
196 // number should behave exactly as the libc sigaction.
197 if (signal > 0 && signal < _NSIG && user_sigactions[signal].IsClaimed() &&
198 (new_action == nullptr || new_action->sa_handler != SIG_DFL)) {
199 struct sigaction saved_action = user_sigactions[signal].GetAction();
200 if (new_action != nullptr) {
201 user_sigactions[signal].SetAction(*new_action, false);
202 }
203 if (old_action != nullptr) {
204 *old_action = saved_action;
205 }
206 return 0;
207 }
208
209 // Will only get here if the signal chain has not been claimed. We want
210 // to pass the sigaction on to the kernel via the real sigaction in libc.
211
212 if (linked_sigaction_sym == nullptr) {
213 // Perform lazy initialization.
214 // This will only occur outside of a signal context since we have
215 // not been initialized and therefore cannot be within the ART
216 // runtime.
217 InitializeSignalChain();
218 }
219
220 if (linked_sigaction_sym == nullptr) {
221 log("Unable to find next sigaction in signal chain");
222 abort();
223 }
224 SigActionFnPtr linked_sigaction = reinterpret_cast<SigActionFnPtr>(linked_sigaction_sym);
225 return linked_sigaction(signal, new_action, old_action);
226 }
227
signal(int signal,sighandler_t handler)228 extern "C" sighandler_t signal(int signal, sighandler_t handler) {
229 struct sigaction sa;
230 sigemptyset(&sa.sa_mask);
231 sa.sa_handler = handler;
232 sa.sa_flags = SA_RESTART;
233 sighandler_t oldhandler;
234
235 // If this signal has been claimed as a signal chain, record the user's
236 // action but don't pass it on to the kernel.
237 // Note that we check that the signal number is in range here. An out of range signal
238 // number should behave exactly as the libc sigaction.
239 if (signal > 0 && signal < _NSIG && user_sigactions[signal].IsClaimed() && handler != SIG_DFL) {
240 oldhandler = reinterpret_cast<sighandler_t>(user_sigactions[signal].GetAction().sa_handler);
241 user_sigactions[signal].SetAction(sa, true);
242 return oldhandler;
243 }
244
245 // Will only get here if the signal chain has not been claimed. We want
246 // to pass the sigaction on to the kernel via the real sigaction in libc.
247
248 if (linked_sigaction_sym == nullptr) {
249 // Perform lazy initialization.
250 InitializeSignalChain();
251 }
252
253 if (linked_sigaction_sym == nullptr) {
254 log("Unable to find next sigaction in signal chain");
255 abort();
256 }
257
258 typedef int (*SigAction)(int, const struct sigaction*, struct sigaction*);
259 SigAction linked_sigaction = reinterpret_cast<SigAction>(linked_sigaction_sym);
260 if (linked_sigaction(signal, &sa, &sa) == -1) {
261 return SIG_ERR;
262 }
263
264 return reinterpret_cast<sighandler_t>(sa.sa_handler);
265 }
266
sigprocmask(int how,const sigset_t * bionic_new_set,sigset_t * bionic_old_set)267 extern "C" int sigprocmask(int how, const sigset_t* bionic_new_set, sigset_t* bionic_old_set) {
268 const sigset_t* new_set_ptr = bionic_new_set;
269 sigset_t tmpset;
270 if (bionic_new_set != nullptr) {
271 tmpset = *bionic_new_set;
272
273 if (how == SIG_BLOCK) {
274 // Don't allow claimed signals in the mask. If a signal chain has been claimed
275 // we can't allow the user to block that signal.
276 for (int i = 0 ; i < _NSIG; ++i) {
277 if (user_sigactions[i].IsClaimed() && sigismember(&tmpset, i)) {
278 sigdelset(&tmpset, i);
279 }
280 }
281 }
282 new_set_ptr = &tmpset;
283 }
284
285 if (linked_sigprocmask_sym == nullptr) {
286 // Perform lazy initialization.
287 InitializeSignalChain();
288 }
289
290 if (linked_sigprocmask_sym == nullptr) {
291 log("Unable to find next sigprocmask in signal chain");
292 abort();
293 }
294
295 typedef int (*SigProcMask)(int how, const sigset_t*, sigset_t*);
296 SigProcMask linked_sigprocmask= reinterpret_cast<SigProcMask>(linked_sigprocmask_sym);
297 return linked_sigprocmask(how, new_set_ptr, bionic_old_set);
298 }
299
InitializeSignalChain()300 extern "C" void InitializeSignalChain() {
301 // Warning.
302 // Don't call this from within a signal context as it makes calls to
303 // dlsym. Calling into the dynamic linker will result in locks being
304 // taken and if it so happens that a signal occurs while one of these
305 // locks is already taken, dlsym will block trying to reenter a
306 // mutex and we will never get out of it.
307 if (initialized) {
308 // Don't initialize twice.
309 return;
310 }
311 linked_sigaction_sym = dlsym(RTLD_NEXT, "sigaction");
312 if (linked_sigaction_sym == nullptr) {
313 linked_sigaction_sym = dlsym(RTLD_DEFAULT, "sigaction");
314 if (linked_sigaction_sym == nullptr ||
315 linked_sigaction_sym == reinterpret_cast<void*>(sigaction)) {
316 linked_sigaction_sym = nullptr;
317 }
318 }
319
320 linked_sigprocmask_sym = dlsym(RTLD_NEXT, "sigprocmask");
321 if (linked_sigprocmask_sym == nullptr) {
322 linked_sigprocmask_sym = dlsym(RTLD_DEFAULT, "sigprocmask");
323 if (linked_sigprocmask_sym == nullptr ||
324 linked_sigprocmask_sym == reinterpret_cast<void*>(sigprocmask)) {
325 linked_sigprocmask_sym = nullptr;
326 }
327 }
328 initialized = true;
329 }
330
SetSpecialSignalHandlerFn(int signal,SpecialSignalHandlerFn fn)331 extern "C" void SetSpecialSignalHandlerFn(int signal, SpecialSignalHandlerFn fn) {
332 CheckSignalValid(signal);
333
334 // Set the managed_handler.
335 user_sigactions[signal].SetSpecialHandler(fn);
336
337 // In case the chain isn't claimed, claim it for ourself so we can ensure the managed handler
338 // goes first.
339 if (!user_sigactions[signal].IsClaimed()) {
340 struct sigaction tmp;
341 tmp.sa_sigaction = sigchainlib_managed_handler_sigaction;
342 sigemptyset(&tmp.sa_mask);
343 tmp.sa_flags = SA_SIGINFO | SA_ONSTACK;
344 #if !defined(__APPLE__) && !defined(__mips__)
345 tmp.sa_restorer = nullptr;
346 #endif
347 user_sigactions[signal].Claim(tmp);
348 }
349 }
350
351 } // namespace art
352
353