• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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