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