Explicitly check for a continued process with waitpid(2). Otherwise,

waitpid() will return 0 when the command is resumed after being
suspended, which we were treating the same as -1.  Fixes suspend
and resume on Linux and probably others.
This commit is contained in:
Todd C. Miller
2016-07-27 16:17:41 -06:00
parent a014a2abd4
commit 4f47a2ad7d

View File

@@ -1148,13 +1148,14 @@ static bool
handle_sigchld(int backchannel, struct command_status *cstat) handle_sigchld(int backchannel, struct command_status *cstat)
{ {
char signame[SIG2STR_MAX]; char signame[SIG2STR_MAX];
bool alive = true;
int status; int status;
pid_t pid; pid_t pid;
debug_decl(handle_sigchld, SUDO_DEBUG_EXEC); debug_decl(handle_sigchld, SUDO_DEBUG_EXEC);
/* Read command status. */ /* Read command status. */
do { do {
pid = waitpid(cmnd_pid, &status, WUNTRACED|WNOHANG); pid = waitpid(cmnd_pid, &status, WUNTRACED|WCONTINUED|WNOHANG);
} while (pid == -1 && errno == EINTR); } while (pid == -1 && errno == EINTR);
if (pid <= 0) { if (pid <= 0) {
sudo_debug_printf(SUDO_DEBUG_DIAG, sudo_debug_printf(SUDO_DEBUG_DIAG,
@@ -1162,17 +1163,23 @@ handle_sigchld(int backchannel, struct command_status *cstat)
debug_return_bool(false); debug_return_bool(false);
} }
if (WIFSTOPPED(status)) { if (WIFCONTINUED(status)) {
sudo_debug_printf(SUDO_DEBUG_INFO, "command (%d) resumed", cmnd_pid);
} else if (WIFSTOPPED(status)) {
if (sig2str(WSTOPSIG(status), signame) == -1) if (sig2str(WSTOPSIG(status), signame) == -1)
snprintf(signame, sizeof(signame), "%d", WSTOPSIG(status)); snprintf(signame, sizeof(signame), "%d", WSTOPSIG(status));
sudo_debug_printf(SUDO_DEBUG_INFO, "command stopped, SIG%s", signame); sudo_debug_printf(SUDO_DEBUG_INFO, "command (%d) stopped, SIG%s",
cmnd_pid, signame);
} else if (WIFSIGNALED(status)) { } else if (WIFSIGNALED(status)) {
if (sig2str(WTERMSIG(status), signame) == -1) if (sig2str(WTERMSIG(status), signame) == -1)
snprintf(signame, sizeof(signame), "%d", WTERMSIG(status)); snprintf(signame, sizeof(signame), "%d", WTERMSIG(status));
sudo_debug_printf(SUDO_DEBUG_INFO, "command killed, SIG%s", signame); sudo_debug_printf(SUDO_DEBUG_INFO, "command (%d) killed, SIG%s",
cmnd_pid, signame);
alive = false;
} else { } else {
sudo_debug_printf(SUDO_DEBUG_INFO, "command exited: %d", sudo_debug_printf(SUDO_DEBUG_INFO, "command (%d) exited: %d",
WEXITSTATUS(status)); cmnd_pid, WEXITSTATUS(status));
alive = false;
} }
/* Don't overwrite execve() failure with child exit status. */ /* Don't overwrite execve() failure with child exit status. */
@@ -1188,13 +1195,11 @@ handle_sigchld(int backchannel, struct command_status *cstat)
pid = tcgetpgrp(io_fds[SFD_SLAVE]); pid = tcgetpgrp(io_fds[SFD_SLAVE]);
} while (pid == -1 && errno == EINTR); } while (pid == -1 && errno == EINTR);
if (pid != mon_pgrp) if (pid != mon_pgrp)
send_status(backchannel, cstat); send_status(backchannel, cstat);
debug_return_bool(true);
} }
} }
/* It's dead, Jim. */ debug_return_bool(alive);
debug_return_bool(false);
} }
struct monitor_closure { struct monitor_closure {