diff --git a/src/exec_nopty.c b/src/exec_nopty.c index 63d6fe323..a9fc72408 100644 --- a/src/exec_nopty.c +++ b/src/exec_nopty.c @@ -568,8 +568,8 @@ handle_sigchld_nopty(struct exec_closure_nopty *ec) "%s: process %d stopped, SIG%s", __func__, (int)pid, signame); if (ISSET(ec->details->flags, CD_USE_PTRACE)) { - /* Did exec_ptrace_handled() suppress the signal? */ - if (exec_ptrace_handled(pid, status, ec->intercept)) + /* If not a group-stop signal, just continue. */ + if (!exec_ptrace_stopped(pid, status, ec->intercept)) continue; } diff --git a/src/exec_ptrace.c b/src/exec_ptrace.c index 169eedfda..6661e943f 100644 --- a/src/exec_ptrace.c +++ b/src/exec_ptrace.c @@ -1195,17 +1195,19 @@ done: /* * Handle a process stopped due to ptrace. - * Returns true if the signal was suppressed and false if it was delivered. + * Restarts the tracee with PTRACE_LISTEN (for a group-stop) + * or PTRACE_CONT (for signal-delivery-stop). + * Returns true if stopped by a group-stop, else false. */ bool -exec_ptrace_handled(pid_t pid, int status, void *intercept) +exec_ptrace_stopped(pid_t pid, int status, void *intercept) { struct intercept_closure *closure = intercept; const int stopsig = WSTOPSIG(status); const int sigtrap = status >> 8; long signo = 0; bool group_stop = false; - debug_decl(exec_ptrace_handled, SUDO_DEBUG_EXEC); + debug_decl(exec_ptrace_stopped, SUDO_DEBUG_EXEC); if (sigtrap == (SIGTRAP | (PTRACE_EVENT_SECCOMP << 8))) { if (!ptrace_intercept_execve(pid, closure)) { @@ -1255,24 +1257,22 @@ exec_ptrace_handled(pid_t pid, int status, void *intercept) } } - /* Continue child. */ - /* XXX - handle ptrace returning ESRCH if process dies */ if (group_stop) { /* * Restart child but prevent it from executing * until SIGCONT is received (simulate SIGSTOP, etc). */ - if (ptrace(PTRACE_LISTEN, pid, NULL, 0L) == -1) - sudo_warn("%s: ptrace(PTRACE_LISTEN, %d, NULL, %d)", - __func__, (int)pid, stopsig); + if (ptrace(PTRACE_LISTEN, pid, NULL, 0L) == -1 && errno != ESRCH) + sudo_warn("%s: ptrace(PTRACE_LISTEN, %d, NULL, 0L)", + __func__, (int)pid); } else { - /* Restart child. */ - if (ptrace(PTRACE_CONT, pid, NULL, signo) == -1) + /* Restart child immediately. */ + if (ptrace(PTRACE_CONT, pid, NULL, signo) == -1 && errno != ESRCH) sudo_warn("%s: ptrace(PTRACE_CONT, %d, NULL, %ld)", __func__, (int)pid, signo); } - debug_return_bool(signo == 0); + debug_return_bool(group_stop); } #else /* STUB */ @@ -1284,9 +1284,9 @@ have_seccomp_action(const char *action) /* STUB */ bool -exec_ptrace_handled(pid_t pid, int status, void *intercept) +exec_ptrace_stopped(pid_t pid, int status, void *intercept) { - return false; + return true; } /* STUB */ diff --git a/src/exec_pty.c b/src/exec_pty.c index 119afd774..4e9b71d3d 100644 --- a/src/exec_pty.c +++ b/src/exec_pty.c @@ -1100,7 +1100,7 @@ handle_sigchld_pty(struct exec_closure_pty *ec) } else if (WIFSTOPPED(status)) { if (pid != ec->monitor_pid) { if (ISSET(ec->details->flags, CD_USE_PTRACE)) - exec_ptrace_handled(pid, status, ec->intercept); + exec_ptrace_stopped(pid, status, ec->intercept); continue; } diff --git a/src/regress/intercept/test_ptrace.c b/src/regress/intercept/test_ptrace.c index 02550cdc1..704222a18 100644 --- a/src/regress/intercept/test_ptrace.c +++ b/src/regress/intercept/test_ptrace.c @@ -210,7 +210,13 @@ main(int argc, char *argv[]) if (pid == child) return WTERMSIG(status) | 128; } else if (WIFSTOPPED(status)) { - exec_ptrace_handled(pid, status, &closure); + if (exec_ptrace_stopped(pid, status, &closure)) { + if (pid == child) { + /* TODO - terminal pgrp switching like exec_nopty.c. */ + kill(getpid(), WSTOPSIG(status)); + kill(child, SIGCONT); + } + } } else { sudo_fatalx("%d: unknown status 0x%x", pid, status); } diff --git a/src/sudo_exec.h b/src/sudo_exec.h index a640da636..9c58cd2ab 100644 --- a/src/sudo_exec.h +++ b/src/sudo_exec.h @@ -147,7 +147,7 @@ bool utmp_logout(const char *line, int status); char **sudo_preload_dso(char *envp[], const char *dso_file, int intercept_fd); /* exec_ptrace.c */ -bool exec_ptrace_handled(pid_t pid, int status, void *intercept); +bool exec_ptrace_stopped(pid_t pid, int status, void *intercept); bool set_exec_filter(void); int exec_ptrace_seize(pid_t child);