diff options
author | Daniel Norman <danielnorman@google.com> | 2020-08-31 12:05:50 -0700 |
---|---|---|
committer | Brian Orr <brianorr@google.com> | 2020-09-03 11:08:10 -0700 |
commit | 9a1114d8a44e4d93a719095ad81c119273d43ee4 (patch) | |
tree | e50f8133f3f65cafa0d1d2235044e2d65e75bc0a /debuggerd/handler/debuggerd_handler.cpp | |
parent | 600e96934a288c86ff438e6d8cea6f55acddd615 (diff) | |
parent | 0ba167e991c75828b215580220230fdec95f85c2 (diff) |
Merge SP1A.200727.001
Change-Id: I8f6750352c361cdc5b23825395234de12384ddd7
Diffstat (limited to 'debuggerd/handler/debuggerd_handler.cpp')
-rw-r--r-- | debuggerd/handler/debuggerd_handler.cpp | 127 |
1 files changed, 66 insertions, 61 deletions
diff --git a/debuggerd/handler/debuggerd_handler.cpp b/debuggerd/handler/debuggerd_handler.cpp index b7ee6e135..1a7102d2a 100644 --- a/debuggerd/handler/debuggerd_handler.cpp +++ b/debuggerd/handler/debuggerd_handler.cpp @@ -83,7 +83,7 @@ using unique_fd = android::base::unique_fd_impl<FdsanBypassCloser>; #define CRASH_DUMP_NAME "crash_dump32" #endif -#define CRASH_DUMP_PATH "/system/bin/" CRASH_DUMP_NAME +#define CRASH_DUMP_PATH "/apex/com.android.runtime/bin/" CRASH_DUMP_NAME // Wrappers that directly invoke the respective syscalls, in case the cached values are invalid. #pragma GCC poison getpid gettid @@ -167,7 +167,7 @@ static bool get_main_thread_name(char* buf, size_t len) { * mutex is being held, so we don't want to use any libc functions that * could allocate memory or hold a lock. */ -static void log_signal_summary(const siginfo_t* info) { +static void log_signal_summary(const siginfo_t* info, const ucontext_t* ucontext) { char thread_name[MAX_TASK_NAME_LEN + 1]; // one more for termination if (prctl(PR_GET_NAME, reinterpret_cast<unsigned long>(thread_name), 0, 0, 0) != 0) { strcpy(thread_name, "<name unknown>"); @@ -186,7 +186,8 @@ static void log_signal_summary(const siginfo_t* info) { // Many signals don't have an address or sender. char addr_desc[32] = ""; // ", fault addr 0x1234" if (signal_has_si_addr(info)) { - async_safe_format_buffer(addr_desc, sizeof(addr_desc), ", fault addr %p", info->si_addr); + async_safe_format_buffer(addr_desc, sizeof(addr_desc), ", fault addr %p", + reinterpret_cast<void*>(get_fault_address(info, ucontext))); } pid_t self_pid = __getpid(); char sender_desc[32] = {}; // " from pid 1234, uid 666" @@ -297,10 +298,7 @@ struct debugger_thread_info { pid_t pseudothread_tid; siginfo_t* siginfo; void* ucontext; - uintptr_t abort_msg; - uintptr_t fdsan_table; - uintptr_t gwp_asan_state; - uintptr_t gwp_asan_metadata; + debugger_process_info process_info; }; // Logging and contacting debuggerd requires free file descriptors, which we might not have. @@ -344,25 +342,36 @@ static int debuggerd_dispatch_pseudothread(void* arg) { fatal_errno("failed to create pipe"); } + uint32_t version; + ssize_t expected; + // ucontext_t is absurdly large on AArch64, so piece it together manually with writev. - uint32_t version = 3; - constexpr size_t expected = sizeof(CrashInfoHeader) + sizeof(CrashInfoDataV3); + struct iovec iovs[4] = { + {.iov_base = &version, .iov_len = sizeof(version)}, + {.iov_base = thread_info->siginfo, .iov_len = sizeof(siginfo_t)}, + {.iov_base = thread_info->ucontext, .iov_len = sizeof(ucontext_t)}, + }; + + if (thread_info->process_info.fdsan_table) { + // Dynamic executables always use version 4. There is no need to increment the version number if + // the format changes, because the sender (linker) and receiver (crash_dump) are version locked. + version = 4; + expected = sizeof(CrashInfoHeader) + sizeof(CrashInfoDataDynamic); + + iovs[3] = {.iov_base = &thread_info->process_info, + .iov_len = sizeof(thread_info->process_info)}; + } else { + // Static executables always use version 1. + version = 1; + expected = sizeof(CrashInfoHeader) + sizeof(CrashInfoDataStatic); + iovs[3] = {.iov_base = &thread_info->process_info.abort_msg, .iov_len = sizeof(uintptr_t)}; + } errno = 0; if (fcntl(output_write.get(), F_SETPIPE_SZ, expected) < static_cast<int>(expected)) { fatal_errno("failed to set pipe buffer size"); } - struct iovec iovs[] = { - {.iov_base = &version, .iov_len = sizeof(version)}, - {.iov_base = thread_info->siginfo, .iov_len = sizeof(siginfo_t)}, - {.iov_base = thread_info->ucontext, .iov_len = sizeof(ucontext_t)}, - {.iov_base = &thread_info->abort_msg, .iov_len = sizeof(uintptr_t)}, - {.iov_base = &thread_info->fdsan_table, .iov_len = sizeof(uintptr_t)}, - {.iov_base = &thread_info->gwp_asan_state, .iov_len = sizeof(uintptr_t)}, - {.iov_base = &thread_info->gwp_asan_metadata, .iov_len = sizeof(uintptr_t)}, - }; - ssize_t rc = TEMP_FAILURE_RETRY(writev(output_write.get(), iovs, arraysize(iovs))); if (rc == -1) { fatal_errno("failed to write crash info"); @@ -408,23 +417,28 @@ static int debuggerd_dispatch_pseudothread(void* arg) { // us to fork off a process to read memory from. char buf[4]; rc = TEMP_FAILURE_RETRY(read(input_read.get(), &buf, sizeof(buf))); - if (rc == -1) { - async_safe_format_log(ANDROID_LOG_FATAL, "libc", "read of IPC pipe failed: %s", strerror(errno)); - return 1; - } else if (rc == 0) { - async_safe_format_log(ANDROID_LOG_FATAL, "libc", "crash_dump helper failed to exec"); - return 1; - } else if (rc != 1) { - async_safe_format_log(ANDROID_LOG_FATAL, "libc", - "read of IPC pipe returned unexpected value: %zd", rc); - return 1; - } else if (buf[0] != '\1') { - async_safe_format_log(ANDROID_LOG_FATAL, "libc", "crash_dump helper reported failure"); - return 1; - } - // crash_dump is ptracing us, fork off a copy of our address space for it to use. - create_vm_process(); + bool success = false; + if (rc == 1 && buf[0] == '\1') { + // crash_dump successfully started, and is ptracing us. + // Fork off a copy of our address space for it to use. + create_vm_process(); + success = true; + } else { + // Something went wrong, log it. + if (rc == -1) { + async_safe_format_log(ANDROID_LOG_FATAL, "libc", "read of IPC pipe failed: %s", + strerror(errno)); + } else if (rc == 0) { + async_safe_format_log(ANDROID_LOG_FATAL, "libc", + "crash_dump helper failed to exec, or was killed"); + } else if (rc != 1) { + async_safe_format_log(ANDROID_LOG_FATAL, "libc", + "read of IPC pipe returned unexpected value: %zd", rc); + } else if (buf[0] != '\1') { + async_safe_format_log(ANDROID_LOG_FATAL, "libc", "crash_dump helper reported failure"); + } + } // Don't leave a zombie child. int status; @@ -435,14 +449,16 @@ static int debuggerd_dispatch_pseudothread(void* arg) { async_safe_format_log(ANDROID_LOG_FATAL, "libc", "crash_dump helper crashed or stopped"); } - if (thread_info->siginfo->si_signo != BIONIC_SIGNAL_DEBUGGER) { - // For crashes, we don't need to minimize pause latency. - // Wait for the dump to complete before having the process exit, to avoid being murdered by - // ActivityManager or init. - TEMP_FAILURE_RETRY(read(input_read, &buf, sizeof(buf))); + if (success) { + if (thread_info->siginfo->si_signo != BIONIC_SIGNAL_DEBUGGER) { + // For crashes, we don't need to minimize pause latency. + // Wait for the dump to complete before having the process exit, to avoid being murdered by + // ActivityManager or init. + TEMP_FAILURE_RETRY(read(input_read, &buf, sizeof(buf))); + } } - return 0; + return success ? 0 : 1; } static void resend_signal(siginfo_t* info) { @@ -468,6 +484,8 @@ static void debuggerd_signal_handler(int signal_number, siginfo_t* info, void* c // making a syscall and checking errno. ErrnoRestorer restorer; + auto *ucontext = static_cast<ucontext_t*>(context); + // It's possible somebody cleared the SA_SIGINFO flag, which would mean // our "info" arg holds an undefined value. if (!have_siginfo(signal_number)) { @@ -489,29 +507,19 @@ static void debuggerd_signal_handler(int signal_number, siginfo_t* info, void* c // check to allow all si_code values in calls coming from inside the house. } - void* abort_message = nullptr; - const gwp_asan::AllocatorState* gwp_asan_state = nullptr; - const gwp_asan::AllocationMetadata* gwp_asan_metadata = nullptr; + debugger_process_info process_info = {}; uintptr_t si_val = reinterpret_cast<uintptr_t>(info->si_ptr); if (signal_number == BIONIC_SIGNAL_DEBUGGER) { if (info->si_code == SI_QUEUE && info->si_pid == __getpid()) { // Allow for the abort message to be explicitly specified via the sigqueue value. // Keep the bottom bit intact for representing whether we want a backtrace or a tombstone. if (si_val != kDebuggerdFallbackSivalUintptrRequestDump) { - abort_message = reinterpret_cast<void*>(si_val & ~1); + process_info.abort_msg = reinterpret_cast<void*>(si_val & ~1); info->si_ptr = reinterpret_cast<void*>(si_val & 1); } } - } else { - if (g_callbacks.get_abort_message) { - abort_message = g_callbacks.get_abort_message(); - } - if (g_callbacks.get_gwp_asan_state) { - gwp_asan_state = g_callbacks.get_gwp_asan_state(); - } - if (g_callbacks.get_gwp_asan_metadata) { - gwp_asan_metadata = g_callbacks.get_gwp_asan_metadata(); - } + } else if (g_callbacks.get_process_info) { + process_info = g_callbacks.get_process_info(); } // If sival_int is ~0, it means that the fallback handler has been called @@ -524,7 +532,7 @@ static void debuggerd_signal_handler(int signal_number, siginfo_t* info, void* c // This check might be racy if another thread sets NO_NEW_PRIVS, but this should be unlikely, // you can only set NO_NEW_PRIVS to 1, and the effect should be at worst a single missing // ANR trace. - debuggerd_fallback_handler(info, static_cast<ucontext_t*>(context), abort_message); + debuggerd_fallback_handler(info, ucontext, process_info.abort_msg); resend_signal(info); return; } @@ -536,17 +544,14 @@ static void debuggerd_signal_handler(int signal_number, siginfo_t* info, void* c return; } - log_signal_summary(info); + log_signal_summary(info, ucontext); debugger_thread_info thread_info = { .crashing_tid = __gettid(), .pseudothread_tid = -1, .siginfo = info, .ucontext = context, - .abort_msg = reinterpret_cast<uintptr_t>(abort_message), - .fdsan_table = reinterpret_cast<uintptr_t>(android_fdsan_get_fd_table()), - .gwp_asan_state = reinterpret_cast<uintptr_t>(gwp_asan_state), - .gwp_asan_metadata = reinterpret_cast<uintptr_t>(gwp_asan_metadata), + .process_info = process_info, }; // Set PR_SET_DUMPABLE to 1, so that crash_dump can ptrace us. |