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