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