sigchain.cc revision fabe91e0d558936ac26b98d2b4ee1af08f58831d
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#if defined(__APPLE__) 30#define _NSIG NSIG 31#endif 32 33namespace art { 34 35class SignalAction { 36 public: 37 SignalAction() : claimed_(false) { 38 } 39 40 // Claim the signal and keep the action specified. 41 void Claim(const struct sigaction& action) { 42 action_ = action; 43 claimed_ = true; 44 } 45 46 // Unclaim the signal and restore the old action. 47 void Unclaim(int signal) { 48 claimed_ = false; 49 sigaction(signal, &action_, NULL); // Restore old action. 50 } 51 52 // Get the action associated with this signal. 53 const struct sigaction& GetAction() const { 54 return action_; 55 } 56 57 // Is the signal claimed? 58 bool IsClaimed() const { 59 return claimed_; 60 } 61 62 // Change the recorded action to that specified. 63 void SetAction(const struct sigaction& action) { 64 action_ = action; 65 } 66 67 private: 68 struct sigaction action_; // Action to be performed. 69 bool claimed_; // Whether signal is claimed or not. 70}; 71 72// User's signal handlers 73static SignalAction user_sigactions[_NSIG]; 74 75static void log(const char* format, ...) { 76 char buf[256]; 77 va_list ap; 78 va_start(ap, format); 79 vsnprintf(buf, sizeof(buf), format, ap); 80#ifdef HAVE_ANDROID_OS 81 __android_log_write(ANDROID_LOG_ERROR, "libsigchain", buf); 82#else 83 std::cout << buf << "\n"; 84#endif 85 va_end(ap); 86} 87 88static void CheckSignalValid(int signal) { 89 if (signal <= 0 || signal >= _NSIG) { 90 log("Invalid signal %d", signal); 91 abort(); 92 } 93} 94 95// Claim a signal chain for a particular signal. 96void ClaimSignalChain(int signal, struct sigaction* oldaction) { 97 CheckSignalValid(signal); 98 user_sigactions[signal].Claim(*oldaction); 99} 100 101void UnclaimSignalChain(int signal) { 102 CheckSignalValid(signal); 103 104 user_sigactions[signal].Unclaim(signal); 105} 106 107// Invoke the user's signal handler. 108void InvokeUserSignalHandler(int sig, siginfo_t* info, void* context) { 109 // Check the arguments. 110 CheckSignalValid(sig); 111 112 // The signal must have been claimed in order to get here. Check it. 113 if (!user_sigactions[sig].IsClaimed()) { 114 abort(); 115 } 116 117 const struct sigaction& action = user_sigactions[sig].GetAction(); 118 if ((action.sa_flags & SA_SIGINFO) == 0) { 119 if (action.sa_handler != NULL) { 120 action.sa_handler(sig); 121 } else { 122 signal(sig, SIG_DFL); 123 raise(sig); 124 } 125 } else { 126 if (action.sa_sigaction != NULL) { 127 action.sa_sigaction(sig, info, context); 128 } else { 129 signal(sig, SIG_DFL); 130 raise(sig); 131 } 132 } 133} 134 135extern "C" { 136// These functions are C linkage since they replace the functions in libc. 137 138int sigaction(int signal, const struct sigaction* new_action, struct sigaction* old_action) { 139 // If this signal has been claimed as a signal chain, record the user's 140 // action but don't pass it on to the kernel. 141 // Note that we check that the signal number is in range here. An out of range signal 142 // number should behave exactly as the libc sigaction. 143 if (signal > 0 && signal < _NSIG && user_sigactions[signal].IsClaimed()) { 144 if (old_action != NULL) { 145 *old_action = user_sigactions[signal].GetAction(); 146 } 147 if (new_action != NULL) { 148 user_sigactions[signal].SetAction(*new_action); 149 } 150 return 0; 151 } 152 153 // Will only get here if the signal chain has not been claimed. We want 154 // to pass the sigaction on to the kernel via the real sigaction in libc. 155 156 void* linked_sigaction_sym = dlsym(RTLD_NEXT, "sigaction"); 157 if (linked_sigaction_sym == nullptr) { 158 linked_sigaction_sym = dlsym(RTLD_DEFAULT, "sigaction"); 159 if (linked_sigaction_sym == nullptr || 160 linked_sigaction_sym == reinterpret_cast<void*>(sigaction)) { 161 log("Unable to find next sigaction in signal chain"); 162 abort(); 163 } 164 } 165 166 typedef int (*SigAction)(int, const struct sigaction*, struct sigaction*); 167 SigAction linked_sigaction = reinterpret_cast<SigAction>(linked_sigaction_sym); 168 return linked_sigaction(signal, new_action, old_action); 169} 170 171int sigprocmask(int how, const sigset_t* bionic_new_set, sigset_t* bionic_old_set) { 172 const sigset_t* new_set_ptr = bionic_new_set; 173 sigset_t tmpset; 174 if (bionic_new_set != NULL) { 175 tmpset = *bionic_new_set; 176 177 if (how == SIG_BLOCK) { 178 // Don't allow claimed signals in the mask. If a signal chain has been claimed 179 // we can't allow the user to block that signal. 180 for (int i = 0 ; i < _NSIG; ++i) { 181 if (user_sigactions[i].IsClaimed() && sigismember(&tmpset, i)) { 182 sigdelset(&tmpset, i); 183 } 184 } 185 } 186 new_set_ptr = &tmpset; 187 } 188 189 void* linked_sigprocmask_sym = dlsym(RTLD_NEXT, "sigprocmask"); 190 if (linked_sigprocmask_sym == nullptr) { 191 linked_sigprocmask_sym = dlsym(RTLD_DEFAULT, "sigprocmask"); 192 if (linked_sigprocmask_sym == nullptr || 193 linked_sigprocmask_sym == reinterpret_cast<void*>(sigprocmask)) { 194 log("Unable to find next sigprocmask in signal chain"); 195 abort(); 196 } 197 } 198 199 typedef int (*SigProcMask)(int how, const sigset_t*, sigset_t*); 200 SigProcMask linked_sigprocmask= reinterpret_cast<SigProcMask>(linked_sigprocmask_sym); 201 return linked_sigprocmask(how, new_set_ptr, bionic_old_set); 202} 203} // extern "C" 204} // namespace art 205 206