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