Skip to content

Commit

Permalink
Handle unexpected exits in desched processing (fixes #3000)
Browse files Browse the repository at this point in the history
There are two issues here:
1. We shouldn't attempt to do a `waitpid` if we know the process is
   dying, because our `waitpid` calling is pretty carefully choreographed
   after receiving PTRACE_EVENT_EXIT and an extra waitpid messes that up.
2. `advance_to_disarm_desched_syscall` wasn't robust to the possibility
   that the task could die and would infinite loop.

Fix both by adding appropriate checks. Fixes #3000.
  • Loading branch information
Keno authored and rocallahan committed Dec 22, 2021
1 parent 888ac93 commit 81c8521
Show file tree
Hide file tree
Showing 3 changed files with 6 additions and 3 deletions.
3 changes: 3 additions & 0 deletions src/RecordSession.cc
Original file line number Diff line number Diff line change
Expand Up @@ -874,6 +874,9 @@ static void advance_to_disarm_desched_syscall(RecordTask* t) {
/* TODO: mask off signals and avoid this loop. */
do {
t->resume_execution(RESUME_SYSCALL, RESUME_WAIT, RESUME_UNLIMITED_TICKS);
if (t->is_dying()) {
return;
}
/* We can safely ignore TIME_SLICE_SIGNAL while trying to
* reach the disarm-desched ioctl: once we reach it,
* the desched'd syscall will be "done" and the tracee
Expand Down
4 changes: 2 additions & 2 deletions src/Task.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1413,7 +1413,7 @@ void Task::resume_execution(ResumeRequest how, WaitRequest wait_how,
flush_regs();

pid_t wait_ret = 0;
if (session().is_recording()) {
if (session().is_recording() && !is_dying()) {
/* There's a nasty race where a stopped task gets woken up by a SIGKILL
* and advances to the PTRACE_EXIT_EVENT ptrace-stop just before we
* send a PTRACE_CONT. Our PTRACE_CONT will cause it to continue and exit,
Expand Down Expand Up @@ -1446,7 +1446,7 @@ void Task::resume_execution(ResumeRequest how, WaitRequest wait_how,
<< "waitpid(" << tid << ", NOHANG) failed with " << wait_ret;
}
}
if (wait_ret > 0 || handled_ptrace_exit_event) {
if (wait_ret > 0 || is_dying()) {
LOG(debug) << "Task " << tid << " exited unexpectedly";
// wait() will see this and report the ptrace-exit event.
detected_unexpected_exit = true;
Expand Down
2 changes: 1 addition & 1 deletion src/test/desched_sigkill.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ int main(void) {
pids[i] = fork();
if (pids[i] == 0) {
test_assert(1 == write(child_to_parent[1], "x", 1));
test_assert(1 == read(parent_to_child[0], &ch, 1) && ch == 'y');
test_assert(1 == read(parent_to_child[0], &ch, 1) && ch == 'x');
pause();
return 77;
}
Expand Down

0 comments on commit 81c8521

Please sign in to comment.