• 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 #include "dfx_signal_handler.h"
16 
17 #ifndef _GNU_SOURCE
18 #define _GNU_SOURCE 1
19 #endif
20 
21 #include <fcntl.h>
22 #include <poll.h>
23 #include <pthread.h>
24 #include <sched.h>
25 #include <signal.h>
26 #include <sigchain.h>
27 #include <stdint.h>
28 #include <stdio.h>
29 #include <sys/capability.h>
30 #include <sys/mman.h>
31 #include <sys/prctl.h>
32 #include <sys/syscall.h>
33 #include <sys/time.h>
34 #include <sys/types.h>
35 #include <sys/uio.h>
36 #include <sys/wait.h>
37 #include <time.h>
38 #include <unistd.h>
39 #include "dfx_define.h"
40 #include "dfx_dump_request.h"
41 #include "dfx_signalhandler_exception.h"
42 #include "errno.h"
43 #include "linux/capability.h"
44 #include "stdbool.h"
45 #include "string.h"
46 #ifndef DFX_SIGNAL_LIBC
47 #include <securec.h>
48 #include "dfx_cutil.h"
49 #include "dfx_log.h"
50 #else
51 #include "musl_cutil.h"
52 #include "musl_log.h"
53 #endif
54 
55 #ifdef is_ohos_lite
56 #include "dfx_dumprequest.h"
57 #endif
58 
59 #include "info/fatal_message.h"
60 
61 #ifdef LOG_DOMAIN
62 #undef LOG_DOMAIN
63 #define LOG_DOMAIN 0xD002D11
64 #endif
65 
66 #ifdef LOG_TAG
67 #undef LOG_TAG
68 #define LOG_TAG "DfxSignalHandler"
69 #endif
70 
71 #if defined (__LP64__)
72 #define RESERVED_CHILD_STACK_SIZE (32 * 1024)  // 32K
73 #else
74 #define RESERVED_CHILD_STACK_SIZE (16 * 1024)  // 16K
75 #endif
76 
77 #define BOOL int
78 #define TRUE 1
79 #define FALSE 0
80 
81 #ifndef NSIG
82 #define NSIG 64
83 #endif
84 
85 #ifndef F_SETPIPE_SZ
86 #define F_SETPIPE_SZ 1031
87 #endif
88 
89 #define NUMBER_SIXTYFOUR 64
90 #define INHERITABLE_OFFSET 32
91 
92 #ifndef __MUSL__
InitHandler(void)93 void __attribute__((constructor)) InitHandler(void)
94 {
95     DFX_InstallSignalHandler();
96 }
97 #endif
98 
99 static struct ProcessDumpRequest g_request;
100 static pthread_mutex_t g_signalHandlerMutex = PTHREAD_MUTEX_INITIALIZER;
101 static pthread_key_t g_crashObjKey;
102 static bool g_crashObjInit = false;
103 static BOOL g_hasInit = FALSE;
104 static const int SIGNALHANDLER_TIMEOUT = 10000; // 10000 us
105 static const int ALARM_TIME_S = 10;
106 static int g_prevHandledSignal = SIGDUMP;
107 static struct sigaction g_oldSigactionList[NSIG] = {};
108 static char g_appRunningId[MAX_APP_RUNNING_UNIQUE_ID_LEN];
109 enum DumpPreparationStage {
110     CREATE_PIPE_FAIL = 1,
111     SET_PIPE_LEN_FAIL,
112     WRITE_PIPE_FAIL,
113     INHERIT_CAP_FAIL,
114     EXEC_FAIL,
115 };
116 
117 const char* GetLastFatalMessage(void) __attribute__((weak));
118 fatal_msg_t *get_fatal_message(void) __attribute__((weak));
119 
120 typedef struct ThreadCallbackItem {
121     int32_t tid;
122     ThreadInfoCallBack callback;
123 } ThreadCallbackItem;
124 
125 #define CALLBACK_ITEM_COUNT 32
126 static ThreadCallbackItem g_callbackItems[CALLBACK_ITEM_COUNT];
InitCallbackItems(void)127 static void InitCallbackItems(void)
128 {
129     for (int i = 0; i < CALLBACK_ITEM_COUNT; i++) {
130         g_callbackItems[i].tid = -1;
131         g_callbackItems[i].callback = NULL;
132     }
133 }
134 
135 static GetStackIdFunc g_GetStackIdFunc = NULL;
SetAsyncStackCallbackFunc(void * func)136 void SetAsyncStackCallbackFunc(void* func)
137 {
138     g_GetStackIdFunc = (GetStackIdFunc)func;
139 }
140 
141 // caller should set to NULL before exit thread
SetThreadInfoCallback(ThreadInfoCallBack func)142 void SetThreadInfoCallback(ThreadInfoCallBack func)
143 {
144     int32_t currentTid = syscall(SYS_gettid);
145     int32_t firstEmptySlot = -1;
146     int32_t currentThreadSlot = -1;
147     pthread_mutex_lock(&g_signalHandlerMutex);
148     for (int i = 0; i < CALLBACK_ITEM_COUNT; i++) {
149         if (firstEmptySlot == -1 && g_callbackItems[i].tid == -1) {
150             firstEmptySlot = i;
151         }
152 
153         if (g_callbackItems[i].tid == currentTid) {
154             currentThreadSlot = i;
155             break;
156         }
157     }
158 
159     int32_t targetSlot = currentThreadSlot == -1 ? firstEmptySlot : currentThreadSlot;
160     if (targetSlot != -1) {
161         g_callbackItems[targetSlot].tid = func == NULL ? -1 : currentTid;
162         g_callbackItems[targetSlot].callback = func;
163     }
164     pthread_mutex_unlock(&g_signalHandlerMutex);
165 }
166 
GetCallbackLocked()167 static ThreadInfoCallBack GetCallbackLocked()
168 {
169     int32_t currentTid = syscall(SYS_gettid);
170     for (int i = 0; i < CALLBACK_ITEM_COUNT; i++) {
171         if (g_callbackItems[i].tid != currentTid) {
172             continue;
173         }
174 
175         return g_callbackItems[i].callback;
176     }
177     return NULL;
178 }
179 
FillLastFatalMessageLocked(int32_t signo)180 static void FillLastFatalMessageLocked(int32_t signo)
181 {
182     if (signo != SIGABRT) {
183         return;
184     }
185 
186     const char* lastFatalMessage = NULL;
187     if (get_fatal_message != NULL) {
188         fatal_msg_t* fatalMsg = get_fatal_message();
189         lastFatalMessage = fatalMsg == NULL ? NULL : fatalMsg->msg;
190     }
191 
192     if (lastFatalMessage == NULL && GetLastFatalMessage != NULL) {
193         lastFatalMessage = GetLastFatalMessage();
194     }
195 
196     if (lastFatalMessage == NULL) {
197         return;
198     }
199 
200     size_t len = strlen(lastFatalMessage);
201     if (len > MAX_FATAL_MSG_SIZE) {
202         DFXLOGE("Last message is longer than MAX_FATAL_MSG_SIZE");
203         return;
204     }
205 
206     g_request.msg.type = MESSAGE_FATAL;
207     (void)strncpy(g_request.msg.body, lastFatalMessage, sizeof(g_request.msg.body) - 1);
208 }
209 
FillDebugMessageLocked(int32_t signo,siginfo_t * si)210 static bool FillDebugMessageLocked(int32_t signo, siginfo_t *si)
211 {
212     if (signo != SIGLEAK_STACK || si == NULL ||
213         (si->si_code != SIGLEAK_STACK_FDSAN && si->si_code != SIGLEAK_STACK_JEMALLOC)) {
214         return true;
215     }
216 
217     // The pointer received by the Linux kernel must be NULL
218     debug_msg_t *dMsg = (debug_msg_t*)si->si_value.sival_ptr;
219     if (dMsg == NULL || g_request.timeStamp > dMsg->timestamp + PROCESSDUMP_TIMEOUT * NUMBER_ONE_THOUSAND) {
220         DFXLOGE("The event has timed out since it was triggered");
221         return false;
222     }
223     return true;
224 }
225 
GetCrashDescription(const int32_t errCode)226 static const char* GetCrashDescription(const int32_t errCode)
227 {
228     size_t i;
229 
230     for (i = 0; i < sizeof(g_crashExceptionMap) / sizeof(g_crashExceptionMap[0]); i++) {
231         if (errCode == g_crashExceptionMap[i].errCode) {
232             return g_crashExceptionMap[i].str;
233         }
234     }
235     return g_crashExceptionMap[i - 1].str;    /* the end of map is "unknown reason" */
236 }
237 
FillCrashExceptionAndReport(const int err)238 static void FillCrashExceptionAndReport(const int err)
239 {
240     struct CrashDumpException exception;
241     memset(&exception, 0, sizeof(struct CrashDumpException));
242     exception.pid = g_request.pid;
243     exception.uid = (int32_t)(g_request.uid);
244     exception.error = err;
245     exception.time = (int64_t)(GetTimeMilliseconds());
246     (void)strncpy(exception.message, GetCrashDescription(err), sizeof(exception.message) - 1);
247     ReportException(&exception);
248 }
249 
IsDumpSignal(int signo)250 static bool IsDumpSignal(int signo)
251 {
252     return signo == SIGDUMP || signo == SIGLEAK_STACK;
253 }
254 
FillDumpRequest(int signo,siginfo_t * si,void * context)255 static bool FillDumpRequest(int signo, siginfo_t *si, void *context)
256 {
257     memset(&g_request, 0, sizeof(g_request));
258     g_request.type = signo;
259     g_request.pid = GetRealPid();
260     g_request.nsPid = syscall(SYS_getpid);
261     g_request.tid = syscall(SYS_gettid);
262     g_request.uid = getuid();
263     g_request.reserved = 0;
264     g_request.timeStamp = GetTimeMilliseconds();
265     g_request.fdTableAddr = (uint64_t)fdsan_get_fd_table();
266     memcpy(g_request.appRunningId, g_appRunningId, sizeof(g_request.appRunningId));
267     if (!IsDumpSignal(signo) && g_GetStackIdFunc!= NULL) {
268         g_request.stackId = g_GetStackIdFunc();
269         DFXLOGI("g_GetStackIdFunc %{public}p.", (void*)g_request.stackId);
270     }
271 
272     GetThreadNameByTid(g_request.tid, g_request.threadName, sizeof(g_request.threadName));
273     GetProcessName(g_request.processName, sizeof(g_request.processName));
274 
275     memcpy(&(g_request.siginfo), si, sizeof(siginfo_t));
276     memcpy(&(g_request.context), context, sizeof(ucontext_t));
277 
278     bool ret = true;
279     switch (signo) {
280         case SIGABRT:
281             FillLastFatalMessageLocked(signo);
282             break;
283         case SIGLEAK_STACK:
284             ret = FillDebugMessageLocked(signo, si);
285             /* fall-through */
286         default: {
287             ThreadInfoCallBack callback = GetCallbackLocked();
288             if (callback != NULL) {
289                 DFXLOGI("Start collect crash thread info.");
290                 g_request.msg.type = MESSAGE_CALLBACK;
291                 callback(g_request.msg.body, sizeof(g_request.msg.body), context);
292                 DFXLOGI("Finish collect crash thread info.");
293             }
294             break;
295         }
296     }
297     g_request.crashObj = (uintptr_t)pthread_getspecific(g_crashObjKey);
298 
299     return ret;
300 }
301 
302 static const int SIGCHAIN_DUMP_SIGNAL_LIST[] = {
303     SIGDUMP, SIGLEAK_STACK
304 };
305 
306 static const int SIGCHAIN_CRASH_SIGNAL_LIST[] = {
307     SIGILL, SIGABRT, SIGBUS, SIGFPE,
308     SIGSEGV, SIGSTKFLT, SIGSYS, SIGTRAP
309 };
310 
IsMainThread(void)311 static bool IsMainThread(void)
312 {
313     if (syscall(SYS_getpid) == 1) {
314         if (syscall(SYS_gettid) == 1) {
315             return true;
316         }
317     } else {
318         if (syscall(SYS_getpid) == syscall(SYS_gettid)) {
319             return true;
320         }
321     }
322     return false;
323 }
324 
ResetAndRethrowSignalIfNeed(int signo,siginfo_t * si)325 static void ResetAndRethrowSignalIfNeed(int signo, siginfo_t *si)
326 {
327     if (IsDumpSignal(signo)) {
328         return;
329     }
330 
331     if (g_oldSigactionList[signo].sa_sigaction == NULL) {
332         signal(signo, SIG_DFL);
333     } else if (sigaction(signo, &(g_oldSigactionList[signo]), NULL) != 0) {
334         DFXLOGE("Failed to reset signo(%{public}d).", signo);
335         signal(signo, SIG_DFL);
336     }
337 
338     if (syscall(SYS_rt_tgsigqueueinfo, syscall(SYS_getpid), syscall(SYS_gettid), signo, si) != 0) {
339         DFXLOGE("Failed to rethrow signo(%{public}d), errno(%{public}d).", signo, errno);
340     } else {
341         DFXLOGI("Current process(%{public}ld) rethrow signo(%{public}d).", syscall(SYS_getpid), signo);
342     }
343 }
344 
345 #ifndef is_ohos_lite
346 void DfxDumpRequest(int signo, struct ProcessDumpRequest *request) __attribute__((weak));
347 #endif
DumpRequest(int signo)348 static void DumpRequest(int signo)
349 {
350     if (DfxDumpRequest == NULL) {
351         DFXLOGE("DumpRequest fail, the DfxDumpRequest is NULL");
352         FillCrashExceptionAndReport(CRASH_SIGNAL_EDUMPREQUEST);
353         return;
354     }
355     DfxDumpRequest(signo, &g_request);
356 }
357 
DFX_SigchainHandler(int signo,siginfo_t * si,void * context)358 static bool DFX_SigchainHandler(int signo, siginfo_t *si, void *context)
359 {
360     int pid = syscall(SYS_getpid);
361     int tid = syscall(SYS_gettid);
362     if (si == NULL) {
363         return IsDumpSignal(signo);
364     }
365 
366     DFXLOGI("DFX_SigchainHandler :: signo(%{public}d), si_code(%{public}d), pid(%{public}d), tid(%{public}d).",
367             signo, si->si_code, pid, tid);
368     if (signo == SIGDUMP) {
369         if (si->si_code != DUMP_TYPE_REMOTE && si->si_code != DUMP_TYPE_REMOTE_JSON) {
370             DFXLOGW("DFX_SigchainHandler :: signo(%{public}d:%{public}d) is not remote dump type, return directly",
371                 signo, si->si_code);
372             return IsDumpSignal(signo);
373         }
374     }
375 
376     // crash signal should never be skipped
377     pthread_mutex_lock(&g_signalHandlerMutex);
378     if (!IsDumpSignal(g_prevHandledSignal)) {
379         pthread_mutex_unlock(&g_signalHandlerMutex);
380         return IsDumpSignal(signo);
381     }
382     g_prevHandledSignal = signo;
383 
384     if (!FillDumpRequest(signo, si, context)) {
385         pthread_mutex_unlock(&g_signalHandlerMutex);
386         DFXLOGE("DFX_SigchainHandler :: signal(%{public}d) in %{public}d:%{public}d fill dump request faild.",
387             signo, g_request.pid, g_request.tid);
388         return IsDumpSignal(signo);
389     }
390     DFXLOGI("DFX_SigchainHandler :: signo(%{public}d), pid(%{public}d), processName(%{public}s), \
391         threadName(%{public}s).", signo, g_request.pid, g_request.processName, g_request.threadName);
392     DumpRequest(signo);
393     pthread_mutex_unlock(&g_signalHandlerMutex);
394     DFXLOGI("Finish handle signal(%{public}d) in %{public}d:%{public}d.", signo, g_request.pid, g_request.tid);
395     return IsDumpSignal(signo);
396 }
397 
DFX_SignalHandler(int signo,siginfo_t * si,void * context)398 static void DFX_SignalHandler(int signo, siginfo_t *si, void *context)
399 {
400     DFX_SigchainHandler(signo, si, context);
401     ResetAndRethrowSignalIfNeed(signo, si);
402 }
403 
InstallSigActionHandler(int signo)404 static void InstallSigActionHandler(int signo)
405 {
406     struct sigaction action;
407     memset(&action, 0, sizeof(action));
408     memset(&g_oldSigactionList, 0, sizeof(g_oldSigactionList));
409     sigfillset(&action.sa_mask);
410     action.sa_sigaction = DFX_SignalHandler;
411     action.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
412     if (sigaction(signo, &action, &(g_oldSigactionList[signo])) != 0) {
413         DFXLOGE("Failed to register signal(%{public}d)", signo);
414     }
415 }
416 
DFX_InstallSignalHandler(void)417 void DFX_InstallSignalHandler(void)
418 {
419     if (g_hasInit) {
420         return;
421     }
422 
423     InitCallbackItems();
424     struct signal_chain_action sigchain = {
425         .sca_sigaction = DFX_SigchainHandler,
426         .sca_mask = {},
427         .sca_flags = 0,
428     };
429 
430     for (size_t i = 0; i < sizeof(SIGCHAIN_DUMP_SIGNAL_LIST) / sizeof(SIGCHAIN_DUMP_SIGNAL_LIST[0]); i++) {
431         int32_t signo = SIGCHAIN_DUMP_SIGNAL_LIST[i];
432         sigfillset(&sigchain.sca_mask);
433         // dump signal not mask crash signal
434         for (size_t j = 0; j < sizeof(SIGCHAIN_CRASH_SIGNAL_LIST) / sizeof(SIGCHAIN_CRASH_SIGNAL_LIST[0]); j++) {
435             sigdelset(&sigchain.sca_mask, SIGCHAIN_CRASH_SIGNAL_LIST[j]);
436         }
437         add_special_handler_at_last(signo, &sigchain);
438     }
439     for (size_t i = 0; i < sizeof(SIGCHAIN_CRASH_SIGNAL_LIST) / sizeof(SIGCHAIN_CRASH_SIGNAL_LIST[0]); i++) {
440         int32_t signo = SIGCHAIN_CRASH_SIGNAL_LIST[i];
441         if (signo == SIGILL || signo == SIGSYS) {
442             InstallSigActionHandler(signo);
443         } else {
444             sigfillset(&sigchain.sca_mask);
445             add_special_handler_at_last(signo, &sigchain);
446         }
447     }
448 
449     g_hasInit = TRUE;
450     if (pthread_key_create(&g_crashObjKey, NULL) == 0) {
451         g_crashObjInit = true;
452     }
453 }
454 
DFX_SetAppRunningUniqueId(const char * appRunningId,size_t len)455 int DFX_SetAppRunningUniqueId(const char* appRunningId, size_t len)
456 {
457     size_t appRunningIdMaxLen = sizeof(g_appRunningId);
458     if (appRunningId == NULL || appRunningIdMaxLen <= len) {
459         DFXLOGE("param error. appRunningId is NULL or length overflow");
460         return -1;
461     }
462     memset(g_appRunningId, 0, appRunningIdMaxLen);
463     memcpy(g_appRunningId, appRunningId, len);
464     return 0;
465 }
466 
DFX_SetCrashObj(uint8_t type,uintptr_t addr)467 uintptr_t DFX_SetCrashObj(uint8_t type, uintptr_t addr)
468 {
469     if (!g_crashObjInit) {
470         return 0;
471     }
472 #if defined __LP64__
473     uintptr_t origin = (uintptr_t)pthread_getspecific(g_crashObjKey);
474     uintptr_t crashObj = 0;
475     const int moveBit = 56;
476     crashObj = ((uintptr_t)type << moveBit) | (addr & 0x00ffffffffffffff);
477     pthread_setspecific(g_crashObjKey, (void*)(crashObj));
478     return origin;
479 #else
480     return 0;
481 #endif
482 }
483 
DFX_ResetCrashObj(uintptr_t crashObj)484 void DFX_ResetCrashObj(uintptr_t crashObj)
485 {
486     if (!g_crashObjInit) {
487         return;
488     }
489 #if defined __LP64__
490     pthread_setspecific(g_crashObjKey, (void*)(crashObj));
491 #endif
492 }
493