Loading debuggerd/Android.bp +9 −1 Original line number Diff line number Diff line Loading @@ -171,6 +171,7 @@ cc_library_static { srcs: [ "libdebuggerd/backtrace.cpp", "libdebuggerd/gwp_asan.cpp", "libdebuggerd/open_files_list.cpp", "libdebuggerd/tombstone.cpp", "libdebuggerd/utility.cpp", Loading @@ -181,7 +182,10 @@ cc_library_static { // Needed for private/bionic_fdsan.h include_dirs: ["bionic/libc"], header_libs: ["bionic_libc_platform_headers"], header_libs: [ "bionic_libc_platform_headers", "gwp_asan_headers", ], static_libs: [ "libdexfile_support_static", // libunwindstack dependency Loading @@ -192,6 +196,8 @@ cc_library_static { "liblog", ], whole_static_libs: ["gwp_asan_crash_handler"], target: { recovery: { exclude_static_libs: [ Loading Loading @@ -246,10 +252,12 @@ cc_test { static_libs: [ "libdebuggerd", "libgmock", ], header_libs: [ "bionic_libc_platform_headers", "gwp_asan_headers", ], local_include_dirs: [ Loading debuggerd/client/debuggerd_client_test.cpp +2 −2 Original line number Diff line number Diff line Loading @@ -73,8 +73,8 @@ TEST(debuggerd_client, race) { unique_fd pipe_read, pipe_write; ASSERT_TRUE(Pipe(&pipe_read, &pipe_write)); // 64 MiB should be enough for everyone. constexpr int PIPE_SIZE = 64 * 1024 * 1024; // 16 MiB should be enough for everyone. constexpr int PIPE_SIZE = 16 * 1024 * 1024; ASSERT_EQ(PIPE_SIZE, fcntl(pipe_read.get(), F_SETPIPE_SZ, PIPE_SIZE)); // Wait for a bit to let the child spawn all of its threads. Loading debuggerd/crash_dump.cpp +17 −3 Original line number Diff line number Diff line Loading @@ -255,7 +255,8 @@ static void ParseArgs(int argc, char** argv, pid_t* pseudothread_tid, DebuggerdD static void ReadCrashInfo(unique_fd& fd, siginfo_t* siginfo, std::unique_ptr<unwindstack::Regs>* regs, uintptr_t* abort_msg_address, uintptr_t* fdsan_table_address) { uintptr_t* fdsan_table_address, uintptr_t* gwp_asan_state, uintptr_t* gwp_asan_metadata) { std::aligned_storage<sizeof(CrashInfo) + 1, alignof(CrashInfo)>::type buf; CrashInfo* crash_info = reinterpret_cast<CrashInfo*>(&buf); ssize_t rc = TEMP_FAILURE_RETRY(read(fd.get(), &buf, sizeof(buf))); Loading @@ -272,6 +273,10 @@ static void ReadCrashInfo(unique_fd& fd, siginfo_t* siginfo, expected_size = sizeof(CrashInfoHeader) + sizeof(CrashInfoDataV2); break; case 3: expected_size = sizeof(CrashInfoHeader) + sizeof(CrashInfoDataV3); break; default: LOG(FATAL) << "unexpected CrashInfo version: " << crash_info->header.version; break; Loading @@ -284,7 +289,13 @@ static void ReadCrashInfo(unique_fd& fd, siginfo_t* siginfo, } *fdsan_table_address = 0; *gwp_asan_state = 0; *gwp_asan_metadata = 0; switch (crash_info->header.version) { case 3: *gwp_asan_state = crash_info->data.v3.gwp_asan_state; *gwp_asan_metadata = crash_info->data.v3.gwp_asan_metadata; FALLTHROUGH_INTENDED; case 2: *fdsan_table_address = crash_info->data.v2.fdsan_table_address; FALLTHROUGH_INTENDED; Loading Loading @@ -416,6 +427,8 @@ int main(int argc, char** argv) { DebuggerdDumpType dump_type; uintptr_t abort_msg_address = 0; uintptr_t fdsan_table_address = 0; uintptr_t gwp_asan_state = 0; uintptr_t gwp_asan_metadata = 0; Initialize(argv); ParseArgs(argc, argv, &pseudothread_tid, &dump_type); Loading Loading @@ -477,7 +490,7 @@ int main(int argc, char** argv) { if (thread == g_target_thread) { // Read the thread's registers along with the rest of the crash info out of the pipe. ReadCrashInfo(input_pipe, &siginfo, &info.registers, &abort_msg_address, &fdsan_table_address); &fdsan_table_address, &gwp_asan_state, &gwp_asan_metadata); info.siginfo = &siginfo; info.signo = info.siginfo->si_signo; } else { Loading Loading @@ -592,7 +605,8 @@ int main(int argc, char** argv) { { ATRACE_NAME("engrave_tombstone"); engrave_tombstone(std::move(g_output_fd), &unwinder, thread_info, g_target_thread, abort_msg_address, &open_files, &amfd_data); abort_msg_address, &open_files, &amfd_data, gwp_asan_state, gwp_asan_metadata); } } Loading debuggerd/handler/debuggerd_handler.cpp +19 −4 Original line number Diff line number Diff line Loading @@ -49,6 +49,7 @@ #include <sys/wait.h> #include <unistd.h> #include <android-base/macros.h> #include <android-base/unique_fd.h> #include <async_safe/log.h> #include <bionic/reserved_signals.h> Loading Loading @@ -298,6 +299,8 @@ struct debugger_thread_info { void* ucontext; uintptr_t abort_msg; uintptr_t fdsan_table; uintptr_t gwp_asan_state; uintptr_t gwp_asan_metadata; }; // Logging and contacting debuggerd requires free file descriptors, which we might not have. Loading Loading @@ -342,23 +345,25 @@ static int debuggerd_dispatch_pseudothread(void* arg) { } // ucontext_t is absurdly large on AArch64, so piece it together manually with writev. uint32_t version = 2; constexpr size_t expected = sizeof(CrashInfoHeader) + sizeof(CrashInfoDataV2); uint32_t version = 3; constexpr size_t expected = sizeof(CrashInfoHeader) + sizeof(CrashInfoDataV3); 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[5] = { 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, 5)); ssize_t rc = TEMP_FAILURE_RETRY(writev(output_write.get(), iovs, arraysize(iovs))); if (rc == -1) { fatal_errno("failed to write crash info"); } else if (rc != expected) { Loading Loading @@ -485,6 +490,8 @@ static void debuggerd_signal_handler(int signal_number, siginfo_t* info, void* c } void* abort_message = nullptr; const gwp_asan::AllocatorState* gwp_asan_state = nullptr; const gwp_asan::AllocationMetadata* gwp_asan_metadata = nullptr; 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()) { Loading @@ -499,6 +506,12 @@ static void debuggerd_signal_handler(int signal_number, siginfo_t* info, void* c 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(); } } // If sival_int is ~0, it means that the fallback handler has been called Loading Loading @@ -532,6 +545,8 @@ static void debuggerd_signal_handler(int signal_number, siginfo_t* info, void* c .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), }; // Set PR_SET_DUMPABLE to 1, so that crash_dump can ptrace us. Loading debuggerd/include/debuggerd/handler.h +9 −0 Original line number Diff line number Diff line Loading @@ -24,11 +24,20 @@ __BEGIN_DECLS // Forward declare these classes so not everyone has to include GWP-ASan // headers. namespace gwp_asan { struct AllocatorState; struct AllocationMetadata; }; // namespace gwp_asan // These callbacks are called in a signal handler, and thus must be async signal safe. // If null, the callbacks will not be called. typedef struct { struct abort_msg_t* (*get_abort_message)(); void (*post_dump)(); const struct gwp_asan::AllocatorState* (*get_gwp_asan_state)(); const struct gwp_asan::AllocationMetadata* (*get_gwp_asan_metadata)(); } debuggerd_callbacks_t; void debuggerd_init(debuggerd_callbacks_t* callbacks); Loading Loading
debuggerd/Android.bp +9 −1 Original line number Diff line number Diff line Loading @@ -171,6 +171,7 @@ cc_library_static { srcs: [ "libdebuggerd/backtrace.cpp", "libdebuggerd/gwp_asan.cpp", "libdebuggerd/open_files_list.cpp", "libdebuggerd/tombstone.cpp", "libdebuggerd/utility.cpp", Loading @@ -181,7 +182,10 @@ cc_library_static { // Needed for private/bionic_fdsan.h include_dirs: ["bionic/libc"], header_libs: ["bionic_libc_platform_headers"], header_libs: [ "bionic_libc_platform_headers", "gwp_asan_headers", ], static_libs: [ "libdexfile_support_static", // libunwindstack dependency Loading @@ -192,6 +196,8 @@ cc_library_static { "liblog", ], whole_static_libs: ["gwp_asan_crash_handler"], target: { recovery: { exclude_static_libs: [ Loading Loading @@ -246,10 +252,12 @@ cc_test { static_libs: [ "libdebuggerd", "libgmock", ], header_libs: [ "bionic_libc_platform_headers", "gwp_asan_headers", ], local_include_dirs: [ Loading
debuggerd/client/debuggerd_client_test.cpp +2 −2 Original line number Diff line number Diff line Loading @@ -73,8 +73,8 @@ TEST(debuggerd_client, race) { unique_fd pipe_read, pipe_write; ASSERT_TRUE(Pipe(&pipe_read, &pipe_write)); // 64 MiB should be enough for everyone. constexpr int PIPE_SIZE = 64 * 1024 * 1024; // 16 MiB should be enough for everyone. constexpr int PIPE_SIZE = 16 * 1024 * 1024; ASSERT_EQ(PIPE_SIZE, fcntl(pipe_read.get(), F_SETPIPE_SZ, PIPE_SIZE)); // Wait for a bit to let the child spawn all of its threads. Loading
debuggerd/crash_dump.cpp +17 −3 Original line number Diff line number Diff line Loading @@ -255,7 +255,8 @@ static void ParseArgs(int argc, char** argv, pid_t* pseudothread_tid, DebuggerdD static void ReadCrashInfo(unique_fd& fd, siginfo_t* siginfo, std::unique_ptr<unwindstack::Regs>* regs, uintptr_t* abort_msg_address, uintptr_t* fdsan_table_address) { uintptr_t* fdsan_table_address, uintptr_t* gwp_asan_state, uintptr_t* gwp_asan_metadata) { std::aligned_storage<sizeof(CrashInfo) + 1, alignof(CrashInfo)>::type buf; CrashInfo* crash_info = reinterpret_cast<CrashInfo*>(&buf); ssize_t rc = TEMP_FAILURE_RETRY(read(fd.get(), &buf, sizeof(buf))); Loading @@ -272,6 +273,10 @@ static void ReadCrashInfo(unique_fd& fd, siginfo_t* siginfo, expected_size = sizeof(CrashInfoHeader) + sizeof(CrashInfoDataV2); break; case 3: expected_size = sizeof(CrashInfoHeader) + sizeof(CrashInfoDataV3); break; default: LOG(FATAL) << "unexpected CrashInfo version: " << crash_info->header.version; break; Loading @@ -284,7 +289,13 @@ static void ReadCrashInfo(unique_fd& fd, siginfo_t* siginfo, } *fdsan_table_address = 0; *gwp_asan_state = 0; *gwp_asan_metadata = 0; switch (crash_info->header.version) { case 3: *gwp_asan_state = crash_info->data.v3.gwp_asan_state; *gwp_asan_metadata = crash_info->data.v3.gwp_asan_metadata; FALLTHROUGH_INTENDED; case 2: *fdsan_table_address = crash_info->data.v2.fdsan_table_address; FALLTHROUGH_INTENDED; Loading Loading @@ -416,6 +427,8 @@ int main(int argc, char** argv) { DebuggerdDumpType dump_type; uintptr_t abort_msg_address = 0; uintptr_t fdsan_table_address = 0; uintptr_t gwp_asan_state = 0; uintptr_t gwp_asan_metadata = 0; Initialize(argv); ParseArgs(argc, argv, &pseudothread_tid, &dump_type); Loading Loading @@ -477,7 +490,7 @@ int main(int argc, char** argv) { if (thread == g_target_thread) { // Read the thread's registers along with the rest of the crash info out of the pipe. ReadCrashInfo(input_pipe, &siginfo, &info.registers, &abort_msg_address, &fdsan_table_address); &fdsan_table_address, &gwp_asan_state, &gwp_asan_metadata); info.siginfo = &siginfo; info.signo = info.siginfo->si_signo; } else { Loading Loading @@ -592,7 +605,8 @@ int main(int argc, char** argv) { { ATRACE_NAME("engrave_tombstone"); engrave_tombstone(std::move(g_output_fd), &unwinder, thread_info, g_target_thread, abort_msg_address, &open_files, &amfd_data); abort_msg_address, &open_files, &amfd_data, gwp_asan_state, gwp_asan_metadata); } } Loading
debuggerd/handler/debuggerd_handler.cpp +19 −4 Original line number Diff line number Diff line Loading @@ -49,6 +49,7 @@ #include <sys/wait.h> #include <unistd.h> #include <android-base/macros.h> #include <android-base/unique_fd.h> #include <async_safe/log.h> #include <bionic/reserved_signals.h> Loading Loading @@ -298,6 +299,8 @@ struct debugger_thread_info { void* ucontext; uintptr_t abort_msg; uintptr_t fdsan_table; uintptr_t gwp_asan_state; uintptr_t gwp_asan_metadata; }; // Logging and contacting debuggerd requires free file descriptors, which we might not have. Loading Loading @@ -342,23 +345,25 @@ static int debuggerd_dispatch_pseudothread(void* arg) { } // ucontext_t is absurdly large on AArch64, so piece it together manually with writev. uint32_t version = 2; constexpr size_t expected = sizeof(CrashInfoHeader) + sizeof(CrashInfoDataV2); uint32_t version = 3; constexpr size_t expected = sizeof(CrashInfoHeader) + sizeof(CrashInfoDataV3); 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[5] = { 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, 5)); ssize_t rc = TEMP_FAILURE_RETRY(writev(output_write.get(), iovs, arraysize(iovs))); if (rc == -1) { fatal_errno("failed to write crash info"); } else if (rc != expected) { Loading Loading @@ -485,6 +490,8 @@ static void debuggerd_signal_handler(int signal_number, siginfo_t* info, void* c } void* abort_message = nullptr; const gwp_asan::AllocatorState* gwp_asan_state = nullptr; const gwp_asan::AllocationMetadata* gwp_asan_metadata = nullptr; 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()) { Loading @@ -499,6 +506,12 @@ static void debuggerd_signal_handler(int signal_number, siginfo_t* info, void* c 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(); } } // If sival_int is ~0, it means that the fallback handler has been called Loading Loading @@ -532,6 +545,8 @@ static void debuggerd_signal_handler(int signal_number, siginfo_t* info, void* c .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), }; // Set PR_SET_DUMPABLE to 1, so that crash_dump can ptrace us. Loading
debuggerd/include/debuggerd/handler.h +9 −0 Original line number Diff line number Diff line Loading @@ -24,11 +24,20 @@ __BEGIN_DECLS // Forward declare these classes so not everyone has to include GWP-ASan // headers. namespace gwp_asan { struct AllocatorState; struct AllocationMetadata; }; // namespace gwp_asan // These callbacks are called in a signal handler, and thus must be async signal safe. // If null, the callbacks will not be called. typedef struct { struct abort_msg_t* (*get_abort_message)(); void (*post_dump)(); const struct gwp_asan::AllocatorState* (*get_gwp_asan_state)(); const struct gwp_asan::AllocationMetadata* (*get_gwp_asan_metadata)(); } debuggerd_callbacks_t; void debuggerd_init(debuggerd_callbacks_t* callbacks); Loading