1 /*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "sighook.h"
17
18 #include "utils/logger.h"
19 #include <dlfcn.h>
20 #include <errno.h> // NOLINTNEXTLINE(modernize-deprecated-headers)
21 #include <signal.h> // NOLINTNEXTLINE(modernize-deprecated-headers)
22 #include <stdio.h> // NOLINTNEXTLINE(modernize-deprecated-headers)
23 #include <stdlib.h> // NOLINTNEXTLINE(modernize-deprecated-headers)
24 #include <string.h> // NOLINTNEXTLINE(modernize-deprecated-headers)
25 #include <array>
26
27 #include <algorithm>
28 #include <initializer_list>
29 #include <os/mutex.h>
30 #include <type_traits>
31 #include <utility>
32 #include <unistd.h>
33
34 #include <securec.h>
35 #include <ucontext.h>
36
37 namespace panda {
38
39 static decltype(&sigaction) real_sigaction;
40 static decltype(&sigprocmask) real_sigprocmask;
41 static bool g_is_init_really {false};
42 static bool g_is_init_key_create {false};
43 // NOLINTNEXTLINE(fuchsia-statically-constructed-objects)
44 #if PANDA_TARGET_MACOS
45 __attribute__((init_priority(101))) static os::memory::Mutex real_lock;
46 #else
47 // NOLINTNEXTLINE(fuchsia-statically-constructed-objects)
48 static os::memory::Mutex real_lock;
49 #endif
50 // NOLINTNEXTLINE(fuchsia-statically-constructed-objects)
51 static os::memory::Mutex key_create_lock;
52
GetHandlingSignalKey()53 static os::memory::PandaThreadKey GetHandlingSignalKey()
54 {
55 static os::memory::PandaThreadKey key;
56 {
57 os::memory::LockHolder lock(key_create_lock);
58 if (!g_is_init_key_create) {
59 int rc = os::memory::PandaThreadKeyCreate(&key, nullptr);
60 if (rc != 0) {
61 LOG(FATAL, RUNTIME) << "Failed to create sigchain thread key: " << os::Error(rc).ToString();
62 }
63 g_is_init_key_create = true;
64 }
65 }
66 return key;
67 }
68
GetHandlingSignal()69 static bool GetHandlingSignal()
70 {
71 void *result = os::memory::PandaGetspecific(GetHandlingSignalKey());
72 return reinterpret_cast<uintptr_t>(result) != 0;
73 }
74
SetHandlingSignal(bool value)75 static void SetHandlingSignal(bool value)
76 {
77 os::memory::PandaSetspecific(GetHandlingSignalKey(), reinterpret_cast<void *>(static_cast<uintptr_t>(value)));
78 }
79
80 class SignalHook {
81 public:
82 SignalHook() = default;
83
84 ~SignalHook() = default;
85
86 NO_COPY_SEMANTIC(SignalHook);
87 NO_MOVE_SEMANTIC(SignalHook);
88
IsHook() const89 bool IsHook() const
90 {
91 return is_hook_;
92 }
93
HookSig(int signo)94 void HookSig(int signo)
95 {
96 if (!is_hook_) {
97 RegisterAction(signo);
98 is_hook_ = true;
99 }
100 }
101
RegisterAction(int signo)102 void RegisterAction(int signo)
103 {
104 struct sigaction handler_action = {};
105 sigfillset(&handler_action.sa_mask);
106 // SIGSEGV from signal handler must be handled as well
107 sigdelset(&handler_action.sa_mask, SIGSEGV);
108
109 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-union-access)
110 handler_action.sa_sigaction = SignalHook::Handler;
111 // SA_NODEFER+: do not block signals from the signal handler
112 // SA_ONSTACK-: call signal handler on the same stack
113 // NOLINTNEXTLINE(hicpp-signed-bitwise)
114 handler_action.sa_flags = SA_RESTART | SA_SIGINFO | SA_NODEFER;
115 real_sigaction(signo, nullptr, &old_action_);
116 real_sigaction(signo, &handler_action, &user_action_);
117 }
118
RegisterHookAction(const SighookAction * sa)119 void RegisterHookAction(const SighookAction *sa)
120 {
121 for (SighookAction &handler : hook_action_handlers_) {
122 if (handler.sc_sigaction == nullptr) {
123 handler = *sa;
124 return;
125 }
126 }
127 LOG(FATAL, RUNTIME) << "Failed to register hook action, too many handlers";
128 }
129
RegisterUserAction(const struct sigaction * new_action)130 void RegisterUserAction(const struct sigaction *new_action)
131 {
132 user_action_register_ = true;
133 if constexpr (std::is_same_v<decltype(user_action_), struct sigaction>) {
134 user_action_ = *new_action;
135 } else {
136 user_action_.sa_flags = new_action->sa_flags; // NOLINT
137 user_action_.sa_handler = new_action->sa_handler; // NOLINT
138 #if defined(SA_RESTORER)
139 user_action_.sa_restorer = new_action->sa_restorer; // NOLINT
140 #endif
141 sigemptyset(&user_action_.sa_mask);
142 (void)memcpy_s(&user_action_.sa_mask, sizeof(user_action_.sa_mask), &new_action->sa_mask,
143 std::min(sizeof(user_action_.sa_mask), sizeof(new_action->sa_mask)));
144 }
145 }
146
GetUserAction() const147 struct sigaction GetUserAction() const
148 {
149 if constexpr (std::is_same_v<decltype(user_action_), struct sigaction>) {
150 return user_action_;
151 } else {
152 struct sigaction result {
153 };
154 result.sa_flags = user_action_.sa_flags; // NOLINT
155 result.sa_handler = user_action_.sa_handler; // NOLINT
156 #if defined(SA_RESTORER)
157 result.sa_restorer = user_action_.sa_restorer;
158 #endif
159 (void)memcpy_s(&result.sa_mask, sizeof(result.sa_mask), &user_action_.sa_mask,
160 std::min(sizeof(user_action_.sa_mask), sizeof(result.sa_mask)));
161 return result;
162 }
163 }
164
165 static void Handler(int signo, siginfo_t *siginfo, void *ucontext_raw);
166 static void CallOldAction(int signo, siginfo_t *siginfo, void *ucontext_raw);
167
RemoveHookAction(bool (* action)(int,siginfo_t *,void *))168 void RemoveHookAction(bool (*action)(int, siginfo_t *, void *))
169 {
170 for (size_t i = 0; i < HOOK_LENGTH; ++i) {
171 if (hook_action_handlers_[i].sc_sigaction == action) {
172 for (size_t j = i; j < HOOK_LENGTH - 1; ++j) {
173 hook_action_handlers_[j] = hook_action_handlers_[j + 1];
174 }
175 hook_action_handlers_[HOOK_LENGTH - 1].sc_sigaction = nullptr;
176 return;
177 }
178 }
179 LOG(FATAL, RUNTIME) << "Failed to find removed hook handler";
180 }
181
IsUserActionRegister() const182 bool IsUserActionRegister() const
183 {
184 return user_action_register_;
185 }
186
ClearHookActionHandlers()187 void ClearHookActionHandlers()
188 {
189 for (SighookAction &handler : hook_action_handlers_) {
190 handler.sc_sigaction = nullptr;
191 }
192 }
193
194 private:
195 static bool SetHandlingSignal(int signo, siginfo_t *siginfo, void *ucontext_raw);
196
197 constexpr static const int HOOK_LENGTH = 2;
198 bool is_hook_ {false};
199 std::array<SighookAction, HOOK_LENGTH> hook_action_handlers_ {};
200 struct sigaction user_action_ {
201 };
202 struct sigaction old_action_ = {};
203 bool user_action_register_ {false};
204 };
205
206 static std::array<SignalHook, _NSIG + 1> signal_hooks;
207
CallOldAction(int signo,siginfo_t * siginfo,void * ucontext_raw)208 void SignalHook::CallOldAction(int signo, siginfo_t *siginfo, void *ucontext_raw)
209 {
210 auto handler_flags = static_cast<size_t>(signal_hooks[signo].old_action_.sa_flags);
211 sigset_t mask = signal_hooks[signo].old_action_.sa_mask;
212 real_sigprocmask(SIG_SETMASK, &mask, nullptr);
213
214 if ((handler_flags & SA_SIGINFO)) { // NOLINT
215 signal_hooks[signo].old_action_.sa_sigaction(signo, siginfo, ucontext_raw); // NOLINT
216 } else {
217 if (signal_hooks[signo].old_action_.sa_handler == nullptr) { // NOLINT
218 real_sigaction(signo, &signal_hooks[signo].old_action_, nullptr);
219 kill(getpid(), signo); // Send signal again
220 return;
221 }
222 signal_hooks[signo].old_action_.sa_handler(signo); // NOLINT
223 }
224 }
225
SetHandlingSignal(int signo,siginfo_t * siginfo,void * ucontext_raw)226 bool SignalHook::SetHandlingSignal(int signo, siginfo_t *siginfo, void *ucontext_raw)
227 {
228 for (const auto &handler : signal_hooks[signo].hook_action_handlers_) {
229 if (handler.sc_sigaction == nullptr) {
230 break;
231 }
232
233 bool handler_noreturn = ((handler.sc_flags & SIGHOOK_ALLOW_NORETURN) != 0);
234 sigset_t previous_mask;
235 real_sigprocmask(SIG_SETMASK, &handler.sc_mask, &previous_mask);
236
237 bool old_handle_key = GetHandlingSignal();
238 if (!handler_noreturn) {
239 ::panda::SetHandlingSignal(true);
240 }
241 if (handler.sc_sigaction(signo, siginfo, ucontext_raw)) {
242 ::panda::SetHandlingSignal(old_handle_key);
243 return false;
244 }
245
246 real_sigprocmask(SIG_SETMASK, &previous_mask, nullptr);
247 ::panda::SetHandlingSignal(old_handle_key);
248 }
249
250 return true;
251 }
252
Handler(int signo,siginfo_t * siginfo,void * ucontext_raw)253 void SignalHook::Handler(int signo, siginfo_t *siginfo, void *ucontext_raw)
254 {
255 if (!GetHandlingSignal()) {
256 if (!SetHandlingSignal(signo, siginfo, ucontext_raw)) {
257 return;
258 }
259 }
260
261 // If not set user handler, call linker handler
262 if (!signal_hooks[signo].IsUserActionRegister()) {
263 CallOldAction(signo, siginfo, ucontext_raw);
264 return;
265 }
266
267 // Call user handler
268 auto handler_flags = static_cast<size_t>(signal_hooks[signo].user_action_.sa_flags);
269 auto *ucontext = static_cast<ucontext_t *>(ucontext_raw);
270 sigset_t mask;
271 sigemptyset(&mask);
272 constexpr size_t N = sizeof(sigset_t) * 2;
273 for (size_t i = 0; i < N; ++i) {
274 if (sigismember(&ucontext->uc_sigmask, i) == 1 ||
275 sigismember(&signal_hooks[signo].user_action_.sa_mask, i) == 1) {
276 sigaddset(&mask, i);
277 }
278 }
279
280 if ((handler_flags & SA_NODEFER) == 0) { // NOLINT
281 sigaddset(&mask, signo);
282 }
283 real_sigprocmask(SIG_SETMASK, &mask, nullptr);
284
285 if ((handler_flags & SA_SIGINFO)) { // NOLINT
286 signal_hooks[signo].user_action_.sa_sigaction(signo, siginfo, ucontext_raw); // NOLINT
287 } else {
288 auto handler = signal_hooks[signo].user_action_.sa_handler; // NOLINT
289 if (handler == SIG_IGN) { // NOLINT
290 return;
291 }
292 if (handler == SIG_DFL) { // NOLINT
293 LOG(FATAL, RUNTIME) << "Actually signal:" << signo << " | register sigaction's handler == SIG_DFL";
294 }
295 handler(signo);
296 }
297
298 // If user handler does not exit, continue to call Old Action
299 CallOldAction(signo, siginfo, ucontext_raw);
300 }
301
302 template <typename Sigaction>
FindRealSignal(Sigaction * real_fun,Sigaction hook_fun,const char * name)303 static bool FindRealSignal(Sigaction *real_fun, [[maybe_unused]] Sigaction hook_fun, const char *name)
304 {
305 void *find_fun = dlsym(RTLD_NEXT, name);
306 if (find_fun != nullptr) {
307 *real_fun = reinterpret_cast<Sigaction>(find_fun);
308 } else {
309 find_fun = dlsym(RTLD_DEFAULT, name);
310 if (find_fun == nullptr || reinterpret_cast<uintptr_t>(find_fun) == reinterpret_cast<uintptr_t>(hook_fun) ||
311 reinterpret_cast<uintptr_t>(find_fun) == reinterpret_cast<uintptr_t>(sigaction)) {
312 LOG(ERROR, RUNTIME) << "dlsym(RTLD_DEFAULT, " << name << ") can not find really " << name;
313 return false;
314 }
315 *real_fun = reinterpret_cast<Sigaction>(find_fun);
316 }
317 LOG(INFO, RUNTIME) << "Find " << name << " success";
318 return true;
319 }
320
321 #if PANDA_TARGET_MACOS
InitRealSignalFun()322 __attribute__((constructor(102))) static bool InitRealSignalFun()
323 #else
324 __attribute__((constructor)) static bool InitRealSignalFun()
325 #endif
326 {
327 {
328 os::memory::LockHolder lock(real_lock);
329 if (!g_is_init_really) {
330 bool is_error = true;
331 is_error = is_error && FindRealSignal(&real_sigaction, sigaction, "sigaction");
332 is_error = is_error && FindRealSignal(&real_sigprocmask, sigprocmask, "sigprocmask");
333 if (is_error) {
334 g_is_init_really = true;
335 }
336 return is_error;
337 }
338 }
339 return true;
340 }
341
342 // NOLINTNEXTLINE(readability-identifier-naming)
RegisterUserHandler(int signal,const struct sigaction * new_action,struct sigaction * old_action,int (* really)(int,const struct sigaction *,struct sigaction *))343 static int RegisterUserHandler(int signal, const struct sigaction *new_action, struct sigaction *old_action,
344 int (*really)(int, const struct sigaction *, struct sigaction *))
345 {
346 // Just hook signal in range, otherwise use libc sigaction
347 if (signal <= 0 || signal >= _NSIG) {
348 LOG(ERROR, RUNTIME) << "Illegal signal " << signal;
349 return -1;
350 }
351
352 if (signal_hooks[signal].IsHook()) {
353 auto user_action = signal_hooks[signal].SignalHook::GetUserAction();
354 if (new_action != nullptr) {
355 signal_hooks[signal].RegisterUserAction(new_action);
356 }
357 if (old_action != nullptr) {
358 *old_action = user_action;
359 }
360 return 0;
361 }
362
363 return really(signal, new_action, old_action);
364 }
365
RegisterUserMask(int how,const sigset_t * new_set,sigset_t * old_set,int (* really)(int,const sigset_t *,sigset_t *))366 int RegisterUserMask(int how, const sigset_t *new_set, sigset_t *old_set,
367 int (*really)(int, const sigset_t *, sigset_t *))
368 {
369 if (GetHandlingSignal()) {
370 return really(how, new_set, old_set);
371 }
372
373 if (new_set == nullptr) {
374 return really(how, new_set, old_set);
375 }
376
377 sigset_t build_sigset = *new_set;
378 if (how == SIG_BLOCK || how == SIG_SETMASK) {
379 for (int i = 1; i < _NSIG; ++i) {
380 if (signal_hooks[i].IsHook() && (sigismember(&build_sigset, i) != 0)) {
381 sigdelset(&build_sigset, i);
382 }
383 }
384 }
385 const sigset_t *build_sigset_const = &build_sigset;
386 return really(how, build_sigset_const, old_set);
387 }
388
389 // NOTE: issue #2681
390 // Using ADDRESS_SANITIZER will expose a bug. Try to define 'sigaction' which will make SIGSEGV happen
391 #ifdef USE_ADDRESS_SANITIZER
392 // NOLINTNEXTLINE(readability-identifier-naming)
sigaction(int __sig,const struct sigaction * __restrict __act,struct sigaction * __oact)393 extern "C" int sigaction([[maybe_unused]] int __sig, [[maybe_unused]] const struct sigaction *__restrict __act,
394 [[maybe_unused]] struct sigaction *__oact) // NOLINT(readability-identifier-naming)
395 {
396 if (!InitRealSignalFun()) {
397 return -1;
398 }
399 return RegisterUserHandler(__sig, __act, __oact, real_sigaction);
400 }
401 #else
402 // NOLINTNEXTLINE(readability-identifier-naming)
sigactionStub(int __sig,const struct sigaction * __restrict __act,struct sigaction * __oact)403 extern "C" int sigactionStub([[maybe_unused]] int __sig, [[maybe_unused]] const struct sigaction *__restrict __act,
404 [[maybe_unused]] struct sigaction *__oact) // NOLINT(readability-identifier-naming)
405 {
406 if (!InitRealSignalFun()) {
407 return -1;
408 }
409 return RegisterUserHandler(__sig, __act, __oact, real_sigaction);
410 }
411 #endif // USE_ADDRESS_SANITIZER
412
413 // NOLINTNEXTLINE(readability-identifier-naming)
sigprocmask(int how,const sigset_t * new_set,sigset_t * old_set)414 extern "C" int sigprocmask(int how, const sigset_t *new_set, sigset_t *old_set) // NOLINT
415 {
416 if (!InitRealSignalFun()) {
417 return -1;
418 }
419 return RegisterUserMask(how, new_set, old_set, real_sigprocmask);
420 }
421
RegisterHookHandler(int signal,const SighookAction * sa)422 extern "C" void RegisterHookHandler(int signal, const SighookAction *sa)
423 {
424 if (!InitRealSignalFun()) {
425 return;
426 }
427
428 if (signal <= 0 || signal >= _NSIG) {
429 LOG(FATAL, RUNTIME) << "Illegal signal " << signal;
430 }
431
432 signal_hooks[signal].RegisterHookAction(sa);
433 signal_hooks[signal].HookSig(signal);
434 }
435
RemoveHookHandler(int signal,bool (* action)(int,siginfo_t *,void *))436 extern "C" void RemoveHookHandler(int signal, bool (*action)(int, siginfo_t *, void *))
437 {
438 if (!InitRealSignalFun()) {
439 return;
440 }
441
442 if (signal <= 0 || signal >= _NSIG) {
443 LOG(FATAL, RUNTIME) << "Illegal signal " << signal;
444 }
445
446 signal_hooks[signal].RemoveHookAction(action);
447 }
448
CheckOldHookHandler(int signal)449 extern "C" void CheckOldHookHandler(int signal)
450 {
451 if (!InitRealSignalFun()) {
452 return;
453 }
454
455 if (signal <= 0 || signal >= _NSIG) {
456 LOG(FATAL, RUNTIME) << "Illegal signal " << signal;
457 }
458
459 // Get old action
460 struct sigaction old_action {
461 };
462 real_sigaction(signal, nullptr, &old_action);
463
464 if (old_action.sa_sigaction != SignalHook::Handler) { // NOLINT
465 LOG(ERROR, RUNTIME) << "Error: check old hook handler found unexpected action "
466 << (old_action.sa_sigaction != nullptr); // NOLINT
467 signal_hooks[signal].RegisterAction(signal);
468 }
469 }
470
AddSpecialSignalHandlerFn(int signal,SigchainAction * sa)471 extern "C" void AddSpecialSignalHandlerFn(int signal, SigchainAction *sa)
472 {
473 LOG(DEBUG, RUNTIME) << "Panda sighook RegisterHookHandler is used, signal:" << signal << " action:" << sa;
474 RegisterHookHandler(signal, reinterpret_cast<SighookAction *>(sa));
475 }
476
RemoveSpecialSignalHandlerFn(int signal,bool (* fn)(int,siginfo_t *,void *))477 extern "C" void RemoveSpecialSignalHandlerFn(int signal, bool (*fn)(int, siginfo_t *, void *))
478 {
479 LOG(DEBUG, RUNTIME) << "Panda sighook RemoveHookHandler is used, signal:"
480 << "sigaction";
481 RemoveHookHandler(signal, fn);
482 }
483
EnsureFrontOfChain(int signal)484 extern "C" void EnsureFrontOfChain(int signal)
485 {
486 LOG(DEBUG, RUNTIME) << "Panda sighook CheckOldHookHandler is used, signal:" << signal;
487 CheckOldHookHandler(signal);
488 }
489
ClearSignalHooksHandlersArray()490 void ClearSignalHooksHandlersArray()
491 {
492 g_is_init_really = false;
493 g_is_init_key_create = false;
494 for (int i = 1; i < _NSIG; i++) {
495 signal_hooks[i].ClearHookActionHandlers();
496 }
497 }
498
499 } // namespace panda
500