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