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 // Claim a signal chain for a particular signal.
ClaimSignalChain(int signal,struct sigaction * oldaction)103 extern "C" void ClaimSignalChain(int signal, struct sigaction* oldaction) {
104 CheckSignalValid(signal);
105 user_sigactions[signal].Claim(*oldaction);
106 }
107
UnclaimSignalChain(int signal)108 extern "C" void UnclaimSignalChain(int signal) {
109 CheckSignalValid(signal);
110
111 user_sigactions[signal].Unclaim(signal);
112 }
113
114 // Invoke the user's signal handler.
InvokeUserSignalHandler(int sig,siginfo_t * info,void * context)115 extern "C" void InvokeUserSignalHandler(int sig, siginfo_t* info, void* context) {
116 // Check the arguments.
117 CheckSignalValid(sig);
118
119 // The signal must have been claimed in order to get here. Check it.
120 if (!user_sigactions[sig].IsClaimed()) {
121 abort();
122 }
123
124 const struct sigaction& action = user_sigactions[sig].GetAction();
125 if ((action.sa_flags & SA_SIGINFO) == 0) {
126 if (action.sa_handler != NULL) {
127 action.sa_handler(sig);
128 } else {
129 signal(sig, SIG_DFL);
130 raise(sig);
131 }
132 } else {
133 if (action.sa_sigaction != NULL) {
134 action.sa_sigaction(sig, info, context);
135 } else {
136 signal(sig, SIG_DFL);
137 raise(sig);
138 }
139 }
140 }
141
EnsureFrontOfChain(int signal,struct sigaction * expected_action)142 extern "C" void EnsureFrontOfChain(int signal, struct sigaction* expected_action) {
143 CheckSignalValid(signal);
144 // Read the current action without looking at the chain, it should be the expected action.
145 SigActionFnPtr linked_sigaction = reinterpret_cast<SigActionFnPtr>(linked_sigaction_sym);
146 struct sigaction current_action;
147 linked_sigaction(signal, nullptr, ¤t_action);
148 // If the sigactions don't match then we put the current action on the chain and make ourself as
149 // the main action.
150 if (current_action.sa_sigaction != expected_action->sa_sigaction) {
151 log("Warning: Unexpected sigaction action found %p\n", current_action.sa_sigaction);
152 user_sigactions[signal].Claim(current_action);
153 linked_sigaction(signal, expected_action, nullptr);
154 }
155 }
156
157 // These functions are C linkage since they replace the functions in libc.
158
sigaction(int signal,const struct sigaction * new_action,struct sigaction * old_action)159 extern "C" int sigaction(int signal, const struct sigaction* new_action, struct sigaction* old_action) {
160 // If this signal has been claimed as a signal chain, record the user's
161 // action but don't pass it on to the kernel.
162 // Note that we check that the signal number is in range here. An out of range signal
163 // number should behave exactly as the libc sigaction.
164 if (signal > 0 && signal < _NSIG && user_sigactions[signal].IsClaimed()) {
165 struct sigaction saved_action = user_sigactions[signal].GetAction();
166 if (new_action != NULL) {
167 user_sigactions[signal].SetAction(*new_action);
168 }
169 if (old_action != NULL) {
170 *old_action = saved_action;
171 }
172 return 0;
173 }
174
175 // Will only get here if the signal chain has not been claimed. We want
176 // to pass the sigaction on to the kernel via the real sigaction in libc.
177
178 if (linked_sigaction_sym == nullptr) {
179 // Perform lazy initialization.
180 // This will only occur outside of a signal context since we have
181 // not been initialized and therefore cannot be within the ART
182 // runtime.
183 InitializeSignalChain();
184 }
185
186 if (linked_sigaction_sym == nullptr) {
187 log("Unable to find next sigaction in signal chain");
188 abort();
189 }
190 SigActionFnPtr linked_sigaction = reinterpret_cast<SigActionFnPtr>(linked_sigaction_sym);
191 return linked_sigaction(signal, new_action, old_action);
192 }
193
sigprocmask(int how,const sigset_t * bionic_new_set,sigset_t * bionic_old_set)194 extern "C" int sigprocmask(int how, const sigset_t* bionic_new_set, sigset_t* bionic_old_set) {
195 const sigset_t* new_set_ptr = bionic_new_set;
196 sigset_t tmpset;
197 if (bionic_new_set != NULL) {
198 tmpset = *bionic_new_set;
199
200 if (how == SIG_BLOCK) {
201 // Don't allow claimed signals in the mask. If a signal chain has been claimed
202 // we can't allow the user to block that signal.
203 for (int i = 0 ; i < _NSIG; ++i) {
204 if (user_sigactions[i].IsClaimed() && sigismember(&tmpset, i)) {
205 sigdelset(&tmpset, i);
206 }
207 }
208 }
209 new_set_ptr = &tmpset;
210 }
211
212 if (linked_sigprocmask_sym == nullptr) {
213 // Perform lazy initialization.
214 InitializeSignalChain();
215 }
216
217 if (linked_sigprocmask_sym == nullptr) {
218 log("Unable to find next sigprocmask in signal chain");
219 abort();
220 }
221
222 typedef int (*SigProcMask)(int how, const sigset_t*, sigset_t*);
223 SigProcMask linked_sigprocmask= reinterpret_cast<SigProcMask>(linked_sigprocmask_sym);
224 return linked_sigprocmask(how, new_set_ptr, bionic_old_set);
225 }
226
InitializeSignalChain()227 extern "C" void InitializeSignalChain() {
228 // Warning.
229 // Don't call this from within a signal context as it makes calls to
230 // dlsym. Calling into the dynamic linker will result in locks being
231 // taken and if it so happens that a signal occurs while one of these
232 // locks is already taken, dlsym will block trying to reenter a
233 // mutex and we will never get out of it.
234 if (initialized) {
235 // Don't initialize twice.
236 return;
237 }
238 linked_sigaction_sym = dlsym(RTLD_NEXT, "sigaction");
239 if (linked_sigaction_sym == nullptr) {
240 linked_sigaction_sym = dlsym(RTLD_DEFAULT, "sigaction");
241 if (linked_sigaction_sym == nullptr ||
242 linked_sigaction_sym == reinterpret_cast<void*>(sigaction)) {
243 linked_sigaction_sym = nullptr;
244 }
245 }
246
247 linked_sigprocmask_sym = dlsym(RTLD_NEXT, "sigprocmask");
248 if (linked_sigprocmask_sym == nullptr) {
249 linked_sigprocmask_sym = dlsym(RTLD_DEFAULT, "sigprocmask");
250 if (linked_sigprocmask_sym == nullptr ||
251 linked_sigprocmask_sym == reinterpret_cast<void*>(sigprocmask)) {
252 linked_sigprocmask_sym = nullptr;
253 }
254 }
255 initialized = true;
256 }
257 } // namespace art
258
259