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 <pthread.h>
23 #include <sched.h>
24 #include <signal.h>
25 #include <stdint.h>
26 #include <stdio.h>
27 #include <sys/capability.h>
28 #include <sys/mman.h>
29 #include <sys/prctl.h>
30 #include <sys/syscall.h>
31 #include <sys/time.h>
32 #include <sys/types.h>
33 #include <sys/uio.h>
34 #include <sys/wait.h>
35 #include <time.h>
36 #include <unistd.h>
37 #include "dfx_define.h"
38 #include "errno.h"
39 #include "linux/capability.h"
40 #include "stdbool.h"
41 #include "string.h"
42 #ifndef DFX_SIGNAL_LIBC
43 #include <securec.h>
44 #include "dfx_cutil.h"
45 #include "dfx_log.h"
46 #else
47 #include "musl_cutil.h"
48 #include "musl_log.h"
49 #endif
50 #if defined(CRASH_LOCAL_HANDLER)
51 #include "dfx_crash_local_handler.h"
52 #endif
53
54 #ifdef LOG_DOMAIN
55 #undef LOG_DOMAIN
56 #define LOG_DOMAIN 0xD002D11
57 #endif
58
59 #ifdef LOG_TAG
60 #undef LOG_TAG
61 #define LOG_TAG "DfxSignalHandler"
62 #endif
63
64 #if defined (__LP64__)
65 #define RESERVED_CHILD_STACK_SIZE (32 * 1024) // 32K
66 #else
67 #define RESERVED_CHILD_STACK_SIZE (16 * 1024) // 16K
68 #endif
69
70 #define BOOL int
71 #define TRUE 1
72 #define FALSE 0
73
74 #ifndef NSIG
75 #define NSIG 64
76 #endif
77
78 #ifndef F_SETPIPE_SZ
79 #define F_SETPIPE_SZ 1031
80 #endif
81
82 #define NUMBER_SIXTYFOUR 64
83 #define INHERITABLE_OFFSET 32
84
85 #ifndef __MUSL__
InitHandler(void)86 void __attribute__((constructor)) InitHandler(void)
87 {
88 DFX_InstallSignalHandler();
89 }
90 #endif
91
92 static struct ProcessDumpRequest g_request;
93 static struct ProcInfo g_procInfo;
94 static void *g_reservedChildStack;
95 static pthread_mutex_t g_signalHandlerMutex = PTHREAD_MUTEX_INITIALIZER;
96 static int g_pipefd[2] = {-1, -1};
97 static BOOL g_hasInit = FALSE;
98 static const int SIGNALHANDLER_TIMEOUT = 10000; // 10000 us
99 static const int ALARM_TIME_S = 10;
100 static int g_prevHandledSignal = SIGDUMP;
101 static BOOL g_isDumping = FALSE;
102 static struct sigaction g_oldSigactionList[NSIG] = {};
103
104 enum DumpPreparationStage {
105 CREATE_PIPE_FAIL = 1,
106 SET_PIPE_LEN_FAIL,
107 WRITE_PIPE_FAIL,
108 INHERIT_CAP_FAIL,
109 EXEC_FAIL,
110 };
111
112 TraceInfo HiTraceGetId(void) __attribute__((weak));
FillTraceIdLocked(struct ProcessDumpRequest * request)113 static void FillTraceIdLocked(struct ProcessDumpRequest* request)
114 {
115 if (HiTraceGetId == NULL || request == NULL) {
116 return;
117 }
118
119 TraceInfo id = HiTraceGetId();
120 memcpy(&(request->traceInfo), &id, sizeof(TraceInfo));
121 }
122
123 const char* GetLastFatalMessage(void) __attribute__((weak));
FillLastFatalMessageLocked(int32_t sig)124 static void FillLastFatalMessageLocked(int32_t sig)
125 {
126 if (sig != SIGABRT) {
127 return;
128 }
129
130 if (GetLastFatalMessage == NULL) {
131 DfxLogError("Could not find GetLastFatalMessage func");
132 return;
133 }
134
135 const char* lastFatalMessage = GetLastFatalMessage();
136 if (lastFatalMessage == NULL) {
137 DfxLogError("Could not find last message");
138 return;
139 }
140
141 size_t len = strlen(lastFatalMessage);
142 if (len > MAX_FATAL_MSG_SIZE) {
143 DfxLogError("Last message is longer than MAX_FATAL_MSG_SIZE");
144 return;
145 }
146
147 (void)strncpy(g_request.lastFatalMessage, lastFatalMessage, sizeof(g_request.lastFatalMessage) - 1);
148 }
149
InheritCapabilities(void)150 static int32_t InheritCapabilities(void)
151 {
152 struct __user_cap_header_struct capHeader;
153 memset(&capHeader, 0, sizeof(capHeader));
154
155 capHeader.version = _LINUX_CAPABILITY_VERSION_3;
156 capHeader.pid = 0;
157 struct __user_cap_data_struct capData[2];
158 if (capget(&capHeader, &capData[0]) == -1) {
159 DfxLogError("Failed to get origin cap data");
160 return -1;
161 }
162
163 capData[0].inheritable = capData[0].permitted;
164 capData[1].inheritable = capData[1].permitted;
165 if (capset(&capHeader, &capData[0]) == -1) {
166 DfxLogError("Failed to set cap data");
167 return -1;
168 }
169
170 uint64_t ambCap = capData[0].inheritable;
171 ambCap = ambCap | (((uint64_t)capData[1].inheritable) << INHERITABLE_OFFSET);
172 for (size_t i = 0; i < NUMBER_SIXTYFOUR; i++) {
173 if (ambCap & ((uint64_t)1)) {
174 (void)prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, i, 0, 0);
175 }
176 ambCap = ambCap >> 1;
177 }
178 return 0;
179 }
180
181 static const int g_interestedSignalList[] = {
182 SIGABRT, SIGBUS, SIGDUMP, SIGFPE, SIGILL,
183 SIGSEGV, SIGSTKFLT, SIGSYS, SIGTRAP,
184 };
185
SetInterestedSignalMasks(int how)186 static void SetInterestedSignalMasks(int how)
187 {
188 sigset_t set;
189 sigemptyset(&set);
190 for (size_t i = 0; i < sizeof(g_interestedSignalList) / sizeof(g_interestedSignalList[0]); i++) {
191 sigaddset(&set, g_interestedSignalList[i]);
192 }
193 sigprocmask(how, &set, NULL);
194 }
195
DFX_SetUpEnvironment()196 static void DFX_SetUpEnvironment()
197 {
198 // avoiding fd exhaust
199 const int closeFdCount = 1024;
200 for (int i = 0; i < closeFdCount; i++) {
201 syscall(SYS_close, i);
202 }
203 // clear stdout and stderr
204 int devNull = OHOS_TEMP_FAILURE_RETRY(open("/dev/null", O_RDWR));
205 if (devNull < 0) {
206 DfxLogError("Failed to open dev/null.");
207 return;
208 }
209
210 OHOS_TEMP_FAILURE_RETRY(dup2(devNull, STDOUT_FILENO));
211 OHOS_TEMP_FAILURE_RETRY(dup2(devNull, STDERR_FILENO));
212 syscall(SYS_close, devNull);
213 SetInterestedSignalMasks(SIG_BLOCK);
214 }
215
DFX_SetUpSigAlarmAction(void)216 static void DFX_SetUpSigAlarmAction(void)
217 {
218 if (signal(SIGALRM, SIG_DFL) == SIG_ERR) {
219 DfxLogError("signal error!");
220 }
221 sigset_t set;
222 sigemptyset(&set);
223 sigaddset(&set, SIGALRM);
224 sigprocmask(SIG_UNBLOCK, &set, NULL);
225 }
226
DFX_ExecDump(void * arg)227 static int DFX_ExecDump(void *arg)
228 {
229 (void)arg;
230 DFX_SetUpEnvironment();
231 DFX_SetUpSigAlarmAction();
232 alarm(ALARM_TIME_S);
233 // create pipe for passing request to processdump
234 if (pipe(g_pipefd) != 0) {
235 DfxLogError("Failed to create pipe for transfering context.");
236 return CREATE_PIPE_FAIL;
237 }
238 ssize_t writeLen = (long)(sizeof(struct ProcessDumpRequest));
239 if (fcntl(g_pipefd[1], F_SETPIPE_SZ, writeLen) < writeLen) {
240 DfxLogError("Failed to set pipe buffer size.");
241 return SET_PIPE_LEN_FAIL;
242 }
243
244 struct iovec iovs[1] = {
245 {
246 .iov_base = &g_request,
247 .iov_len = sizeof(struct ProcessDumpRequest)
248 },
249 };
250 ssize_t realWriteSize = OHOS_TEMP_FAILURE_RETRY(writev(g_pipefd[1], iovs, 1));
251 if ((ssize_t)writeLen != realWriteSize) {
252 DfxLogError("Failed to write pipe.");
253 return WRITE_PIPE_FAIL;
254 }
255 OHOS_TEMP_FAILURE_RETRY(dup2(g_pipefd[0], STDIN_FILENO));
256 if (g_pipefd[0] != STDIN_FILENO) {
257 syscall(SYS_close, g_pipefd[0]);
258 }
259 syscall(SYS_close, g_pipefd[1]);
260
261 if (InheritCapabilities() != 0) {
262 DfxLogError("Failed to inherit Capabilities from parent.");
263 return INHERIT_CAP_FAIL;
264 }
265 DfxLogInfo("execl processdump.");
266 #ifdef DFX_LOG_USE_HILOG_BASE
267 execl("/system/bin/processdump", "processdump", "-signalhandler", NULL);
268 #else
269 execl("/bin/processdump", "processdump", "-signalhandler", NULL);
270 #endif
271 DfxLogError("Failed to execl processdump, errno: %d(%s)", errno, strerror(errno));
272 return errno;
273 }
274
GetPid(void)275 static pid_t GetPid(void)
276 {
277 return g_procInfo.pid;
278 }
279
GetTid(void)280 static pid_t GetTid(void)
281 {
282 return g_procInfo.tid;
283 }
284
IsMainThread(void)285 static bool IsMainThread(void)
286 {
287 if (g_procInfo.ns) {
288 if (GetTid() == 1) {
289 return true;
290 }
291 } else {
292 if (GetPid() == GetTid()) {
293 return true;
294 }
295 }
296 return false;
297 }
298
ResetSignalHandlerIfNeed(int sig)299 static void ResetSignalHandlerIfNeed(int sig)
300 {
301 if (sig == SIGDUMP) {
302 return;
303 }
304
305 if (g_oldSigactionList[sig].sa_sigaction == NULL) {
306 signal(sig, SIG_DFL);
307 // real init will not handle crash signal
308 // crash in pid namespace may not exit even if rethrow the signal
309 // use exit instead
310 if (GetPid() == 1) {
311 DfxLogError("Sandbox process is about to exit with signal %d.", sig);
312 _exit(sig);
313 }
314 return;
315 }
316
317 if (sigaction(sig, &(g_oldSigactionList[sig]), NULL) != 0) {
318 DfxLogError("Failed to reset signal.");
319 signal(sig, SIG_DFL);
320 }
321 }
322
PauseMainThreadHandler(int sig)323 static void PauseMainThreadHandler(int sig)
324 {
325 // only work when subthread crash and send SIGDUMP to mainthread.
326 pthread_mutex_lock(&g_signalHandlerMutex);
327 pthread_mutex_unlock(&g_signalHandlerMutex);
328 DfxLogInfo("Crash in child thread(%d), exit main thread.", GetTid());
329 }
330
BlockMainThreadIfNeed(int sig)331 static void BlockMainThreadIfNeed(int sig)
332 {
333 if (IsMainThread() || (sig == SIGDUMP)) {
334 return;
335 }
336
337 DfxLogInfo("Crash(%d) in child thread(%d), try stop main thread.", sig, GetTid());
338 (void)signal(SIGDUMP, PauseMainThreadHandler);
339 if (syscall(SYS_tgkill, GetPid(), GetPid(), SIGDUMP) != 0) {
340 DfxLogError("Failed to send SIGDUMP to main thread, errno(%d).", errno);
341 }
342 }
343
ForkBySyscall(void)344 static pid_t ForkBySyscall(void)
345 {
346 #ifdef SYS_fork
347 return syscall(SYS_fork);
348 #else
349 return syscall(SYS_clone, SIGCHLD, 0);
350 #endif
351 }
352
SetDumpState(void)353 static bool SetDumpState(void)
354 {
355 if (prctl(PR_SET_DUMPABLE, 1) != 0) {
356 DfxLogError("Failed to set dumpable.");
357 return false;
358 }
359
360 if (prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY) != 0) {
361 if (errno != EINVAL) {
362 DfxLogError("Failed to set ptracer.");
363 return false;
364 }
365 }
366 return true;
367 }
368
RestoreDumpState(int prevState,bool isTracerStatusModified)369 static void RestoreDumpState(int prevState, bool isTracerStatusModified)
370 {
371 prctl(PR_SET_DUMPABLE, prevState);
372 if (isTracerStatusModified == true) {
373 prctl(PR_SET_PTRACER, 0);
374 }
375 }
376
DoProcessDump(void * arg)377 static int DoProcessDump(void* arg)
378 {
379 (void)arg;
380 int status;
381 int ret = -1;
382 int childPid = -1;
383 int startTime = (int)time(NULL);
384 bool isTimeout = false;
385 g_request.recycleTid = syscall(SYS_gettid);
386 // set privilege for dump ourself
387 int prevDumpableStatus = prctl(PR_GET_DUMPABLE);
388 bool isTracerStatusModified = SetDumpState();
389 if (!isTracerStatusModified) {
390 goto out;
391 }
392
393 // fork a child process that could ptrace us
394 childPid = ForkBySyscall();
395 if (childPid == 0) {
396 _exit(DFX_ExecDump(NULL));
397 } else if (childPid < 0) {
398 DfxLogError("Failed to fork child process, errno(%d).", errno);
399 goto out;
400 }
401
402 do {
403 errno = 0;
404 ret = waitpid(childPid, &status, WNOHANG);
405 if (ret < 0) {
406 DfxLogError("Failed to wait child process terminated, errno(%d)", errno);
407 goto out;
408 }
409
410 if (ret == childPid) {
411 break;
412 }
413
414 if ((int)time(NULL) - startTime > PROCESSDUMP_TIMEOUT) {
415 isTimeout = true;
416 break;
417 }
418 usleep(SIGNALHANDLER_TIMEOUT); // sleep 10ms
419 } while (1);
420 DfxLogInfo("(%d) wait for process(%d) return with ret(%d) status(%d) timeout(%d)",
421 g_request.recycleTid, childPid, ret, status, isTimeout);
422 out:
423 #if defined(CRASH_LOCAL_HANDLER)
424 if ((g_prevHandledSignal != SIGDUMP) && ((isTimeout) || ((ret >= 0) && (status != 0)))) {
425 CrashLocalHandler(&g_request);
426 }
427 #endif
428 g_isDumping = FALSE;
429 RestoreDumpState(prevDumpableStatus, isTracerStatusModified);
430 pthread_mutex_unlock(&g_signalHandlerMutex);
431 return 0;
432 }
433
UnlockSignalHandlerMutex(void)434 static void UnlockSignalHandlerMutex(void)
435 {
436 if (pthread_mutex_trylock(&g_signalHandlerMutex) == 0) {
437 pthread_mutex_unlock(&g_signalHandlerMutex);
438 } else {
439 pthread_mutex_unlock(&g_signalHandlerMutex);
440 }
441 }
442
ForkAndDoProcessDump(void)443 static void ForkAndDoProcessDump(void)
444 {
445 int prevDumpableStatus = prctl(PR_GET_DUMPABLE);
446 bool isTracerStatusModified = SetDumpState();
447 int childPid = ForkBySyscall();
448 if (childPid == 0) {
449 g_request.vmPid = syscall(SYS_getpid);
450 DfxLogInfo("Start DoProcessDump in VmProcess(%d).", g_request.vmPid);
451 alarm(ALARM_TIME_S);
452 _exit(DoProcessDump(NULL));
453 } else if (childPid < 0) {
454 DfxLogError("Failed to vfork child process, errno(%d).", errno);
455 RestoreDumpState(prevDumpableStatus, isTracerStatusModified);
456 DoProcessDump(NULL);
457 return;
458 }
459
460 DfxLogInfo("Start wait for VmProcess(%d) exit.", childPid);
461 errno = 0;
462 int status;
463 int ret = waitpid(childPid, &status, 0);
464 RestoreDumpState(prevDumpableStatus, isTracerStatusModified);
465 DfxLogInfo("(%d) wait for VmProcess(%d) return with ret(%d) status(%d)",
466 getpid(), childPid, ret, status);
467 }
468
DFX_SignalHandler(int sig,siginfo_t * si,void * context)469 static void DFX_SignalHandler(int sig, siginfo_t *si, void *context)
470 {
471 if (sig == SIGDUMP && g_isDumping) {
472 DfxLogInfo("Current Process is dumping stacktrace now.");
473 return;
474 }
475
476 // crash signal should never be skipped
477 pthread_mutex_lock(&g_signalHandlerMutex);
478 memset(&g_procInfo, 0, sizeof(g_procInfo));
479 GetProcStatus(&g_procInfo);
480 BlockMainThreadIfNeed(sig);
481 if (g_prevHandledSignal != SIGDUMP) {
482 ResetSignalHandlerIfNeed(sig);
483 if (syscall(SYS_rt_tgsigqueueinfo, GetPid(), GetTid(), si->si_signo, si) != 0) {
484 DfxLogError("Failed to resend signal(%d), errno(%d).", si->si_signo, errno);
485 } else {
486 DfxLogInfo("Current process has encount a crash, rethrow sig(%d).", si->si_signo);
487 }
488 return;
489 }
490 g_prevHandledSignal = sig;
491 g_isDumping = TRUE;
492 memset(&g_request, 0, sizeof(g_request));
493 g_request.type = sig;
494 g_request.pid = GetPid();
495 g_request.tid = syscall(SYS_gettid);
496 g_request.uid = getuid();
497 g_request.reserved = 0;
498 g_request.timeStamp = GetTimeMilliseconds();
499 DfxLogInfo("DFX_SignalHandler :: sig(%d), pid(%d), tid(%d).", sig, g_request.pid, g_request.tid);
500
501 GetThreadName(g_request.threadName, sizeof(g_request.threadName));
502 GetProcessName(g_request.processName, sizeof(g_request.processName));
503
504 memcpy(&(g_request.siginfo), si, sizeof(siginfo_t));
505 memcpy(&(g_request.context), context, sizeof(ucontext_t));
506
507 FillTraceIdLocked(&g_request);
508 FillLastFatalMessageLocked(sig);
509
510 // for protecting g_reservedChildStack
511 // g_signalHandlerMutex will be unlocked in DoProcessDump function
512 if (sig != SIGDUMP) {
513 ForkAndDoProcessDump();
514 ResetSignalHandlerIfNeed(sig);
515 if (syscall(SYS_rt_tgsigqueueinfo, syscall(SYS_getpid), syscall(SYS_gettid), si->si_signo, si) != 0) {
516 DfxLogError("Failed to resend signal(%d), errno(%d).", si->si_signo, errno);
517 }
518 UnlockSignalHandlerMutex();
519 } else {
520 int recycleTid = clone(DoProcessDump, g_reservedChildStack, CLONE_THREAD | CLONE_SIGHAND | CLONE_VM, NULL);
521 if (recycleTid == -1) {
522 DfxLogError("Failed to create thread for recycle dump process");
523 pthread_mutex_unlock(&g_signalHandlerMutex);
524 }
525 }
526
527 DfxLogInfo("Finish handle signal(%d) in %d:%d", sig, g_request.pid, g_request.tid);
528 }
529
DFX_InstallSignalHandler(void)530 void DFX_InstallSignalHandler(void)
531 {
532 if (g_hasInit) {
533 return;
534 }
535
536 // reserve stack for fork
537 g_reservedChildStack = mmap(NULL, RESERVED_CHILD_STACK_SIZE, \
538 PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, 1, 0);
539 if (g_reservedChildStack == NULL) {
540 DfxLogError("Failed to alloc memory for child stack.");
541 return;
542 }
543 g_reservedChildStack = (void *)(((uint8_t *)g_reservedChildStack) + RESERVED_CHILD_STACK_SIZE - 1);
544
545 struct sigaction action;
546 memset(&action, 0, sizeof(action));
547 memset(&g_oldSigactionList, 0, sizeof(g_oldSigactionList));
548 sigfillset(&action.sa_mask);
549 action.sa_sigaction = DFX_SignalHandler;
550 action.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
551
552 for (size_t i = 0; i < sizeof(g_interestedSignalList) / sizeof(g_interestedSignalList[0]); i++) {
553 int32_t sig = g_interestedSignalList[i];
554 if (sigaction(sig, &action, &(g_oldSigactionList[sig])) != 0) {
555 DfxLogError("Failed to register signal(%d)", sig);
556 }
557 }
558
559 g_hasInit = TRUE;
560 }
561