If any of std{in,out,err} are not hooked up to a tty only interpose

ourselves with a pipe if the plugin will actually log the data.
This avoids a problem with non-interactive commands where no tty
is present where sudo will consume stdin even when log_input is not
enabled in sudoers.
This commit is contained in:
Todd C. Miller
2017-05-05 14:27:42 -06:00
parent 62730d13da
commit 44dc15d02d
2 changed files with 84 additions and 36 deletions

View File

@@ -390,10 +390,26 @@ exec_cmnd_pty(struct command_details *details, bool foreground, int errfd)
setpgid(0, self); setpgid(0, self);
/* Wire up standard fds, note that stdout/stderr may be pipes. */ /* Wire up standard fds, note that stdout/stderr may be pipes. */
if (dup2(io_fds[SFD_STDIN], STDIN_FILENO) == -1 || if (io_fds[SFD_STDIN] != STDIN_FILENO) {
dup2(io_fds[SFD_STDOUT], STDOUT_FILENO) == -1 || if (dup2(io_fds[SFD_STDIN], STDIN_FILENO) == -1)
dup2(io_fds[SFD_STDERR], STDERR_FILENO) == -1)
sudo_fatal("dup2"); sudo_fatal("dup2");
if (io_fds[SFD_STDIN] != io_fds[SFD_SLAVE])
close(io_fds[SFD_STDIN]);
}
if (io_fds[SFD_STDOUT] != STDOUT_FILENO) {
if (dup2(io_fds[SFD_STDOUT], STDOUT_FILENO) == -1)
sudo_fatal("dup2");
if (io_fds[SFD_STDOUT] != io_fds[SFD_SLAVE])
close(io_fds[SFD_STDOUT]);
}
if (io_fds[SFD_STDERR] != STDERR_FILENO) {
if (dup2(io_fds[SFD_STDERR], STDERR_FILENO) == -1)
sudo_fatal("dup2");
if (io_fds[SFD_STDERR] != io_fds[SFD_SLAVE])
close(io_fds[SFD_STDERR]);
}
if (io_fds[SFD_SLAVE] != -1)
close(io_fds[SFD_SLAVE]);
/* Wait for parent to grant us the tty if we are foreground. */ /* Wait for parent to grant us the tty if we are foreground. */
if (foreground && !ISSET(details->flags, CD_EXEC_BG)) { if (foreground && !ISSET(details->flags, CD_EXEC_BG)) {
@@ -402,16 +418,6 @@ exec_cmnd_pty(struct command_details *details, bool foreground, int errfd)
nanosleep(&ts, NULL); nanosleep(&ts, NULL);
} }
/* We have guaranteed that the slave fd is > 2 */
if (io_fds[SFD_SLAVE] != -1)
close(io_fds[SFD_SLAVE]);
if (io_fds[SFD_STDIN] != io_fds[SFD_SLAVE])
close(io_fds[SFD_STDIN]);
if (io_fds[SFD_STDOUT] != io_fds[SFD_SLAVE])
close(io_fds[SFD_STDOUT]);
if (io_fds[SFD_STDERR] != io_fds[SFD_SLAVE])
close(io_fds[SFD_STDERR]);
/* Execute command; only returns on error. */ /* Execute command; only returns on error. */
exec_cmnd(details, errfd); exec_cmnd(details, errfd);

View File

@@ -642,8 +642,10 @@ io_buf_new(int rfd, int wfd,
static int static int
fork_pty(struct command_details *details, int sv[], sigset_t *omask) fork_pty(struct command_details *details, int sv[], sigset_t *omask)
{ {
struct plugin_container *plugin;
struct command_status cstat; struct command_status cstat;
int io_pipe[3][2] = { { -1, -1 }, { -1, -1 }, { -1, -1 } }; int io_pipe[3][2] = { { -1, -1 }, { -1, -1 }, { -1, -1 } };
bool interpose[3] = { false, false, false };
sigaction_t sa; sigaction_t sa;
sigset_t mask; sigset_t mask;
pid_t child; pid_t child;
@@ -669,6 +671,16 @@ fork_pty(struct command_details *details, int sv[], sigset_t *omask)
sigaddset(&ttyblock, SIGTTIN); sigaddset(&ttyblock, SIGTTIN);
sigaddset(&ttyblock, SIGTTOU); sigaddset(&ttyblock, SIGTTOU);
/* Determine whether any of std{in,out,err} should be logged. */
TAILQ_FOREACH(plugin, &io_plugins, entries) {
if (plugin->u.io->log_stdin)
interpose[STDIN_FILENO] = true;
if (plugin->u.io->log_stdout)
interpose[STDOUT_FILENO] = true;
if (plugin->u.io->log_stderr)
interpose[STDERR_FILENO] = true;
}
/* /*
* Setup stdin/stdout/stderr for child, to be duped after forking. * Setup stdin/stdout/stderr for child, to be duped after forking.
* In background mode there is no stdin. * In background mode there is no stdin.
@@ -694,11 +706,20 @@ fork_pty(struct command_details *details, int sv[], sigset_t *omask)
} }
/* /*
* If either stdin, stdout or stderr is not a tty we use a pipe * If stdin, stdout or stderr is not a tty and logging is enabled,
* to interpose ourselves instead of duping the pty fd. * use a pipe to interpose ourselves instead of using the pty fd.
*/ */
if (io_fds[SFD_STDIN] == -1 || !isatty(STDIN_FILENO)) { if (io_fds[SFD_STDIN] == -1 || !isatty(STDIN_FILENO)) {
sudo_debug_printf(SUDO_DEBUG_INFO, "stdin not a tty, creating a pipe"); if (!interpose[STDIN_FILENO]) {
/* Not logging stdin, do not interpose. */
sudo_debug_printf(SUDO_DEBUG_INFO,
"stdin not a tty, not logging");
io_fds[SFD_STDIN] = dup(STDIN_FILENO);
if (io_fds[SFD_STDIN] == -1)
sudo_fatal("dup");
} else {
sudo_debug_printf(SUDO_DEBUG_INFO,
"stdin not a tty, creating a pipe");
pipeline = true; pipeline = true;
if (pipe(io_pipe[STDIN_FILENO]) != 0) if (pipe(io_pipe[STDIN_FILENO]) != 0)
sudo_fatal(U_("unable to create pipe")); sudo_fatal(U_("unable to create pipe"));
@@ -706,8 +727,18 @@ fork_pty(struct command_details *details, int sv[], sigset_t *omask)
log_stdin, &iobufs); log_stdin, &iobufs);
io_fds[SFD_STDIN] = io_pipe[STDIN_FILENO][0]; io_fds[SFD_STDIN] = io_pipe[STDIN_FILENO][0];
} }
}
if (io_fds[SFD_STDOUT] == -1 || !isatty(STDOUT_FILENO)) { if (io_fds[SFD_STDOUT] == -1 || !isatty(STDOUT_FILENO)) {
sudo_debug_printf(SUDO_DEBUG_INFO, "stdout not a tty, creating a pipe"); if (!interpose[STDOUT_FILENO]) {
/* Not logging stdout, do not interpose. */
sudo_debug_printf(SUDO_DEBUG_INFO,
"stdout not a tty, not logging");
io_fds[SFD_STDOUT] = dup(STDOUT_FILENO);
if (io_fds[SFD_STDOUT] == -1)
sudo_fatal("dup");
} else {
sudo_debug_printf(SUDO_DEBUG_INFO,
"stdout not a tty, creating a pipe");
pipeline = true; pipeline = true;
if (pipe(io_pipe[STDOUT_FILENO]) != 0) if (pipe(io_pipe[STDOUT_FILENO]) != 0)
sudo_fatal(U_("unable to create pipe")); sudo_fatal(U_("unable to create pipe"));
@@ -715,14 +746,25 @@ fork_pty(struct command_details *details, int sv[], sigset_t *omask)
log_stdout, &iobufs); log_stdout, &iobufs);
io_fds[SFD_STDOUT] = io_pipe[STDOUT_FILENO][1]; io_fds[SFD_STDOUT] = io_pipe[STDOUT_FILENO][1];
} }
}
if (io_fds[SFD_STDERR] == -1 || !isatty(STDERR_FILENO)) { if (io_fds[SFD_STDERR] == -1 || !isatty(STDERR_FILENO)) {
sudo_debug_printf(SUDO_DEBUG_INFO, "stderr not a tty, creating a pipe"); if (!interpose[STDERR_FILENO]) {
/* Not logging stderr, do not interpose. */
sudo_debug_printf(SUDO_DEBUG_INFO,
"stderr not a tty, not logging");
io_fds[SFD_STDERR] = dup(STDERR_FILENO);
if (io_fds[SFD_STDERR] == -1)
sudo_fatal("dup");
} else {
sudo_debug_printf(SUDO_DEBUG_INFO,
"stderr not a tty, creating a pipe");
if (pipe(io_pipe[STDERR_FILENO]) != 0) if (pipe(io_pipe[STDERR_FILENO]) != 0)
sudo_fatal(U_("unable to create pipe")); sudo_fatal(U_("unable to create pipe"));
io_buf_new(io_pipe[STDERR_FILENO][0], STDERR_FILENO, io_buf_new(io_pipe[STDERR_FILENO][0], STDERR_FILENO,
log_stderr, &iobufs); log_stderr, &iobufs);
io_fds[SFD_STDERR] = io_pipe[STDERR_FILENO][1]; io_fds[SFD_STDERR] = io_pipe[STDERR_FILENO][1];
} }
}
if (foreground) { if (foreground) {
/* Copy terminal attrs from user tty -> pty slave. */ /* Copy terminal attrs from user tty -> pty slave. */