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 #endif
34
35 namespace art {
36
37 typedef int (*SigActionFnPtr)(int, const struct sigaction*, struct sigaction*);
38
39 class SignalAction {
40 public:
SignalAction()41 SignalAction() : claimed_(false) {
42 }
43
44 // Claim the signal and keep the action specified.
Claim(const struct sigaction & action)45 void Claim(const struct sigaction& action) {
46 action_ = action;
47 claimed_ = true;
48 }
49
50 // Unclaim the signal and restore the old action.
Unclaim(int signal)51 void Unclaim(int signal) {
52 claimed_ = false;
53 sigaction(signal, &action_, NULL); // Restore old action.
54 }
55
56 // Get the action associated with this signal.
GetAction() const57 const struct sigaction& GetAction() const {
58 return action_;
59 }
60
61 // Is the signal claimed?
IsClaimed() const62 bool IsClaimed() const {
63 return claimed_;
64 }
65
66 // Change the recorded action to that specified.
SetAction(const struct sigaction & action)67 void SetAction(const struct sigaction& action) {
68 action_ = action;
69 }
70
71 private:
72 struct sigaction action_; // Action to be performed.
73 bool claimed_; // Whether signal is claimed or not.
74 };
75
76 // User's signal handlers
77 static SignalAction user_sigactions[_NSIG];
78 static bool initialized;
79 static void* linked_sigaction_sym;
80 static void* linked_sigprocmask_sym;
81
log(const char * format,...)82 static void log(const char* format, ...) {
83 char buf[256];
84 va_list ap;
85 va_start(ap, format);
86 vsnprintf(buf, sizeof(buf), format, ap);
87 #ifdef HAVE_ANDROID_OS
88 __android_log_write(ANDROID_LOG_ERROR, "libsigchain", buf);
89 #else
90 std::cout << buf << "\n";
91 #endif
92 va_end(ap);
93 }
94
CheckSignalValid(int signal)95 static void CheckSignalValid(int signal) {
96 if (signal <= 0 || signal >= _NSIG) {
97 log("Invalid signal %d", signal);
98 abort();
99 }
100 }
101
102
103 // Claim a signal chain for a particular signal.
ClaimSignalChain(int signal,struct sigaction * oldaction)104 void ClaimSignalChain(int signal, struct sigaction* oldaction) {
105 CheckSignalValid(signal);
106 user_sigactions[signal].Claim(*oldaction);
107 }
108
UnclaimSignalChain(int signal)109 void UnclaimSignalChain(int signal) {
110 CheckSignalValid(signal);
111
112 user_sigactions[signal].Unclaim(signal);
113 }
114
115 // Invoke the user's signal handler.
InvokeUserSignalHandler(int sig,siginfo_t * info,void * context)116 void InvokeUserSignalHandler(int sig, siginfo_t* info, void* context) {
117 // Check the arguments.
118 CheckSignalValid(sig);
119
120 // The signal must have been claimed in order to get here. Check it.
121 if (!user_sigactions[sig].IsClaimed()) {
122 abort();
123 }
124
125 const struct sigaction& action = user_sigactions[sig].GetAction();
126 if ((action.sa_flags & SA_SIGINFO) == 0) {
127 if (action.sa_handler != NULL) {
128 action.sa_handler(sig);
129 } else {
130 signal(sig, SIG_DFL);
131 raise(sig);
132 }
133 } else {
134 if (action.sa_sigaction != NULL) {
135 action.sa_sigaction(sig, info, context);
136 } else {
137 signal(sig, SIG_DFL);
138 raise(sig);
139 }
140 }
141 }
142
EnsureFrontOfChain(int signal,struct sigaction * expected_action)143 void EnsureFrontOfChain(int signal, struct sigaction* expected_action) {
144 CheckSignalValid(signal);
145 // Read the current action without looking at the chain, it should be the expected action.
146 SigActionFnPtr linked_sigaction = reinterpret_cast<SigActionFnPtr>(linked_sigaction_sym);
147 struct sigaction current_action;
148 linked_sigaction(signal, nullptr, ¤t_action);
149 // If the sigactions don't match then we put the current action on the chain and make ourself as
150 // the main action.
151 if (current_action.sa_sigaction != expected_action->sa_sigaction) {
152 log("Warning: Unexpected sigaction action found %p\n", current_action.sa_sigaction);
153 user_sigactions[signal].Claim(current_action);
154 linked_sigaction(signal, expected_action, nullptr);
155 }
156 }
157
158 extern "C" {
159 // These functions are C linkage since they replace the functions in libc.
160
sigaction(int signal,const struct sigaction * new_action,struct sigaction * old_action)161 int sigaction(int signal, const struct sigaction* new_action, struct sigaction* old_action) {
162 // If this signal has been claimed as a signal chain, record the user's
163 // action but don't pass it on to the kernel.
164 // Note that we check that the signal number is in range here. An out of range signal
165 // number should behave exactly as the libc sigaction.
166 if (signal > 0 && signal < _NSIG && user_sigactions[signal].IsClaimed()) {
167 if (old_action != NULL) {
168 *old_action = user_sigactions[signal].GetAction();
169 }
170 if (new_action != NULL) {
171 user_sigactions[signal].SetAction(*new_action);
172 }
173 return 0;
174 }
175
176 // Will only get here if the signal chain has not been claimed. We want
177 // to pass the sigaction on to the kernel via the real sigaction in libc.
178
179 if (linked_sigaction_sym == nullptr) {
180 // Perform lazy initialization.
181 // This will only occur outside of a signal context since we have
182 // not been initialized and therefore cannot be within the ART
183 // runtime.
184 InitializeSignalChain();
185 }
186
187 if (linked_sigaction_sym == nullptr) {
188 log("Unable to find next sigaction in signal chain");
189 abort();
190 }
191 SigActionFnPtr linked_sigaction = reinterpret_cast<SigActionFnPtr>(linked_sigaction_sym);
192 return linked_sigaction(signal, new_action, old_action);
193 }
194
sigprocmask(int how,const sigset_t * bionic_new_set,sigset_t * bionic_old_set)195 int sigprocmask(int how, const sigset_t* bionic_new_set, sigset_t* bionic_old_set) {
196 const sigset_t* new_set_ptr = bionic_new_set;
197 sigset_t tmpset;
198 if (bionic_new_set != NULL) {
199 tmpset = *bionic_new_set;
200
201 if (how == SIG_BLOCK) {
202 // Don't allow claimed signals in the mask. If a signal chain has been claimed
203 // we can't allow the user to block that signal.
204 for (int i = 0 ; i < _NSIG; ++i) {
205 if (user_sigactions[i].IsClaimed() && sigismember(&tmpset, i)) {
206 sigdelset(&tmpset, i);
207 }
208 }
209 }
210 new_set_ptr = &tmpset;
211 }
212
213 if (linked_sigprocmask_sym == nullptr) {
214 // Perform lazy initialization.
215 InitializeSignalChain();
216 }
217
218 if (linked_sigprocmask_sym == nullptr) {
219 log("Unable to find next sigprocmask in signal chain");
220 abort();
221 }
222
223 typedef int (*SigProcMask)(int how, const sigset_t*, sigset_t*);
224 SigProcMask linked_sigprocmask= reinterpret_cast<SigProcMask>(linked_sigprocmask_sym);
225 return linked_sigprocmask(how, new_set_ptr, bionic_old_set);
226 }
227 } // extern "C"
228
InitializeSignalChain()229 void InitializeSignalChain() {
230 // Warning.
231 // Don't call this from within a signal context as it makes calls to
232 // dlsym. Calling into the dynamic linker will result in locks being
233 // taken and if it so happens that a signal occurs while one of these
234 // locks is already taken, dlsym will block trying to reenter a
235 // mutex and we will never get out of it.
236 if (initialized) {
237 // Don't initialize twice.
238 return;
239 }
240 linked_sigaction_sym = dlsym(RTLD_NEXT, "sigaction");
241 if (linked_sigaction_sym == nullptr) {
242 linked_sigaction_sym = dlsym(RTLD_DEFAULT, "sigaction");
243 if (linked_sigaction_sym == nullptr ||
244 linked_sigaction_sym == reinterpret_cast<void*>(sigaction)) {
245 linked_sigaction_sym = nullptr;
246 }
247 }
248
249 linked_sigprocmask_sym = dlsym(RTLD_NEXT, "sigprocmask");
250 if (linked_sigprocmask_sym == nullptr) {
251 linked_sigprocmask_sym = dlsym(RTLD_DEFAULT, "sigprocmask");
252 if (linked_sigprocmask_sym == nullptr ||
253 linked_sigprocmask_sym == reinterpret_cast<void*>(sigprocmask)) {
254 linked_sigprocmask_sym = nullptr;
255 }
256 }
257 initialized = true;
258 }
259 } // namespace art
260
261