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 #include "info/fatal_message.h"
56 
57 #ifdef LOG_DOMAIN
58 #undef LOG_DOMAIN
59 #define LOG_DOMAIN 0xD002D11
60 #endif
61 
62 #ifdef LOG_TAG
63 #undef LOG_TAG
64 #define LOG_TAG "DfxSignalHandler"
65 #endif
66 
67 #if defined (__LP64__)
68 #define RESERVED_CHILD_STACK_SIZE (32 * 1024)  // 32K
69 #else
70 #define RESERVED_CHILD_STACK_SIZE (16 * 1024)  // 16K
71 #endif
72 
73 #define BOOL int
74 #define TRUE 1
75 #define FALSE 0
76 
77 #ifndef NSIG
78 #define NSIG 64
79 #endif
80 
81 #ifndef F_SETPIPE_SZ
82 #define F_SETPIPE_SZ 1031
83 #endif
84 
85 #define NUMBER_SIXTYFOUR 64
86 #define INHERITABLE_OFFSET 32
87 
88 #ifndef __MUSL__
InitHandler(void)89 void __attribute__((constructor)) InitHandler(void)
90 {
91     DFX_InstallSignalHandler();
92 }
93 #endif
94 
95 static struct ProcessDumpRequest g_request;
96 static void *g_reservedChildStack = NULL;
97 static pthread_mutex_t g_signalHandlerMutex = PTHREAD_MUTEX_INITIALIZER;
98 
99 enum PIPE_FD_TYPE {
100     WRITE_TO_DUMP,
101     READ_FROM_DUMP_TO_MAIN,
102     READ_FORM_DUMP_TO_VIRTUAL,
103     PIPE_MAX,
104 };
105 
106 static int g_pipeFds[PIPE_MAX][2] = {
107     {-1, -1},
108     {-1, -1},
109     {-1, -1}
110 };
111 
112 static pthread_key_t g_crashObjKey;
113 static bool g_crashObjInit = false;
114 static BOOL g_hasInit = FALSE;
115 static const int SIGNALHANDLER_TIMEOUT = 10000; // 10000 us
116 static const int ALARM_TIME_S = 10;
117 static int g_prevHandledSignal = SIGDUMP;
118 static struct sigaction g_oldSigactionList[NSIG] = {};
119 static char g_appRunningId[MAX_APP_RUNNING_UNIQUE_ID_LEN];
120 enum DumpPreparationStage {
121     CREATE_PIPE_FAIL = 1,
122     SET_PIPE_LEN_FAIL,
123     WRITE_PIPE_FAIL,
124     INHERIT_CAP_FAIL,
125     EXEC_FAIL,
126 };
127 
128 TraceInfo HiTraceGetId(void) __attribute__((weak));
FillTraceIdLocked(struct ProcessDumpRequest * request)129 static void FillTraceIdLocked(struct ProcessDumpRequest* request)
130 {
131     if (HiTraceGetId == NULL || request == NULL) {
132         return;
133     }
134 
135     TraceInfo id = HiTraceGetId();
136     memcpy(&(request->traceInfo), &id, sizeof(TraceInfo));
137 }
138 
139 const char* GetLastFatalMessage(void) __attribute__((weak));
140 fatal_msg_t *get_fatal_message(void) __attribute__((weak));
141 typedef struct ThreadCallbackItem {
142     int32_t tid;
143     ThreadInfoCallBack callback;
144 } ThreadCallbackItem;
145 
146 #define CALLBACK_ITEM_COUNT 32
147 static ThreadCallbackItem g_callbackItems[CALLBACK_ITEM_COUNT];
InitCallbackItems(void)148 static void InitCallbackItems(void)
149 {
150     for (int i = 0; i < CALLBACK_ITEM_COUNT; i++) {
151         g_callbackItems[i].tid = -1;
152         g_callbackItems[i].callback = NULL;
153     }
154 }
155 
156 static GetStackIdFunc g_GetStackIdFunc = NULL;
SetAsyncStackCallbackFunc(void * func)157 void SetAsyncStackCallbackFunc(void* func)
158 {
159     g_GetStackIdFunc = (GetStackIdFunc)func;
160 }
161 
162 // caller should set to NULL before exit thread
SetThreadInfoCallback(ThreadInfoCallBack func)163 void SetThreadInfoCallback(ThreadInfoCallBack func)
164 {
165     int32_t currentTid = syscall(SYS_gettid);
166     int32_t firstEmptySlot = -1;
167     int32_t currentThreadSlot = -1;
168     pthread_mutex_lock(&g_signalHandlerMutex);
169     for (int i = 0; i < CALLBACK_ITEM_COUNT; i++) {
170         if (firstEmptySlot == -1 && g_callbackItems[i].tid == -1) {
171             firstEmptySlot = i;
172         }
173 
174         if (g_callbackItems[i].tid == currentTid) {
175             currentThreadSlot = i;
176             break;
177         }
178     }
179 
180     int32_t targetSlot = currentThreadSlot == -1 ? firstEmptySlot : currentThreadSlot;
181     if (targetSlot != -1) {
182         g_callbackItems[targetSlot].tid = func == NULL ? -1 : currentTid;
183         g_callbackItems[targetSlot].callback = func;
184     }
185     pthread_mutex_unlock(&g_signalHandlerMutex);
186 }
187 
GetCallbackLocked()188 static ThreadInfoCallBack GetCallbackLocked()
189 {
190     int32_t currentTid = syscall(SYS_gettid);
191     for (int i = 0; i < CALLBACK_ITEM_COUNT; i++) {
192         if (g_callbackItems[i].tid != currentTid) {
193             continue;
194         }
195 
196         return g_callbackItems[i].callback;
197     }
198     return NULL;
199 }
200 
FillLastFatalMessageLocked(int32_t sig,void * context)201 static void FillLastFatalMessageLocked(int32_t sig, void *context)
202 {
203     if (sig != SIGABRT) {
204         ThreadInfoCallBack callback = GetCallbackLocked();
205         if (callback != NULL) {
206             DFXLOG_INFO("Start collect crash thread info.");
207             callback(g_request.lastFatalMessage, sizeof(g_request.lastFatalMessage), context);
208             DFXLOG_INFO("Finish collect crash thread info.");
209         }
210         return;
211     }
212 
213     const char* lastFatalMessage = NULL;
214     if (get_fatal_message != NULL) {
215         fatal_msg_t* fatalMsg = get_fatal_message();
216         lastFatalMessage = fatalMsg == NULL ? NULL : fatalMsg->msg;
217     }
218 
219     if (lastFatalMessage == NULL && GetLastFatalMessage != NULL) {
220         lastFatalMessage = GetLastFatalMessage();
221     }
222 
223     if (lastFatalMessage == NULL) {
224         return;
225     }
226 
227     size_t len = strlen(lastFatalMessage);
228     if (len > MAX_FATAL_MSG_SIZE) {
229         DFXLOG_ERROR("Last message is longer than MAX_FATAL_MSG_SIZE");
230         return;
231     }
232 
233     (void)strncpy(g_request.lastFatalMessage, lastFatalMessage, sizeof(g_request.lastFatalMessage) - 1);
234 }
235 
GetCrashDescription(const int32_t errCode)236 static const char* GetCrashDescription(const int32_t errCode)
237 {
238     size_t i;
239 
240     for (i = 0; i < sizeof(g_crashExceptionMap) / sizeof(g_crashExceptionMap[0]); i++) {
241         if (errCode == g_crashExceptionMap[i].errCode) {
242             return g_crashExceptionMap[i].str;
243         }
244     }
245     return g_crashExceptionMap[i - 1].str;    /* the end of map is "unknown reason" */
246 }
247 
FillCrashExceptionAndReport(const int err)248 static void FillCrashExceptionAndReport(const int err)
249 {
250     struct CrashDumpException exception;
251     memset(&exception, 0, sizeof(struct CrashDumpException));
252     exception.pid = g_request.pid;
253     exception.uid = (int32_t)(g_request.uid);
254     exception.error = err;
255     exception.time = (int64_t)(GetTimeMilliseconds());
256     (void)strncpy(exception.message, GetCrashDescription(err), sizeof(exception.message) - 1);
257     ReportException(exception);
258 }
259 
IsDumpSignal(int sig)260 static bool IsDumpSignal(int sig)
261 {
262     return sig == SIGDUMP || sig == SIGLEAK_STACK;
263 }
264 
FillDumpRequest(int sig,siginfo_t * si,void * context)265 static void FillDumpRequest(int sig, siginfo_t *si, void *context)
266 {
267     memset(&g_request, 0, sizeof(g_request));
268     g_request.type = sig;
269     g_request.pid = GetRealPid();
270     g_request.nsPid = syscall(SYS_getpid);
271     g_request.tid = syscall(SYS_gettid);
272     g_request.uid = getuid();
273     g_request.reserved = 0;
274     g_request.timeStamp = GetTimeMilliseconds();
275     g_request.fdTableAddr = (uint64_t)fdsan_get_fd_table();
276     memcpy(g_request.appRunningId, g_appRunningId, sizeof(g_request.appRunningId));
277     if (!IsDumpSignal(sig) && g_GetStackIdFunc!= NULL) {
278         g_request.stackId = g_GetStackIdFunc();
279         DFXLOG_INFO("g_GetStackIdFunc %p.", (void*)g_request.stackId);
280     }
281 
282     GetThreadNameByTid(g_request.tid, g_request.threadName, sizeof(g_request.threadName));
283     GetProcessName(g_request.processName, sizeof(g_request.processName));
284 
285     memcpy(&(g_request.siginfo), si, sizeof(siginfo_t));
286     memcpy(&(g_request.context), context, sizeof(ucontext_t));
287 
288     FillTraceIdLocked(&g_request);
289 
290     FillLastFatalMessageLocked(sig, context);
291     g_request.crashObj = (uintptr_t)pthread_getspecific(g_crashObjKey);
292 }
293 
InheritCapabilities(void)294 static int32_t InheritCapabilities(void)
295 {
296     struct __user_cap_header_struct capHeader;
297     memset(&capHeader, 0, sizeof(capHeader));
298 
299     capHeader.version = _LINUX_CAPABILITY_VERSION_3;
300     capHeader.pid = 0;
301     struct __user_cap_data_struct capData[2];
302     if (capget(&capHeader, &capData[0]) == -1) {
303         DFXLOG_ERROR("Failed to get origin cap data");
304         return -1;
305     }
306 
307     capData[0].inheritable = capData[0].permitted;
308     capData[1].inheritable = capData[1].permitted;
309     if (capset(&capHeader, &capData[0]) == -1) {
310         DFXLOG_ERROR("Failed to set cap data, errno(%d)", errno);
311         return -1;
312     }
313 
314     uint64_t ambCap = capData[0].inheritable;
315     ambCap = ambCap | (((uint64_t)capData[1].inheritable) << INHERITABLE_OFFSET);
316     for (size_t i = 0; i < NUMBER_SIXTYFOUR; i++) {
317         if (ambCap & ((uint64_t)1)) {
318             if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, i, 0, 0) < 0) {
319                 DFXLOG_ERROR("Failed to change the ambient capability set, errno(%d)", errno);
320             }
321         }
322         ambCap = ambCap >> 1;
323     }
324     return 0;
325 }
326 
327 static const int SIGCHAIN_DUMP_SIGNAL_LIST[] = {
328     SIGDUMP, SIGLEAK_STACK
329 };
330 
331 static const int SIGCHAIN_CRASH_SIGNAL_LIST[] = {
332     SIGILL, SIGABRT, SIGBUS, SIGFPE,
333     SIGSEGV, SIGSTKFLT, SIGSYS, SIGTRAP
334 };
335 
SetInterestedSignalMasks(int how)336 static void SetInterestedSignalMasks(int how)
337 {
338     sigset_t set;
339     sigemptyset(&set);
340     for (size_t i = 0; i < sizeof(SIGCHAIN_DUMP_SIGNAL_LIST) / sizeof(SIGCHAIN_DUMP_SIGNAL_LIST[0]); i++) {
341         sigaddset(&set, SIGCHAIN_DUMP_SIGNAL_LIST[i]);
342     }
343     for (size_t i = 0; i < sizeof(SIGCHAIN_CRASH_SIGNAL_LIST) / sizeof(SIGCHAIN_CRASH_SIGNAL_LIST[0]); i++) {
344         sigaddset(&set, SIGCHAIN_CRASH_SIGNAL_LIST[i]);
345     }
346     sigprocmask(how, &set, NULL);
347 }
348 
CloseFds(void)349 static void CloseFds(void)
350 {
351     const int closeFdCount = 1024;
352     for (int i = 0; i < closeFdCount; i++) {
353         syscall(SYS_close, i);
354     }
355 }
356 
DFX_SetUpEnvironment(void)357 static void DFX_SetUpEnvironment(void)
358 {
359     // clear stdout and stderr
360     int devNull = OHOS_TEMP_FAILURE_RETRY(open("/dev/null", O_RDWR));
361     if (devNull < 0) {
362         DFXLOG_ERROR("Failed to open dev/null.");
363         return;
364     }
365 
366     OHOS_TEMP_FAILURE_RETRY(dup2(devNull, STDOUT_FILENO));
367     OHOS_TEMP_FAILURE_RETRY(dup2(devNull, STDERR_FILENO));
368     syscall(SYS_close, devNull);
369     SetInterestedSignalMasks(SIG_BLOCK);
370 }
371 
DFX_SetUpSigAlarmAction(void)372 static void DFX_SetUpSigAlarmAction(void)
373 {
374     if (signal(SIGALRM, SIG_DFL) == SIG_ERR) {
375         DFXLOG_WARN("Default signal alarm error!");
376     }
377     sigset_t set;
378     sigemptyset(&set);
379     sigaddset(&set, SIGALRM);
380     sigprocmask(SIG_UNBLOCK, &set, NULL);
381 }
382 
DFX_ExecDump(void)383 static int DFX_ExecDump(void)
384 {
385     DFX_SetUpEnvironment();
386     DFX_SetUpSigAlarmAction();
387     alarm(ALARM_TIME_S);
388     int pipefd[2] = {-1, -1};
389     // create pipe for passing request to processdump
390     if (g_request.dumpMode == SPLIT_MODE) {
391         if (pipe(pipefd) != 0) {
392             DFXLOG_ERROR("Failed to create pipe for transfering context, errno(%d)", errno);
393             return CREATE_PIPE_FAIL;
394         }
395     } else {
396         pipefd[0] = g_pipeFds[WRITE_TO_DUMP][0];
397         pipefd[1] = g_pipeFds[WRITE_TO_DUMP][1];
398     }
399 
400     ssize_t writeLen = (long)(sizeof(struct ProcessDumpRequest));
401     if (fcntl(pipefd[1], F_SETPIPE_SZ, writeLen) < writeLen) {
402         DFXLOG_ERROR("Failed to set pipe buffer size, errno(%d).", errno);
403         return SET_PIPE_LEN_FAIL;
404     }
405 
406     struct iovec iovs[1] = {
407         {
408             .iov_base = &g_request,
409             .iov_len = sizeof(struct ProcessDumpRequest)
410         },
411     };
412     if (OHOS_TEMP_FAILURE_RETRY(writev(pipefd[1], iovs, 1)) != writeLen) {
413         DFXLOG_ERROR("Failed to write pipe, errno(%d)", errno);
414         return WRITE_PIPE_FAIL;
415     }
416     OHOS_TEMP_FAILURE_RETRY(dup2(pipefd[0], STDIN_FILENO));
417     if (pipefd[0] != STDIN_FILENO) {
418         syscall(SYS_close, pipefd[0]);
419     }
420     syscall(SYS_close, pipefd[1]);
421 
422     if (InheritCapabilities() != 0) {
423         DFXLOG_ERROR("Failed to inherit Capabilities from parent.");
424         FillCrashExceptionAndReport(CRASH_SIGNAL_EINHERITCAP);
425         return INHERIT_CAP_FAIL;
426     }
427     DFXLOG_INFO("execl processdump.");
428 #ifdef DFX_LOG_HILOG_BASE
429     execl("/system/bin/processdump", "processdump", "-signalhandler", NULL);
430 #else
431     execl("/bin/processdump", "processdump", "-signalhandler", NULL);
432 #endif
433     DFXLOG_ERROR("Failed to execl processdump, errno(%d)", errno);
434     FillCrashExceptionAndReport(CRASH_SIGNAL_EEXECL);
435     return errno;
436 }
437 
IsMainThread(void)438 static bool IsMainThread(void)
439 {
440     if (syscall(SYS_getpid) == 1) {
441         if (syscall(SYS_gettid) == 1) {
442             return true;
443         }
444     } else {
445         if (syscall(SYS_getpid) == syscall(SYS_gettid)) {
446             return true;
447         }
448     }
449     return false;
450 }
451 
ResetAndRethrowSignalIfNeed(int sig,siginfo_t * si)452 static void ResetAndRethrowSignalIfNeed(int sig, siginfo_t *si)
453 {
454     if (IsDumpSignal(sig)) {
455         return;
456     }
457 
458     if (g_oldSigactionList[sig].sa_sigaction == NULL) {
459         signal(sig, SIG_DFL);
460     } else if (sigaction(sig, &(g_oldSigactionList[sig]), NULL) != 0) {
461         DFXLOG_ERROR("Failed to reset sig(%d).", sig);
462         signal(sig, SIG_DFL);
463     }
464 
465     if (syscall(SYS_rt_tgsigqueueinfo, syscall(SYS_getpid), syscall(SYS_gettid), sig, si) != 0) {
466         DFXLOG_ERROR("Failed to rethrow sig(%d), errno(%d).", sig, errno);
467     } else {
468         DFXLOG_INFO("Current process(%ld) rethrow sig(%d).", syscall(SYS_getpid), sig);
469     }
470 }
471 
PauseMainThreadHandler(int sig)472 static void PauseMainThreadHandler(int sig)
473 {
474     DFXLOG_INFO("Crash(%d) in child thread(%ld), lock main thread.", sig, syscall(SYS_gettid));
475     // only work when subthread crash and send SIGDUMP to mainthread.
476     pthread_mutex_lock(&g_signalHandlerMutex);
477     pthread_mutex_unlock(&g_signalHandlerMutex);
478     DFXLOG_INFO("Crash in child thread(%ld), exit main thread.", syscall(SYS_gettid));
479 }
480 
BlockMainThreadIfNeed(int sig)481 static void BlockMainThreadIfNeed(int sig)
482 {
483     if (IsMainThread() || IsDumpSignal(sig)) {
484         return;
485     }
486 
487     DFXLOG_INFO("Try block main thread.");
488     (void)signal(SIGQUIT, PauseMainThreadHandler);
489     if (syscall(SYS_tgkill, syscall(SYS_getpid), syscall(SYS_getpid), SIGQUIT) != 0) {
490         DFXLOG_ERROR("Failed to send SIGQUIT to main thread, errno(%d).", errno);
491     }
492 }
493 
ForkBySyscall(void)494 static pid_t ForkBySyscall(void)
495 {
496 #ifdef SYS_fork
497     return syscall(SYS_fork);
498 #else
499     return syscall(SYS_clone, SIGCHLD, 0);
500 #endif
501 }
502 
SetDumpState(void)503 static bool SetDumpState(void)
504 {
505     if (prctl(PR_SET_DUMPABLE, 1) != 0) {
506         DFXLOG_ERROR("Failed to set dumpable, errno(%d).", errno);
507         return false;
508     }
509 
510     if (prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY) != 0) {
511         if (errno != EINVAL) {
512             DFXLOG_ERROR("Failed to set ptracer, errno(%d).", errno);
513             return false;
514         }
515     }
516     return true;
517 }
518 
RestoreDumpState(int prevState,bool isTracerStatusModified)519 static void RestoreDumpState(int prevState, bool isTracerStatusModified)
520 {
521     prctl(PR_SET_DUMPABLE, prevState);
522     if (isTracerStatusModified == true) {
523         prctl(PR_SET_PTRACER, 0);
524     }
525 }
526 
SetSelfThreadParam(const char * name,int priority)527 static void SetSelfThreadParam(const char* name, int priority)
528 {
529     pthread_setname_np(pthread_self(), name);
530     struct sched_param schedParam;
531     schedParam.sched_priority = priority;
532     pthread_setschedparam(pthread_self(), SCHED_FIFO, &schedParam);
533 }
534 
WaitProcessExit(int childPid,const char * name)535 static bool WaitProcessExit(int childPid, const char* name)
536 {
537     int ret = -1;
538     int status = 0;
539     int startTime = (int)time(NULL);
540     bool isSuccess = false;
541     DFXLOG_INFO("(%ld) wait %s(%d) exit.", syscall(SYS_gettid), name, childPid);
542     do {
543         errno = 0;
544         ret = waitpid(childPid, &status, WNOHANG);
545         if (ret < 0) {
546             DFXLOG_ERROR("Failed to wait child process terminated, errno(%d)", errno);
547             return isSuccess;
548         }
549 
550         if (ret == childPid) {
551             isSuccess = true;
552             break;
553         }
554 
555         if ((int)time(NULL) - startTime > PROCESSDUMP_TIMEOUT) {
556             DFXLOG_INFO("(%ld) wait for (%d) timeout", syscall(SYS_gettid), childPid);
557             isSuccess = false;
558             break;
559         }
560         usleep(SIGNALHANDLER_TIMEOUT); // sleep 10ms
561     } while (1);
562 
563     DFXLOG_INFO("(%ld) wait for %s(%d) return with ret(%d), status(%d)",
564         syscall(SYS_gettid), name, childPid, ret, status);
565     if (WIFEXITED(status)) {
566         int exitCode = WEXITSTATUS(status);
567         DFXLOG_INFO("wait %s(%d) exit code: %d", name, childPid, exitCode);
568     } else if (WIFSIGNALED(status)) {
569         int sigNum = WTERMSIG(status);
570         DFXLOG_INFO("wait %s(%d) exit with sig: %d", name, childPid, sigNum);
571     }
572     return isSuccess;
573 }
574 
ForkAndExecProcessDump(void)575 static int ForkAndExecProcessDump(void)
576 {
577     int childPid = -1;
578     SetSelfThreadParam("dump_tmp_thread", 0);
579 
580     // set privilege for dump ourself
581     int prevDumpableStatus = prctl(PR_GET_DUMPABLE);
582     bool isTracerStatusModified = SetDumpState();
583     if (!isTracerStatusModified) {
584         FillCrashExceptionAndReport(CRASH_SIGNAL_ESETSTATE);
585         goto out;
586     }
587 
588     // fork a child process that could ptrace us
589     childPid = ForkBySyscall();
590     if (childPid == 0) {
591         g_request.dumpMode = SPLIT_MODE;
592         DFXLOG_INFO("The exec processdump pid(%ld).", syscall(SYS_getpid));
593         _exit(DFX_ExecDump());
594     } else if (childPid < 0) {
595         DFXLOG_ERROR("Failed to fork child process, errno(%d).", errno);
596         FillCrashExceptionAndReport(CRASH_SIGNAL_EFORK);
597         goto out;
598     }
599     WaitProcessExit(childPid, "processdump");
600 out:
601     RestoreDumpState(prevDumpableStatus, isTracerStatusModified);
602     pthread_mutex_unlock(&g_signalHandlerMutex);
603     return 0;
604 }
605 
CloneAndDoProcessDump(void * arg)606 static int CloneAndDoProcessDump(void* arg)
607 {
608     (void)arg;
609     DFXLOG_INFO("The clone thread(%ld).", syscall(SYS_gettid));
610     g_request.recycleTid = syscall(SYS_gettid);
611     return ForkAndExecProcessDump();
612 }
613 
StartProcessdump(void)614 static bool StartProcessdump(void)
615 {
616     uint64_t startTime = GetAbsTimeMilliSeconds();
617     pid_t pid = ForkBySyscall();
618     if (pid < 0) {
619         DFXLOG_ERROR("Failed to fork dummy processdump(%d)", errno);
620         return false;
621     } else if (pid == 0) {
622         pid_t processDumpPid = ForkBySyscall();
623         if (processDumpPid < 0) {
624             DFXLOG_ERROR("Failed to fork processdump(%d)", errno);
625             _exit(0);
626         } else if (processDumpPid > 0) {
627             _exit(0);
628         } else {
629             uint64_t endTime;
630             int tid;
631             ParseSiValue(&g_request.siginfo, &endTime, &tid);
632             uint64_t curTime = GetAbsTimeMilliSeconds();
633             DFXLOG_INFO("start processdump, fork spend time %" PRIu64 "ms", curTime - startTime);
634             if (endTime != 0) {
635                 DFXLOG_INFO("dump remain %" PRId64 "ms", endTime - curTime);
636             }
637             if (endTime == 0 || endTime > curTime) {
638                 DFX_ExecDump();
639             } else {
640                 DFXLOG_INFO("%s", "current has spend all time, not execl processdump");
641             }
642             _exit(0);
643         }
644     }
645 
646     if (waitpid(pid, NULL, 0) <= 0) {
647         DFXLOG_ERROR("failed to wait dummy processdump(%d)", errno);
648         return false;
649     }
650     return true;
651 }
652 
StartVMProcessUnwind(void)653 static bool StartVMProcessUnwind(void)
654 {
655     uint32_t startTime = GetAbsTimeMilliSeconds();
656     pid_t pid = ForkBySyscall();
657     if (pid < 0) {
658         DFXLOG_ERROR("Failed to fork vm process(%d)", errno);
659         return false;
660     } else if (pid == 0) {
661         pid_t vmPid = ForkBySyscall();
662         if (vmPid == 0) {
663             DFXLOG_INFO("start vm process, fork spend time %" PRIu64 "ms", GetAbsTimeMilliSeconds() - startTime);
664             close(g_pipeFds[WRITE_TO_DUMP][0]);
665             pid_t pids[PID_MAX] = {0};
666             pids[REAL_PROCESS_PID] = GetRealPid();
667             pids[VIRTUAL_PROCESS_PID] = syscall(SYS_getpid);
668 
669             OHOS_TEMP_FAILURE_RETRY(write(g_pipeFds[WRITE_TO_DUMP][1], pids, sizeof(pids)));
670             close(g_pipeFds[WRITE_TO_DUMP][1]);
671 
672             uint32_t finishUnwind = OPE_FAIL;
673             close(g_pipeFds[READ_FORM_DUMP_TO_VIRTUAL][1]);
674             OHOS_TEMP_FAILURE_RETRY(read(g_pipeFds[READ_FORM_DUMP_TO_VIRTUAL][0], &finishUnwind, sizeof(finishUnwind)));
675             close(g_pipeFds[READ_FORM_DUMP_TO_VIRTUAL][0]);
676             DFXLOG_INFO("processdump unwind finish, exit vm pid = %d", pids[VIRTUAL_PROCESS_PID]);
677             _exit(0);
678         } else {
679             DFXLOG_INFO("exit dummy vm process");
680             _exit(0);
681         }
682     }
683 
684     if (waitpid(pid, NULL, 0) <= 0) {
685         DFXLOG_ERROR("failed to wait dummy vm process(%d)", errno);
686         return false;
687     }
688     return true;
689 }
690 
CleanFd(int * pipeFd)691 static void CleanFd(int *pipeFd)
692 {
693     if (*pipeFd != -1) {
694         close(*pipeFd);
695         *pipeFd = -1;
696     }
697 }
698 
CleanPipe(void)699 static void CleanPipe(void)
700 {
701     for (size_t i = 0; i < PIPE_MAX; i++) {
702         CleanFd(&g_pipeFds[i][0]);
703         CleanFd(&g_pipeFds[i][1]);
704     }
705 }
706 
InitPipe(void)707 static bool InitPipe(void)
708 {
709     for (int i = 0; i < PIPE_MAX; i++) {
710         if (pipe(g_pipeFds[i]) == -1) {
711             DFXLOG_ERROR("create pipe fail, errno(%d)", errno);
712             FillCrashExceptionAndReport(CRASH_SIGNAL_ECREATEPIPE);
713             CleanPipe();
714             return false;
715         }
716     }
717 
718     g_request.pmPipeFd[0] = g_pipeFds[READ_FROM_DUMP_TO_MAIN][0];
719     g_request.pmPipeFd[1] = g_pipeFds[READ_FROM_DUMP_TO_MAIN][1];
720     g_request.vmPipeFd[0] = g_pipeFds[READ_FORM_DUMP_TO_VIRTUAL][0];
721     g_request.vmPipeFd[1] = g_pipeFds[READ_FORM_DUMP_TO_VIRTUAL][1];
722     return true;
723 }
724 
ReadPipeTimeout(int fd,uint64_t timeout,uint32_t * value)725 static bool ReadPipeTimeout(int fd, uint64_t timeout, uint32_t* value)
726 {
727     if (fd < 0 || value == NULL) {
728         return false;
729     }
730     struct pollfd pfds[1];
731     pfds[0].fd = fd;
732     pfds[0].events = POLLIN;
733 
734     uint64_t startTime = GetTimeMilliseconds();
735     uint64_t endTime = startTime + timeout;
736     int pollRet = -1;
737     do {
738         pollRet = poll(pfds, 1, timeout);
739         if ((pollRet > 0) && (pfds[0].revents && POLLIN)) {
740             if (OHOS_TEMP_FAILURE_RETRY(read(fd, value, sizeof(uint32_t))) ==
741                 (long int)(sizeof(uint32_t))) {
742                 return true;
743             }
744         }
745 
746         uint64_t now = GetTimeMilliseconds();
747         if (now >= endTime || now < startTime) {
748             break;
749         } else {
750             timeout = endTime - now;
751         }
752     } while (pollRet < 0 && errno == EINTR);
753     FillCrashExceptionAndReport(CRASH_SIGNAL_EREADPIPE);
754     DFXLOG_ERROR("read pipe failed , errno(%d)", errno);
755     return false;
756 }
757 
ReadProcessDumpGetRegsMsg(void)758 static bool ReadProcessDumpGetRegsMsg(void)
759 {
760     CleanFd(&g_pipeFds[READ_FROM_DUMP_TO_MAIN][1]);
761 
762     DFXLOG_INFO("start wait processdump read registers");
763     const uint64_t readRegsTimeout = 5000; // 5s
764     uint32_t isFinishGetRegs = OPE_FAIL;
765     if (ReadPipeTimeout(g_pipeFds[READ_FROM_DUMP_TO_MAIN][0], readRegsTimeout, &isFinishGetRegs)) {
766         if (isFinishGetRegs == OPE_SUCCESS) {
767             DFXLOG_INFO("processdump have get all registers .");
768             return true;
769         }
770     }
771 
772     return false;
773 }
774 
ReadUnwindFinishMsg(int sig)775 static void ReadUnwindFinishMsg(int sig)
776 {
777     if (sig == SIGDUMP) {
778         return;
779     }
780 
781     DFXLOG_INFO("start wait processdump unwind");
782     const uint64_t unwindTimeout = 10000; // 10s
783     uint32_t isExitAfterUnwind = OPE_CONTINUE;
784     if (ReadPipeTimeout(g_pipeFds[READ_FROM_DUMP_TO_MAIN][0], unwindTimeout, &isExitAfterUnwind)) {
785         DFXLOG_INFO("processdump unwind finish");
786     } else {
787         DFXLOG_ERROR("wait processdump unwind finish timeout");
788     }
789 }
790 
ProcessDump(int sig)791 static int ProcessDump(int sig)
792 {
793     int prevDumpableStatus = prctl(PR_GET_DUMPABLE);
794     bool isTracerStatusModified = SetDumpState();
795 
796     if (!InitPipe()) {
797         return -1;
798     }
799     g_request.dumpMode = FUSION_MODE;
800 
801     do {
802         uint64_t endTime;
803         int tid;
804         ParseSiValue(&g_request.siginfo, &endTime, &tid);
805         if (endTime != 0 && endTime <= GetAbsTimeMilliSeconds()) {
806             DFXLOG_INFO("%s", "enter processdump has coat all time, just exit");
807             break;
808         }
809         if (!StartProcessdump()) {
810             DFXLOG_ERROR("start processdump fail");
811             break;
812         }
813 
814         if (!ReadProcessDumpGetRegsMsg()) {
815             break;
816         }
817 
818         if (!StartVMProcessUnwind()) {
819             DFXLOG_ERROR("start vm process unwind fail");
820             break;
821         }
822         ReadUnwindFinishMsg(sig);
823     } while (false);
824 
825     CleanPipe();
826     DFXLOG_INFO("process dump end");
827     RestoreDumpState(prevDumpableStatus, isTracerStatusModified);
828     return 0;
829 }
830 
ForkAndDoProcessDump(int sig)831 static void ForkAndDoProcessDump(int sig)
832 {
833     int prevDumpableStatus = prctl(PR_GET_DUMPABLE);
834     bool isTracerStatusModified = SetDumpState();
835     int childPid = ForkBySyscall();
836     if (childPid == 0) {
837         CloseFds();
838         g_request.vmNsPid = syscall(SYS_getpid);
839         g_request.vmPid = GetRealPid();
840         DFXLOG_INFO("The vm pid(%d:%d).", g_request.vmPid, g_request.vmNsPid);
841         DFX_SetUpSigAlarmAction();
842         alarm(ALARM_TIME_S);
843         _exit(ForkAndExecProcessDump());
844     } else if (childPid < 0) {
845         DFXLOG_ERROR("Failed to fork child process, errno(%d).", errno);
846         RestoreDumpState(prevDumpableStatus, isTracerStatusModified);
847         ForkAndExecProcessDump();
848         return;
849     }
850 
851     DFXLOG_INFO("Start wait for VmProcess(%d) exit.", childPid);
852     errno = 0;
853     if (!WaitProcessExit(childPid, "VmProcess") &&
854         sig != SIGDUMP &&
855         sig != SIGLEAK_STACK) {
856         DFXLOG_INFO("Wait VmProcess(%d) exit timeout in handling critical signal.", childPid);
857         FillCrashExceptionAndReport(CRASH_SIGNAL_EWAITEXIT);
858         // do not left vm process
859         kill(childPid, SIGKILL);
860     }
861 
862     RestoreDumpState(prevDumpableStatus, isTracerStatusModified);
863     pthread_mutex_unlock(&g_signalHandlerMutex);
864 }
865 
DFX_SigchainHandler(int sig,siginfo_t * si,void * context)866 static bool DFX_SigchainHandler(int sig, siginfo_t *si, void *context)
867 {
868     int pid = syscall(SYS_getpid);
869     int tid = syscall(SYS_gettid);
870 
871     DFXLOG_INFO("DFX_SigchainHandler :: sig(%d), pid(%d), tid(%d).", sig, pid, tid);
872     bool ret = false;
873     if (sig == SIGDUMP) {
874         if (si->si_code != DUMP_TYPE_REMOTE) {
875             DFXLOG_WARN("DFX_SigchainHandler :: sig(%d:%d) is not remote dump type, return directly",
876                         sig, si->si_code);
877             return true;
878         }
879     }
880 
881     // crash signal should never be skipped
882     pthread_mutex_lock(&g_signalHandlerMutex);
883     if (!IsDumpSignal(g_prevHandledSignal)) {
884         pthread_mutex_unlock(&g_signalHandlerMutex);
885         return ret;
886     }
887     BlockMainThreadIfNeed(sig);
888     g_prevHandledSignal = sig;
889 
890     FillDumpRequest(sig, si, context);
891     DFXLOG_INFO("DFX_SigchainHandler :: sig(%d), pid(%d), processName(%s), threadName(%s).",
892         sig, g_request.pid, g_request.processName, g_request.threadName);
893     if (ProcessDump(sig) == 0) {
894         ret = sig == SIGDUMP || sig == SIGLEAK_STACK;
895         DFXLOG_INFO("Finish handle signal(%d) in %d:%d", sig, g_request.pid, g_request.tid);
896         pthread_mutex_unlock(&g_signalHandlerMutex);
897         return ret;
898     }
899     // for protecting g_reservedChildStack
900     // g_signalHandlerMutex will be unlocked in ForkAndExecProcessDump function
901     if (sig != SIGDUMP) {
902         ret = sig == SIGLEAK_STACK ? true : false;
903         ForkAndDoProcessDump(sig);
904     } else {
905         ret = true;
906         int recycleTid = clone(CloneAndDoProcessDump, g_reservedChildStack,\
907             CLONE_THREAD | CLONE_SIGHAND | CLONE_VM, NULL);
908         if (recycleTid == -1) {
909             DFXLOG_ERROR("Failed to clone thread for recycle dump process, errno(%d)", errno);
910             pthread_mutex_unlock(&g_signalHandlerMutex);
911         }
912     }
913 
914     DFXLOG_INFO("Finish handle signal(%d) in %d:%d", sig, g_request.pid, g_request.tid);
915     return ret;
916 }
917 
DFX_SignalHandler(int sig,siginfo_t * si,void * context)918 static void DFX_SignalHandler(int sig, siginfo_t *si, void *context)
919 {
920     DFX_SigchainHandler(sig, si, context);
921     ResetAndRethrowSignalIfNeed(sig, si);
922 }
923 
InstallSigActionHandler(int sig)924 static void InstallSigActionHandler(int sig)
925 {
926     struct sigaction action;
927     memset(&action, 0, sizeof(action));
928     memset(&g_oldSigactionList, 0, sizeof(g_oldSigactionList));
929     sigfillset(&action.sa_mask);
930     action.sa_sigaction = DFX_SignalHandler;
931     action.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
932     if (sigaction(sig, &action, &(g_oldSigactionList[sig])) != 0) {
933         DFXLOG_ERROR("Failed to register signal(%d)", sig);
934     }
935 }
936 
DFX_InstallSignalHandler(void)937 void DFX_InstallSignalHandler(void)
938 {
939     if (g_hasInit) {
940         return;
941     }
942 
943     InitCallbackItems();
944     // reserve stack for fork
945     g_reservedChildStack = mmap(NULL, RESERVED_CHILD_STACK_SIZE, \
946         PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, 1, 0);
947     if (g_reservedChildStack == NULL) {
948         DFXLOG_ERROR("Failed to alloc memory for child stack.");
949         return;
950     }
951     g_reservedChildStack = (void *)(((uint8_t *)g_reservedChildStack) + RESERVED_CHILD_STACK_SIZE - 1);
952 
953     struct signal_chain_action sigchain = {
954         .sca_sigaction = DFX_SigchainHandler,
955         .sca_mask = {},
956         .sca_flags = 0,
957     };
958 
959     for (size_t i = 0; i < sizeof(SIGCHAIN_DUMP_SIGNAL_LIST) / sizeof(SIGCHAIN_DUMP_SIGNAL_LIST[0]); i++) {
960         int32_t sig = SIGCHAIN_DUMP_SIGNAL_LIST[i];
961         sigfillset(&sigchain.sca_mask);
962         // dump signal not mask crash signal
963         for (size_t j = 0; j < sizeof(SIGCHAIN_CRASH_SIGNAL_LIST) / sizeof(SIGCHAIN_CRASH_SIGNAL_LIST[0]); j++) {
964             sigdelset(&sigchain.sca_mask, SIGCHAIN_CRASH_SIGNAL_LIST[j]);
965         }
966         add_special_handler_at_last(sig, &sigchain);
967     }
968     for (size_t i = 0; i < sizeof(SIGCHAIN_CRASH_SIGNAL_LIST) / sizeof(SIGCHAIN_CRASH_SIGNAL_LIST[0]); i++) {
969         int32_t sig = SIGCHAIN_CRASH_SIGNAL_LIST[i];
970         if (sig == SIGILL || sig == SIGSYS) {
971             InstallSigActionHandler(sig);
972         } else {
973             sigfillset(&sigchain.sca_mask);
974             add_special_handler_at_last(sig, &sigchain);
975         }
976     }
977 
978     g_hasInit = TRUE;
979     if (pthread_key_create(&g_crashObjKey, NULL) == 0) {
980         g_crashObjInit = true;
981     }
982 }
983 
DFX_SetAppRunningUniqueId(const char * appRunningId,size_t len)984 int DFX_SetAppRunningUniqueId(const char* appRunningId, size_t len)
985 {
986     size_t appRunningIdMaxLen = sizeof(g_appRunningId);
987     if (appRunningId == NULL || appRunningIdMaxLen <= len) {
988         DFXLOG_ERROR("param error. appRunningId is NULL or length overflow");
989         return -1;
990     }
991     memset(g_appRunningId, 0, appRunningIdMaxLen);
992     memcpy(g_appRunningId, appRunningId, len);
993     return 0;
994 }
995 
DFX_SetCrashObj(uint8_t type,uintptr_t addr)996 uintptr_t DFX_SetCrashObj(uint8_t type, uintptr_t addr)
997 {
998     if (!g_crashObjInit) {
999         return 0;
1000     }
1001 #if defined __LP64__
1002     uintptr_t origin = (uintptr_t)pthread_getspecific(g_crashObjKey);
1003     uintptr_t crashObj = 0;
1004     const int moveBit = 56;
1005     crashObj = ((uintptr_t)type << moveBit) | (addr & 0x00ffffffffffffff);
1006     pthread_setspecific(g_crashObjKey, (void*)(crashObj));
1007     return origin;
1008 #endif
1009     return 0;
1010 }
1011 
DFX_ResetCrashObj(uintptr_t crashObj)1012 void DFX_ResetCrashObj(uintptr_t crashObj)
1013 {
1014     if (!g_crashObjInit) {
1015         return;
1016     }
1017 #if defined __LP64__
1018     pthread_setspecific(g_crashObjKey, (void*)(crashObj));
1019 #endif
1020 }