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