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 void *g_reservedChildStack = NULL;
101 static pthread_mutex_t g_signalHandlerMutex = PTHREAD_MUTEX_INITIALIZER;
102 static pthread_key_t g_crashObjKey;
103 static bool g_crashObjInit = false;
104 static BOOL g_hasInit = FALSE;
105 static const int SIGNALHANDLER_TIMEOUT = 10000; // 10000 us
106 static const int ALARM_TIME_S = 10;
107 static int g_prevHandledSignal = SIGDUMP;
108 static struct sigaction g_oldSigactionList[NSIG] = {};
109 static char g_appRunningId[MAX_APP_RUNNING_UNIQUE_ID_LEN];
110 enum DumpPreparationStage {
111     CREATE_PIPE_FAIL = 1,
112     SET_PIPE_LEN_FAIL,
113     WRITE_PIPE_FAIL,
114     INHERIT_CAP_FAIL,
115     EXEC_FAIL,
116 };
117 
118 TraceInfo HiTraceGetId(void) __attribute__((weak));
FillTraceIdLocked(struct ProcessDumpRequest* request)119 static void FillTraceIdLocked(struct ProcessDumpRequest* request)
120 {
121     if (HiTraceGetId == NULL || request == NULL) {
122         return;
123     }
124 
125     TraceInfo id = HiTraceGetId();
126     memcpy(&(request->traceInfo), &id, sizeof(TraceInfo));
127 }
128 
129 const char* GetLastFatalMessage(void) __attribute__((weak));
130 fatal_msg_t *get_fatal_message(void) __attribute__((weak));
131 
132 typedef struct ThreadCallbackItem {
133     int32_t tid;
134     ThreadInfoCallBack callback;
135 } ThreadCallbackItem;
136 
137 #define CALLBACK_ITEM_COUNT 32
138 static ThreadCallbackItem g_callbackItems[CALLBACK_ITEM_COUNT];
InitCallbackItems(void)139 static void InitCallbackItems(void)
140 {
141     for (int i = 0; i < CALLBACK_ITEM_COUNT; i++) {
142         g_callbackItems[i].tid = -1;
143         g_callbackItems[i].callback = NULL;
144     }
145 }
146 
147 static GetStackIdFunc g_GetStackIdFunc = NULL;
SetAsyncStackCallbackFunc(void* func)148 void SetAsyncStackCallbackFunc(void* func)
149 {
150     g_GetStackIdFunc = (GetStackIdFunc)func;
151 }
152 
153 // caller should set to NULL before exit thread
SetThreadInfoCallback(ThreadInfoCallBack func)154 void SetThreadInfoCallback(ThreadInfoCallBack func)
155 {
156     int32_t currentTid = syscall(SYS_gettid);
157     int32_t firstEmptySlot = -1;
158     int32_t currentThreadSlot = -1;
159     pthread_mutex_lock(&g_signalHandlerMutex);
160     for (int i = 0; i < CALLBACK_ITEM_COUNT; i++) {
161         if (firstEmptySlot == -1 && g_callbackItems[i].tid == -1) {
162             firstEmptySlot = i;
163         }
164 
165         if (g_callbackItems[i].tid == currentTid) {
166             currentThreadSlot = i;
167             break;
168         }
169     }
170 
171     int32_t targetSlot = currentThreadSlot == -1 ? firstEmptySlot : currentThreadSlot;
172     if (targetSlot != -1) {
173         g_callbackItems[targetSlot].tid = func == NULL ? -1 : currentTid;
174         g_callbackItems[targetSlot].callback = func;
175     }
176     pthread_mutex_unlock(&g_signalHandlerMutex);
177 }
178 
GetCallbackLockednull179 static ThreadInfoCallBack GetCallbackLocked()
180 {
181     int32_t currentTid = syscall(SYS_gettid);
182     for (int i = 0; i < CALLBACK_ITEM_COUNT; i++) {
183         if (g_callbackItems[i].tid != currentTid) {
184             continue;
185         }
186 
187         return g_callbackItems[i].callback;
188     }
189     return NULL;
190 }
191 
FillLastFatalMessageLocked(int32_t sig)192 static void FillLastFatalMessageLocked(int32_t sig)
193 {
194     if (sig != SIGABRT) {
195         return;
196     }
197 
198     const char* lastFatalMessage = NULL;
199     if (get_fatal_message != NULL) {
200         fatal_msg_t* fatalMsg = get_fatal_message();
201         lastFatalMessage = fatalMsg == NULL ? NULL : fatalMsg->msg;
202     }
203 
204     if (lastFatalMessage == NULL && GetLastFatalMessage != NULL) {
205         lastFatalMessage = GetLastFatalMessage();
206     }
207 
208     if (lastFatalMessage == NULL) {
209         return;
210     }
211 
212     size_t len = strlen(lastFatalMessage);
213     if (len > MAX_FATAL_MSG_SIZE) {
214         DFXLOGE("Last message is longer than MAX_FATAL_MSG_SIZE");
215         return;
216     }
217 
218     g_request.msg.type = MESSAGE_FATAL;
219     (void)strncpy(g_request.msg.body, lastFatalMessage, sizeof(g_request.msg.body) - 1);
220 }
221 
FillMessageBodyLocked(MessageType type, debug_msg_t* dMsg)222 static bool FillMessageBodyLocked(MessageType type, debug_msg_t* dMsg)
223 {
224     if (dMsg == NULL || dMsg->msg == NULL) {
225         return true;
226     }
227 
228     if (g_request.timeStamp > dMsg->timestamp + PROCESSDUMP_TIMEOUT * NUMBER_ONE_THOUSAND) {
229         DFXLOGE("The event has timed out since it was triggered");
230         return false;
231     }
232 
233     g_request.msg.type = type;
234     (void)strncpy(g_request.msg.body, dMsg->msg, sizeof(g_request.msg.body) - 1);
235     return true;
236 }
237 
FillDebugMessageLocked(int32_t sig, siginfo_t *si)238 static bool FillDebugMessageLocked(int32_t sig, siginfo_t *si)
239 {
240     if (sig != SIGLEAK_STACK || si == NULL || si->si_signo != SIGLEAK_STACK) {
241         return true;
242     }
243     switch (si->si_code) {
244         case SIGLEAK_STACK_FDSAN: {
245             return FillMessageBodyLocked(MESSAGE_FDSAN_DEBUG, (debug_msg_t*)si->si_value.sival_ptr);
246         }
247         case SIGLEAK_STACK_JEMALLOC: {
248             return FillMessageBodyLocked(MESSAGE_JEMALLOC, (debug_msg_t*)si->si_value.sival_ptr);
249         }
250         case SIGLEAK_STACK_BADFD:
251             g_request.msg.type = MESSAGE_BADFD;
252             break;
253         default:
254             break;
255     }
256     return true;
257 }
258 
GetCrashDescription(const int32_t errCode)259 static const char* GetCrashDescription(const int32_t errCode)
260 {
261     size_t i;
262 
263     for (i = 0; i < sizeof(g_crashExceptionMap) / sizeof(g_crashExceptionMap[0]); i++) {
264         if (errCode == g_crashExceptionMap[i].errCode) {
265             return g_crashExceptionMap[i].str;
266         }
267     }
268     return g_crashExceptionMap[i - 1].str;    /* the end of map is "unknown reason" */
269 }
270 
FillCrashExceptionAndReport(const int err)271 static void FillCrashExceptionAndReport(const int err)
272 {
273     struct CrashDumpException exception;
274     memset(&exception, 0, sizeof(struct CrashDumpException));
275     exception.pid = g_request.pid;
276     exception.uid = (int32_t)(g_request.uid);
277     exception.error = err;
278     exception.time = (int64_t)(GetTimeMilliseconds());
279     (void)strncpy(exception.message, GetCrashDescription(err), sizeof(exception.message) - 1);
280     ReportException(exception);
281 }
282 
IsDumpSignal(int sig)283 static bool IsDumpSignal(int sig)
284 {
285     return sig == SIGDUMP || sig == SIGLEAK_STACK;
286 }
287 
FillDumpRequest(int sig, siginfo_t *si, void *context)288 static bool FillDumpRequest(int sig, siginfo_t *si, void *context)
289 {
290     memset(&g_request, 0, sizeof(g_request));
291     g_request.type = sig;
292     g_request.pid = GetRealPid();
293     g_request.nsPid = syscall(SYS_getpid);
294     g_request.tid = syscall(SYS_gettid);
295     g_request.uid = getuid();
296     g_request.reserved = 0;
297     g_request.timeStamp = GetTimeMilliseconds();
298     g_request.fdTableAddr = (uint64_t)fdsan_get_fd_table();
299     memcpy(g_request.appRunningId, g_appRunningId, sizeof(g_request.appRunningId));
300     if (!IsDumpSignal(sig) && g_GetStackIdFunc!= NULL) {
301         g_request.stackId = g_GetStackIdFunc();
302         DFXLOGI("g_GetStackIdFunc %{public}p.", (void*)g_request.stackId);
303     }
304 
305     GetThreadNameByTid(g_request.tid, g_request.threadName, sizeof(g_request.threadName));
306     GetProcessName(g_request.processName, sizeof(g_request.processName));
307 
308     memcpy(&(g_request.siginfo), si, sizeof(siginfo_t));
309     memcpy(&(g_request.context), context, sizeof(ucontext_t));
310 
311     FillTraceIdLocked(&g_request);
312     bool ret = true;
313     switch (sig) {
314         case SIGABRT:
315             FillLastFatalMessageLocked(sig);
316             break;
317         case SIGLEAK_STACK:
318             ret = FillDebugMessageLocked(sig, si);
319             /* fall-through */
320         default: {
321             ThreadInfoCallBack callback = GetCallbackLocked();
322             if (callback != NULL) {
323                 DFXLOGI("Start collect crash thread info.");
324                 g_request.msg.type = MESSAGE_FATAL;
325                 callback(g_request.msg.body, sizeof(g_request.msg.body), context);
326                 DFXLOGI("Finish collect crash thread info.");
327             }
328             break;
329         }
330     }
331     g_request.crashObj = (uintptr_t)pthread_getspecific(g_crashObjKey);
332 
333     return ret;
334 }
335 
336 static const int SIGCHAIN_DUMP_SIGNAL_LIST[] = {
337     SIGDUMP, SIGLEAK_STACK
338 };
339 
340 static const int SIGCHAIN_CRASH_SIGNAL_LIST[] = {
341     SIGILL, SIGABRT, SIGBUS, SIGFPE,
342     SIGSEGV, SIGSTKFLT, SIGSYS, SIGTRAP
343 };
344 
IsMainThread(void)345 static bool IsMainThread(void)
346 {
347     if (syscall(SYS_getpid) == 1) {
348         if (syscall(SYS_gettid) == 1) {
349             return true;
350         }
351     } else {
352         if (syscall(SYS_getpid) == syscall(SYS_gettid)) {
353             return true;
354         }
355     }
356     return false;
357 }
358 
ResetAndRethrowSignalIfNeed(int sig, siginfo_t *si)359 static void ResetAndRethrowSignalIfNeed(int sig, siginfo_t *si)
360 {
361     if (IsDumpSignal(sig)) {
362         return;
363     }
364 
365     if (g_oldSigactionList[sig].sa_sigaction == NULL) {
366         signal(sig, SIG_DFL);
367     } else if (sigaction(sig, &(g_oldSigactionList[sig]), NULL) != 0) {
368         DFXLOGE("Failed to reset sig(%{public}d).", sig);
369         signal(sig, SIG_DFL);
370     }
371 
372     if (syscall(SYS_rt_tgsigqueueinfo, syscall(SYS_getpid), syscall(SYS_gettid), sig, si) != 0) {
373         DFXLOGE("Failed to rethrow sig(%{public}d), errno(%{public}d).", sig, errno);
374     } else {
375         DFXLOGI("Current process(%{public}ld) rethrow sig(%{public}d).", syscall(SYS_getpid), sig);
376     }
377 }
378 
PauseMainThreadHandler(int sig)379 static void PauseMainThreadHandler(int sig)
380 {
381     DFXLOGI("Crash(%{public}d) in child thread(%{public}ld), lock main thread.", sig, syscall(SYS_gettid));
382     // only work when subthread crash and send SIGDUMP to mainthread.
383     pthread_mutex_lock(&g_signalHandlerMutex);
384     pthread_mutex_unlock(&g_signalHandlerMutex);
385     DFXLOGI("Crash in child thread(%{public}ld), exit main thread.", syscall(SYS_gettid));
386 }
387 
BlockMainThreadIfNeed(int sig)388 static void BlockMainThreadIfNeed(int sig)
389 {
390     if (IsMainThread() || IsDumpSignal(sig)) {
391         return;
392     }
393 
394     DFXLOGI("Try block main thread.");
395     (void)signal(SIGQUIT, PauseMainThreadHandler);
396     if (syscall(SYS_tgkill, syscall(SYS_getpid), syscall(SYS_getpid), SIGQUIT) != 0) {
397         DFXLOGE("Failed to send SIGQUIT to main thread, errno(%{public}d).", errno);
398     }
399 }
400 
401 #ifndef is_ohos_lite
402 int DfxDumpRequest(int sig, struct ProcessDumpRequest *request, void *reservedChildStack) __attribute__((weak));
403 #endif
DumpRequest(int sig)404 static int DumpRequest(int sig)
405 {
406     int ret = false;
407     if (DfxDumpRequest == NULL) {
408         DFXLOGE("DumpRequest fail, the DfxDumpRequest is NULL");
409         FillCrashExceptionAndReport(CRASH_SIGNAL_EDUMPREQUEST);
410         return ret;
411     }
412     ret = DfxDumpRequest(sig, &g_request, g_reservedChildStack);
413     return ret;
414 }
415 
416 
DFX_SigchainHandler(int sig, siginfo_t *si, void *context)417 static bool DFX_SigchainHandler(int sig, siginfo_t *si, void *context)
418 {
419     int pid = syscall(SYS_getpid);
420     int tid = syscall(SYS_gettid);
421 
422     DFXLOGW("DFX_SigchainHandler :: sig(%{public}d), pid(%{public}d), tid(%{public}d).", sig, pid, tid);
423     bool ret = false;
424     if (sig == SIGDUMP) {
425         if (si->si_code != DUMP_TYPE_REMOTE) {
426             DFXLOGW("DFX_SigchainHandler :: sig(%{public}d:%{public}d) is not remote dump type, return directly",
427                 sig, si->si_code);
428             return true;
429         }
430     }
431 
432     // crash signal should never be skipped
433     pthread_mutex_lock(&g_signalHandlerMutex);
434     if (!IsDumpSignal(g_prevHandledSignal)) {
435         pthread_mutex_unlock(&g_signalHandlerMutex);
436         return ret;
437     }
438     BlockMainThreadIfNeed(sig);
439     g_prevHandledSignal = sig;
440 
441     if (!FillDumpRequest(sig, si, context)) {
442         pthread_mutex_unlock(&g_signalHandlerMutex);
443         DFXLOGE("DFX_SigchainHandler :: signal(%{public}d) in %{public}d:%{public}d fill dump request faild.",
444             sig, g_request.pid, g_request.tid);
445         return sig == SIGLEAK_STACK;
446     }
447     DFXLOGI("DFX_SigchainHandler :: sig(%{public}d), pid(%{public}d), processName(%{public}s), threadName(%{public}s).",
448         sig, g_request.pid, g_request.processName, g_request.threadName);
449     ret = DumpRequest(sig);
450     pthread_mutex_unlock(&g_signalHandlerMutex);
451     DFXLOGW("Finish handle signal(%{public}d) in %{public}d:%{public}d.", sig, g_request.pid, g_request.tid);
452     return ret;
453 }
454 
DFX_SignalHandler(int sig, siginfo_t *si, void *context)455 static void DFX_SignalHandler(int sig, siginfo_t *si, void *context)
456 {
457     DFX_SigchainHandler(sig, si, context);
458     ResetAndRethrowSignalIfNeed(sig, si);
459 }
460 
InstallSigActionHandler(int sig)461 static void InstallSigActionHandler(int sig)
462 {
463     struct sigaction action;
464     memset(&action, 0, sizeof(action));
465     memset(&g_oldSigactionList, 0, sizeof(g_oldSigactionList));
466     sigfillset(&action.sa_mask);
467     action.sa_sigaction = DFX_SignalHandler;
468     action.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
469     if (sigaction(sig, &action, &(g_oldSigactionList[sig])) != 0) {
470         DFXLOGE("Failed to register signal(%{public}d)", sig);
471     }
472 }
473 
DFX_InstallSignalHandler(void)474 void DFX_InstallSignalHandler(void)
475 {
476     if (g_hasInit) {
477         return;
478     }
479 
480     InitCallbackItems();
481     // reserve stack for fork
482     g_reservedChildStack = mmap(NULL, RESERVED_CHILD_STACK_SIZE, \
483         PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, 1, 0);
484     if (g_reservedChildStack == NULL) {
485         DFXLOGE("[%{public}d]: Failed to alloc memory for child stack.", __LINE__);
486         return;
487     }
488     g_reservedChildStack = (void *)(((uint8_t *)g_reservedChildStack) + RESERVED_CHILD_STACK_SIZE - 1);
489 
490     struct signal_chain_action sigchain = {
491         .sca_sigaction = DFX_SigchainHandler,
492         .sca_mask = {},
493         .sca_flags = 0,
494     };
495 
496     for (size_t i = 0; i < sizeof(SIGCHAIN_DUMP_SIGNAL_LIST) / sizeof(SIGCHAIN_DUMP_SIGNAL_LIST[0]); i++) {
497         int32_t sig = SIGCHAIN_DUMP_SIGNAL_LIST[i];
498         sigfillset(&sigchain.sca_mask);
499         // dump signal not mask crash signal
500         for (size_t j = 0; j < sizeof(SIGCHAIN_CRASH_SIGNAL_LIST) / sizeof(SIGCHAIN_CRASH_SIGNAL_LIST[0]); j++) {
501             sigdelset(&sigchain.sca_mask, SIGCHAIN_CRASH_SIGNAL_LIST[j]);
502         }
503         add_special_handler_at_last(sig, &sigchain);
504     }
505     for (size_t i = 0; i < sizeof(SIGCHAIN_CRASH_SIGNAL_LIST) / sizeof(SIGCHAIN_CRASH_SIGNAL_LIST[0]); i++) {
506         int32_t sig = SIGCHAIN_CRASH_SIGNAL_LIST[i];
507         if (sig == SIGILL || sig == SIGSYS) {
508             InstallSigActionHandler(sig);
509         } else {
510             sigfillset(&sigchain.sca_mask);
511             add_special_handler_at_last(sig, &sigchain);
512         }
513     }
514 
515     g_hasInit = TRUE;
516     if (pthread_key_create(&g_crashObjKey, NULL) == 0) {
517         g_crashObjInit = true;
518     }
519 }
520 
DFX_SetAppRunningUniqueId(const char* appRunningId, size_t len)521 int DFX_SetAppRunningUniqueId(const char* appRunningId, size_t len)
522 {
523     size_t appRunningIdMaxLen = sizeof(g_appRunningId);
524     if (appRunningId == NULL || appRunningIdMaxLen <= len) {
525         DFXLOGE("param error. appRunningId is NULL or length overflow");
526         return -1;
527     }
528     memset(g_appRunningId, 0, appRunningIdMaxLen);
529     memcpy(g_appRunningId, appRunningId, len);
530     return 0;
531 }
532 
DFX_SetCrashObj(uint8_t type, uintptr_t addr)533 uintptr_t DFX_SetCrashObj(uint8_t type, uintptr_t addr)
534 {
535     if (!g_crashObjInit) {
536         return 0;
537     }
538 #if defined __LP64__
539     uintptr_t origin = (uintptr_t)pthread_getspecific(g_crashObjKey);
540     uintptr_t crashObj = 0;
541     const int moveBit = 56;
542     crashObj = ((uintptr_t)type << moveBit) | (addr & 0x00ffffffffffffff);
543     pthread_setspecific(g_crashObjKey, (void*)(crashObj));
544     return origin;
545 #else
546     return 0;
547 #endif
548 }
549 
DFX_ResetCrashObj(uintptr_t crashObj)550 void DFX_ResetCrashObj(uintptr_t crashObj)
551 {
552     if (!g_crashObjInit) {
553         return;
554     }
555 #if defined __LP64__
556     pthread_setspecific(g_crashObjKey, (void*)(crashObj));
557 #endif
558 }
559