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__
93void __attribute__((constructor)) InitHandler(void)
94{
95    DFX_InstallSignalHandler();
96}
97#endif
98
99static struct ProcessDumpRequest g_request;
100static void *g_reservedChildStack = NULL;
101static pthread_mutex_t g_signalHandlerMutex = PTHREAD_MUTEX_INITIALIZER;
102static pthread_key_t g_crashObjKey;
103static bool g_crashObjInit = false;
104static BOOL g_hasInit = FALSE;
105static const int SIGNALHANDLER_TIMEOUT = 10000; // 10000 us
106static const int ALARM_TIME_S = 10;
107static int g_prevHandledSignal = SIGDUMP;
108static struct sigaction g_oldSigactionList[NSIG] = {};
109static char g_appRunningId[MAX_APP_RUNNING_UNIQUE_ID_LEN];
110enum DumpPreparationStage {
111    CREATE_PIPE_FAIL = 1,
112    SET_PIPE_LEN_FAIL,
113    WRITE_PIPE_FAIL,
114    INHERIT_CAP_FAIL,
115    EXEC_FAIL,
116};
117
118TraceInfo HiTraceGetId(void) __attribute__((weak));
119static 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
129const char* GetLastFatalMessage(void) __attribute__((weak));
130fatal_msg_t *get_fatal_message(void) __attribute__((weak));
131
132typedef struct ThreadCallbackItem {
133    int32_t tid;
134    ThreadInfoCallBack callback;
135} ThreadCallbackItem;
136
137#define CALLBACK_ITEM_COUNT 32
138static ThreadCallbackItem g_callbackItems[CALLBACK_ITEM_COUNT];
139static 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
147static GetStackIdFunc g_GetStackIdFunc = NULL;
148void SetAsyncStackCallbackFunc(void* func)
149{
150    g_GetStackIdFunc = (GetStackIdFunc)func;
151}
152
153// caller should set to NULL before exit thread
154void 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
179static 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
192static 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
222static 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
238static 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
259static 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
271static 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
283static bool IsDumpSignal(int sig)
284{
285    return sig == SIGDUMP || sig == SIGLEAK_STACK;
286}
287
288static 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
336static const int SIGCHAIN_DUMP_SIGNAL_LIST[] = {
337    SIGDUMP, SIGLEAK_STACK
338};
339
340static const int SIGCHAIN_CRASH_SIGNAL_LIST[] = {
341    SIGILL, SIGABRT, SIGBUS, SIGFPE,
342    SIGSEGV, SIGSTKFLT, SIGSYS, SIGTRAP
343};
344
345static 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
359static 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
379static 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
388static 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
402int DfxDumpRequest(int sig, struct ProcessDumpRequest *request, void *reservedChildStack) __attribute__((weak));
403#endif
404static 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
417static 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
455static void DFX_SignalHandler(int sig, siginfo_t *si, void *context)
456{
457    DFX_SigchainHandler(sig, si, context);
458    ResetAndRethrowSignalIfNeed(sig, si);
459}
460
461static 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
474void 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
521int 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
533uintptr_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
550void 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