From 527331a471207d28d015e210c12fb8bb8b6732fd Mon Sep 17 00:00:00 2001 From: Martin Kurbanov Date: Fri, 31 May 2024 13:36:23 +0300 Subject: [PATCH] Wait for SIGSTOP during attach, reinjecting unrelated signals PTRACE_ATTACH sends SIGSTOP to this thread. However, on waitpid() we may receive some other pending signal sooner than this SIGSTOP. Therefore, we need to call waitpid() until we receive SIGSTOP. Signals other than SIGSTOP that are received need to be reinjected with PTRACE_CONT, or they will otherwise get lost. If we do not wait for the SIGSTOP signal in waitpid(), this signal will be delivered after PTRACE_DETACH, and the thread will enter the "T (stopped)" state. See ptrace(2) manpage, under the section "Attaching and detaching". Change-Id: Ifcc89cc34086988d496cd31f5dc63e9fceebcaf6 Reviewed-on: https://chromium-review.googlesource.com/c/breakpad/breakpad/+/5582149 Reviewed-by: Mike Frysinger --- .../minidump_writer/linux_ptrace_dumper.cc | 23 +++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/src/client/linux/minidump_writer/linux_ptrace_dumper.cc b/src/client/linux/minidump_writer/linux_ptrace_dumper.cc index e5850063c..fb5b7e762 100644 --- a/src/client/linux/minidump_writer/linux_ptrace_dumper.cc +++ b/src/client/linux/minidump_writer/linux_ptrace_dumper.cc @@ -59,6 +59,7 @@ #include "client/linux/minidump_writer/directory_reader.h" #include "client/linux/minidump_writer/line_reader.h" +#include "common/linux/eintr_wrapper.h" #include "common/linux/linux_libc_support.h" #include "third_party/lss/linux_syscall_support.h" @@ -84,11 +85,29 @@ static bool SuspendThread(pid_t pid) { errno != 0) { return false; } - while (sys_waitpid(pid, NULL, __WALL) < 0) { - if (errno != EINTR) { + while (true) { + int status; + int r = HANDLE_EINTR(sys_waitpid(pid, &status, __WALL)); + if (r < 0) { sys_ptrace(PTRACE_DETACH, pid, NULL, NULL); return false; } + + if (!WIFSTOPPED(status)) + return false; + + // Any signal will stop the thread, make sure it is SIGSTOP. Otherwise, this + // signal will be delivered after PTRACE_DETACH, and the thread will enter + // the "T (stopped)" state. + if (WSTOPSIG(status) == SIGSTOP) + break; + + // Signals other than SIGSTOP that are received need to be reinjected, + // or they will otherwise get lost. + r = sys_ptrace(PTRACE_CONT, pid, NULL, + reinterpret_cast(WSTOPSIG(status))); + if (r < 0) + return false; } #if defined(__i386) || defined(__x86_64) // On x86, the stack pointer is NULL or -1, when executing trusted code in