• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2022 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 "utils/logger.h"
17 #include <dlfcn.h>
18 
19 #include <array>
20 #include <algorithm>
21 #include <cerrno>
22 #include <csignal>
23 #include <cstdio>
24 #include <cstdlib>
25 #include <cstring>
26 #include <initializer_list>
27 #include <os/mutex.h>
28 #include <type_traits>
29 #include <utility>
30 #include <unistd.h>
31 
32 #include "os/sighook.h"
33 
34 #include <securec.h>
35 #include <ucontext.h>
36 
37 namespace panda {
38 
39 static decltype(&sigaction) g_realSigaction;
40 static decltype(&sigprocmask) g_realSigProcMask;
41 static bool g_isInitReally {false};
42 static bool g_isInitKeyCreate {false};
43 // NOLINTNEXTLINE(fuchsia-statically-constructed-objects)
44 #if PANDA_TARGET_MACOS
45 __attribute__((init_priority(101))) static os::memory::Mutex g_realLock;
46 #else
47 // NOLINTNEXTLINE(fuchsia-statically-constructed-objects)
48 static os::memory::Mutex g_realLock;
49 #endif
50 // NOLINTNEXTLINE(fuchsia-statically-constructed-objects)
51 static os::memory::Mutex g_keyCreateLock;
52 
GetHandlingSignalKey()53 static os::memory::PandaThreadKey GetHandlingSignalKey()
54 {
55     static os::memory::PandaThreadKey key;
56     {
57         os::memory::LockHolder lock(g_keyCreateLock);
58         if (!g_isInitKeyCreate) {
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_isInitKeyCreate = true;
64         }
65     }
66     return key;
67 }
68 
GetHandlingSignal()69 static bool GetHandlingSignal()
70 {
71     void *result = os::memory::PandaGetspecific(GetHandlingSignalKey());
72     return result != nullptr;
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()89     bool IsHook()
90     {
91         return isHook_;
92     }
93 
HookSig(int signo)94     void HookSig(int signo)
95     {
96         if (!isHook_) {
97             RegisterAction(signo);
98             isHook_ = true;
99         }
100     }
101 
RegisterAction(int signo)102     void RegisterAction(int signo)
103     {
104         struct sigaction handlerAction = {};
105         sigfillset(&handlerAction.sa_mask);
106         // SIGSEGV from signal handler must be handled as well
107         sigdelset(&handlerAction.sa_mask, SIGSEGV);
108 
109         // NOLINTNEXTLINE(cppcoreguidelines-pro-type-union-access)
110         handlerAction.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         handlerAction.sa_flags = SA_RESTART | SA_SIGINFO | SA_NODEFER;
115         g_realSigaction(signo, nullptr, &oldAction_);
116         g_realSigaction(signo, &handlerAction, &userAction_);
117     }
118 
RegisterHookAction(const SighookAction * sa)119     void RegisterHookAction(const SighookAction *sa)
120     {
121         for (SighookAction &handler : hookActionHandlers_) {
122             if (handler.scSigaction == nullptr) {
123                 handler = *sa;
124                 return;
125             }
126         }
127         LOG(FATAL, RUNTIME) << "failed to Register Hook Action, too much handlers";
128     }
129 
RegisterUserAction(const struct sigaction * newAction)130     void RegisterUserAction(const struct sigaction *newAction)
131     {
132         userActionRegister_ = true;
133         if constexpr (std::is_same_v<decltype(userAction_), struct sigaction>) {
134             userAction_ = *newAction;
135         } else {
136             userAction_.sa_flags = newAction->sa_flags;      // NOLINT
137             userAction_.sa_handler = newAction->sa_handler;  // NOLINT
138 #if defined(SA_RESTORER)
139             userAction_.sa_restorer = newAction->sa_restorer;  // NOLINT
140 #endif
141             sigemptyset(&userAction_.sa_mask);
142             memcpy_s(&userAction_.sa_mask, sizeof(userAction_.sa_mask), &newAction->sa_mask,
143                      std::min(sizeof(userAction_.sa_mask), sizeof(newAction->sa_mask)));
144         }
145     }
146 
GetUserAction()147     struct sigaction GetUserAction()
148     {
149         if constexpr (std::is_same_v<decltype(userAction_), struct sigaction>) {
150             return userAction_;
151         } else {
152             struct sigaction result {};
153             result.sa_flags = userAction_.sa_flags;      // NOLINT
154             result.sa_handler = userAction_.sa_handler;  // NOLINT
155 #if defined(SA_RESTORER)
156             result.sa_restorer = userAction_.sa_restorer;
157 #endif
158             memcpy_s(&result.sa_mask, sizeof(result.sa_mask), &userAction_.sa_mask,
159                      std::min(sizeof(userAction_.sa_mask), sizeof(result.sa_mask)));
160             return result;
161         }
162     }
163 
164     static void Handler(int signo, siginfo_t *siginfo, void *ucontextRaw);
165     static void CallOldAction(int signo, siginfo_t *siginfo, void *ucontextRaw);
166 
RemoveHookAction(bool (* action)(int,siginfo_t *,void *))167     void RemoveHookAction(bool (*action)(int, siginfo_t *, void *))
168     {
169         // no thread safe
170         for (size_t i = 0; i < HOOK_LENGTH; ++i) {
171             if (hookActionHandlers_[i].scSigaction == action) {
172                 for (size_t j = i; j < HOOK_LENGTH - 1; ++j) {
173                     hookActionHandlers_[j] = hookActionHandlers_[j + 1];
174                 }
175                 hookActionHandlers_[HOOK_LENGTH - 1].scSigaction = nullptr;
176                 return;
177             }
178         }
179         LOG(FATAL, RUNTIME) << "failed to find remove hook handler";
180     }
181 
IsUserActionRegister()182     bool IsUserActionRegister()
183     {
184         return userActionRegister_;
185     }
186 
ClearHookActionHandlers()187     void ClearHookActionHandlers()
188     {
189         for (SighookAction &handler : hookActionHandlers_) {
190             handler.scSigaction = nullptr;
191         }
192     }
193 
194 private:
195     static bool SetHandlingSignal(int signo, siginfo_t *siginfo, void *ucontextRaw);
196 
197     constexpr static const int HOOK_LENGTH = 2;
198     bool isHook_ {false};
199     std::array<SighookAction, HOOK_LENGTH> hookActionHandlers_ {};
200     struct sigaction userAction_ {};
201     struct sigaction oldAction_ = {};
202     bool userActionRegister_ {false};
203 };
204 
205 static std::array<SignalHook, _NSIG + 1> g_signalHooks;
206 
CallOldAction(int signo,siginfo_t * siginfo,void * ucontextRaw)207 void SignalHook::CallOldAction(int signo, siginfo_t *siginfo, void *ucontextRaw)
208 {
209     auto handlerFlags = static_cast<size_t>(g_signalHooks[signo].oldAction_.sa_flags);
210     sigset_t mask = g_signalHooks[signo].oldAction_.sa_mask;
211     g_realSigProcMask(SIG_SETMASK, &mask, nullptr);
212 
213     if ((handlerFlags & SA_SIGINFO)) {                                              // NOLINT
214         g_signalHooks[signo].oldAction_.sa_sigaction(signo, siginfo, ucontextRaw);  // NOLINT
215     } else {
216         if (g_signalHooks[signo].oldAction_.sa_handler == nullptr) {  // NOLINT
217             g_realSigaction(signo, &g_signalHooks[signo].oldAction_, nullptr);
218             kill(getpid(), signo);  // send signal again
219             return;
220         }
221         g_signalHooks[signo].oldAction_.sa_handler(signo);  // NOLINT
222     }
223 }
224 
SetHandlingSignal(int signo,siginfo_t * siginfo,void * ucontextRaw)225 bool SignalHook::SetHandlingSignal(int signo, siginfo_t *siginfo, void *ucontextRaw)
226 {
227     for (const auto &handler : g_signalHooks[signo].hookActionHandlers_) {
228         if (handler.scSigaction == nullptr) {
229             break;
230         }
231 
232         bool handlerNoreturn = ((handler.scFlags & SIGHOOK_ALLOW_NORETURN) != 0);
233         sigset_t previousMask;
234         g_realSigProcMask(SIG_SETMASK, &handler.scMask, &previousMask);
235 
236         bool oldHandleKey = GetHandlingSignal();
237         if (!handlerNoreturn) {
238             ::panda::SetHandlingSignal(true);
239         }
240         if (handler.scSigaction(signo, siginfo, ucontextRaw)) {
241             ::panda::SetHandlingSignal(oldHandleKey);
242             return false;
243         }
244 
245         g_realSigProcMask(SIG_SETMASK, &previousMask, nullptr);
246         ::panda::SetHandlingSignal(oldHandleKey);
247     }
248 
249     return true;
250 }
251 
Handler(int signo,siginfo_t * siginfo,void * ucontextRaw)252 void SignalHook::Handler(int signo, siginfo_t *siginfo, void *ucontextRaw)
253 {
254     if (!GetHandlingSignal()) {
255         if (!SetHandlingSignal(signo, siginfo, ucontextRaw)) {
256             return;
257         }
258     }
259 
260     // if not set user handler,call linker handler
261     if (!g_signalHooks[signo].IsUserActionRegister()) {
262         CallOldAction(signo, siginfo, ucontextRaw);
263         return;
264     }
265 
266     // call user handler
267     auto handlerFlags = static_cast<size_t>(g_signalHooks[signo].userAction_.sa_flags);
268     auto *ucontext = static_cast<ucontext_t *>(ucontextRaw);
269     sigset_t mask;
270     sigemptyset(&mask);
271     constexpr int N = sizeof(sigset_t) * 2;
272     for (int i = 0; i < N; ++i) {
273         if (sigismember(&ucontext->uc_sigmask, i) == 1 ||
274             sigismember(&g_signalHooks[signo].userAction_.sa_mask, i) == 1) {
275             sigaddset(&mask, i);
276         }
277     }
278 
279     if ((handlerFlags & SA_NODEFER) == 0) {  // NOLINT
280         sigaddset(&mask, signo);
281     }
282     g_realSigProcMask(SIG_SETMASK, &mask, nullptr);
283 
284     if ((handlerFlags & SA_SIGINFO)) {                                               // NOLINT
285         g_signalHooks[signo].userAction_.sa_sigaction(signo, siginfo, ucontextRaw);  // NOLINT
286     } else {
287         auto handler = g_signalHooks[signo].userAction_.sa_handler;  // NOLINT
288         if (handler == SIG_IGN) {                                    // NOLINT
289             return;
290         }
291         if (handler == SIG_DFL) {  // NOLINT
292             LOG(FATAL, RUNTIME) << "Actually signal:" << signo << " | register sigaction's handler == SIG_DFL";
293         }
294         handler(signo);
295     }
296 
297     // if user handler not exit, continue call Old Action
298     CallOldAction(signo, siginfo, ucontextRaw);
299 }
300 
301 template <typename Sigaction>
FindRealSignal(Sigaction * realFun,Sigaction hookFun,const char * name)302 static bool FindRealSignal(Sigaction *realFun, [[maybe_unused]] Sigaction hookFun, const char *name)
303 {
304     void *findFun = dlsym(RTLD_NEXT, name);
305     if (findFun != nullptr) {
306         *realFun = reinterpret_cast<Sigaction>(findFun);
307     } else {
308         findFun = dlsym(RTLD_DEFAULT, name);
309         if (findFun == nullptr || reinterpret_cast<uintptr_t>(findFun) == reinterpret_cast<uintptr_t>(hookFun) ||
310             reinterpret_cast<uintptr_t>(findFun) == reinterpret_cast<uintptr_t>(sigaction)) {
311             LOG(ERROR, RUNTIME) << "dlsym(RTLD_DEFAULT, " << name << ") can not find really " << name;
312             return false;
313         }
314         *realFun = reinterpret_cast<Sigaction>(findFun);
315     }
316     LOG(INFO, RUNTIME) << "find " << name << " success";
317     return true;
318 }
319 
320 #if PANDA_TARGET_MACOS
InitRealSignalFun()321 __attribute__((constructor(102))) static bool InitRealSignalFun()
322 #else
323 __attribute__((constructor)) static bool InitRealSignalFun()
324 #endif
325 {
326     {
327         os::memory::LockHolder lock(g_realLock);
328         if (!g_isInitReally) {
329             bool isError = true;
330             isError = isError && FindRealSignal(&g_realSigaction, sigaction, "sigaction");
331             isError = isError && FindRealSignal(&g_realSigProcMask, sigprocmask, "sigprocmask");
332             if (isError) {
333                 g_isInitReally = true;
334             }
335             return isError;
336         }
337     }
338     return true;
339 }
340 
341 // NOLINTNEXTLINE(readability-identifier-naming)
RegisterUserHandler(int signal,const struct sigaction * newAction,struct sigaction * oldAction,int (* really)(int,const struct sigaction *,struct sigaction *))342 static int RegisterUserHandler(int signal, const struct sigaction *newAction, struct sigaction *oldAction,
343                                int (*really)(int, const struct sigaction *, struct sigaction *))
344 {
345     // just hook signal in range, other use libc sigaction
346     if (signal <= 0 || signal >= _NSIG) {
347         LOG(ERROR, RUNTIME) << "illegal signal " << signal;
348         return -1;
349     }
350 
351     if (g_signalHooks[signal].IsHook()) {
352         auto userAction = g_signalHooks[signal].SignalHook::GetUserAction();
353         if (newAction != nullptr) {
354             g_signalHooks[signal].RegisterUserAction(newAction);
355         }
356         if (oldAction != nullptr) {
357             *oldAction = userAction;
358         }
359         return 0;
360     }
361 
362     return really(signal, newAction, oldAction);
363 }
364 
RegisterUserMask(int how,const sigset_t * newSet,sigset_t * oldSet,int (* really)(int,const sigset_t *,sigset_t *))365 int RegisterUserMask(int how, const sigset_t *newSet, sigset_t *oldSet,
366                      int (*really)(int, const sigset_t *, sigset_t *))
367 {
368     if (GetHandlingSignal()) {
369         return really(how, newSet, oldSet);
370     }
371 
372     if (newSet == nullptr) {
373         return really(how, newSet, oldSet);
374     }
375 
376     sigset_t buildSigset = *newSet;
377     if (how == SIG_BLOCK || how == SIG_SETMASK) {
378         for (int i = 1; i < _NSIG; ++i) {
379             if (g_signalHooks[i].IsHook() && (sigismember(&buildSigset, i) != 0)) {
380                 sigdelset(&buildSigset, i);
381             }
382         }
383     }
384     const sigset_t *buildSigsetConst = &buildSigset;
385     return really(how, buildSigsetConst, oldSet);
386 }
387 
388 // NOTE: #2681
389 // when use ADDRESS_SANITIZER, will exposed a bug,try to define 'sigaction' will happen SIGSEGV
390 #ifdef USE_ADDRESS_SANITIZER
391 // NOLINTNEXTLINE(readability-identifier-naming)
sigaction(int __sig,const struct sigaction * __restrict __act,struct sigaction * __oact)392 extern "C" int sigaction([[maybe_unused]] int __sig, [[maybe_unused]] const struct sigaction *__restrict __act,
393                          [[maybe_unused]] struct sigaction *__oact)  // NOLINT(readability-identifier-naming)
394 {
395     if (!InitRealSignalFun()) {
396         return -1;
397     }
398     return RegisterUserHandler(__sig, __act, __oact, g_realSigaction);
399 }
400 #else
401 // NOLINTNEXTLINE(readability-identifier-naming)
sigactionStub(int __sig,const struct sigaction * __restrict __act,struct sigaction * __oact)402 extern "C" int sigactionStub([[maybe_unused]] int __sig, [[maybe_unused]] const struct sigaction *__restrict __act,
403                              [[maybe_unused]] struct sigaction *__oact)  // NOLINT(readability-identifier-naming)
404 {
405     if (!InitRealSignalFun()) {
406         return -1;
407     }
408     return RegisterUserHandler(__sig, __act, __oact, g_realSigaction);
409 }
410 #endif  // USE_ADDRESS_SANITIZER
411 
412 // NOLINTNEXTLINE(readability-identifier-naming)
sigprocmask(int how,const sigset_t * newSet,sigset_t * oldSet)413 extern "C" int sigprocmask(int how, const sigset_t *newSet, sigset_t *oldSet)  // NOLINT
414 {
415     if (!InitRealSignalFun()) {
416         return -1;
417     }
418     return RegisterUserMask(how, newSet, oldSet, g_realSigProcMask);
419 }
420 
RegisterHookHandler(int signal,const SighookAction * sa)421 extern "C" void RegisterHookHandler(int signal, const SighookAction *sa)
422 {
423     if (!InitRealSignalFun()) {
424         return;
425     }
426 
427     if (signal <= 0 || signal >= _NSIG) {
428         LOG(FATAL, RUNTIME) << "illegal signal " << signal;
429     }
430 
431     g_signalHooks[signal].RegisterHookAction(sa);
432     g_signalHooks[signal].HookSig(signal);
433 }
434 
RemoveHookHandler(int signal,bool (* action)(int,siginfo_t *,void *))435 extern "C" void RemoveHookHandler(int signal, bool (*action)(int, siginfo_t *, void *))
436 {
437     if (!InitRealSignalFun()) {
438         return;
439     }
440 
441     if (signal <= 0 || signal >= _NSIG) {
442         LOG(FATAL, RUNTIME) << "illegal signal " << signal;
443     }
444 
445     g_signalHooks[signal].RemoveHookAction(action);
446 }
447 
CheckOldHookHandler(int signal)448 extern "C" void CheckOldHookHandler(int signal)
449 {
450     if (!InitRealSignalFun()) {
451         return;
452     }
453 
454     if (signal <= 0 || signal >= _NSIG) {
455         LOG(FATAL, RUNTIME) << "illegal signal " << signal;
456     }
457 
458     // get old action
459     struct sigaction oldAction {};
460     g_realSigaction(signal, nullptr, &oldAction);
461 
462     if (oldAction.sa_sigaction != SignalHook::Handler) {  // NOLINT
463         LOG(ERROR, RUNTIME) << "error: Check old hook handler found unexpected action "
464                             << (oldAction.sa_sigaction != nullptr);  // NOLINT
465         g_signalHooks[signal].RegisterAction(signal);
466     }
467 }
468 
AddSpecialSignalHandlerFn(int signal,SigchainAction * sa)469 extern "C" void AddSpecialSignalHandlerFn(int signal, SigchainAction *sa)
470 {
471     LOG(DEBUG, RUNTIME) << "panda sighook RegisterHookHandler is used, signal:" << signal << " action:" << sa;
472     RegisterHookHandler(signal, reinterpret_cast<SighookAction *>(sa));
473 }
RemoveSpecialSignalHandlerFn(int signal,bool (* fn)(int,siginfo_t *,void *))474 extern "C" void RemoveSpecialSignalHandlerFn(int signal, bool (*fn)(int, siginfo_t *, void *))
475 {
476     LOG(DEBUG, RUNTIME) << "panda sighook RemoveHookHandler is used, signal:"
477                         << "sigaction";
478     RemoveHookHandler(signal, fn);
479 }
480 
EnsureFrontOfChain(int signal)481 extern "C" void EnsureFrontOfChain(int signal)
482 {
483     LOG(DEBUG, RUNTIME) << "panda sighook CheckOldHookHandler is used, signal:" << signal;
484     CheckOldHookHandler(signal);
485 }
486 
ClearSignalHooksHandlersArray()487 void ClearSignalHooksHandlersArray()
488 {
489     g_isInitReally = false;
490     g_isInitKeyCreate = false;
491     for (int i = 1; i < _NSIG; i++) {
492         g_signalHooks[i].ClearHookActionHandlers();
493     }
494 }
495 
496 }  // namespace panda
497