Skip to content

Commit

Permalink
Wait for SIGSTOP during attach, reinjecting unrelated signals
Browse files Browse the repository at this point in the history
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 <vapier@chromium.org>
  • Loading branch information
m-kurbanov authored and vapier committed May 31, 2024
1 parent 69f9a4e commit 527331a
Showing 1 changed file with 21 additions and 2 deletions.
23 changes: 21 additions & 2 deletions src/client/linux/minidump_writer/linux_ptrace_dumper.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand All @@ -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<void*>(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
Expand Down

0 comments on commit 527331a

Please sign in to comment.