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: 41 SignalAction() : claimed_(false) { 42 } 43 44 // Claim the signal and keep the action specified. 45 void Claim(const struct sigaction& action) { 46 action_ = action; 47 claimed_ = true; 48 } 49 50 // Unclaim the signal and restore the old action. 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. 57 const struct sigaction& GetAction() const { 58 return action_; 59 } 60 61 // Is the signal claimed? 62 bool IsClaimed() const { 63 return claimed_; 64 } 65 66 // Change the recorded action to that specified. 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 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 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. 103 extern "C" void ClaimSignalChain(int signal, struct sigaction* oldaction) { 104 CheckSignalValid(signal); 105 user_sigactions[signal].Claim(*oldaction); 106 } 107 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. 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 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 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 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 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