From: Todd C. Miller Date: Fri, 5 May 2017 20:27:42 +0000 (-0600) Subject: If any of std{in,out,err} are not hooked up to a tty only interpose X-Git-Tag: SUDO_1_8_20^2~6 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=44dc15d02dc0b34bf03bc971ba08d3a761c3a031;p=sudo 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. --- diff --git a/src/exec_monitor.c b/src/exec_monitor.c index 15e6ff893..f8a21a5ca 100644 --- a/src/exec_monitor.c +++ b/src/exec_monitor.c @@ -390,10 +390,26 @@ exec_cmnd_pty(struct command_details *details, bool foreground, int errfd) setpgid(0, self); /* Wire up standard fds, note that stdout/stderr may be pipes. */ - if (dup2(io_fds[SFD_STDIN], STDIN_FILENO) == -1 || - dup2(io_fds[SFD_STDOUT], STDOUT_FILENO) == -1 || - dup2(io_fds[SFD_STDERR], STDERR_FILENO) == -1) - sudo_fatal("dup2"); + if (io_fds[SFD_STDIN] != STDIN_FILENO) { + if (dup2(io_fds[SFD_STDIN], STDIN_FILENO) == -1) + 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. */ 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); } - /* 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. */ exec_cmnd(details, errfd); diff --git a/src/exec_pty.c b/src/exec_pty.c index 4a05ee012..7e30b66e2 100644 --- a/src/exec_pty.c +++ b/src/exec_pty.c @@ -642,8 +642,10 @@ io_buf_new(int rfd, int wfd, static int fork_pty(struct command_details *details, int sv[], sigset_t *omask) { + struct plugin_container *plugin; struct command_status cstat; int io_pipe[3][2] = { { -1, -1 }, { -1, -1 }, { -1, -1 } }; + bool interpose[3] = { false, false, false }; sigaction_t sa; sigset_t mask; pid_t child; @@ -669,6 +671,16 @@ fork_pty(struct command_details *details, int sv[], sigset_t *omask) sigaddset(&ttyblock, SIGTTIN); 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. * In background mode there is no stdin. @@ -694,34 +706,64 @@ 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 - * to interpose ourselves instead of duping the pty fd. + * If stdin, stdout or stderr is not a tty and logging is enabled, + * use a pipe to interpose ourselves instead of using the pty fd. */ if (io_fds[SFD_STDIN] == -1 || !isatty(STDIN_FILENO)) { - sudo_debug_printf(SUDO_DEBUG_INFO, "stdin not a tty, creating a pipe"); - pipeline = true; - if (pipe(io_pipe[STDIN_FILENO]) != 0) - sudo_fatal(U_("unable to create pipe")); - io_buf_new(STDIN_FILENO, io_pipe[STDIN_FILENO][1], - log_stdin, &iobufs); - io_fds[SFD_STDIN] = io_pipe[STDIN_FILENO][0]; + 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; + if (pipe(io_pipe[STDIN_FILENO]) != 0) + sudo_fatal(U_("unable to create pipe")); + io_buf_new(STDIN_FILENO, io_pipe[STDIN_FILENO][1], + log_stdin, &iobufs); + io_fds[SFD_STDIN] = io_pipe[STDIN_FILENO][0]; + } } if (io_fds[SFD_STDOUT] == -1 || !isatty(STDOUT_FILENO)) { - sudo_debug_printf(SUDO_DEBUG_INFO, "stdout not a tty, creating a pipe"); - pipeline = true; - if (pipe(io_pipe[STDOUT_FILENO]) != 0) - sudo_fatal(U_("unable to create pipe")); - io_buf_new(io_pipe[STDOUT_FILENO][0], STDOUT_FILENO, - log_stdout, &iobufs); - io_fds[SFD_STDOUT] = io_pipe[STDOUT_FILENO][1]; + 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; + if (pipe(io_pipe[STDOUT_FILENO]) != 0) + sudo_fatal(U_("unable to create pipe")); + io_buf_new(io_pipe[STDOUT_FILENO][0], STDOUT_FILENO, + log_stdout, &iobufs); + io_fds[SFD_STDOUT] = io_pipe[STDOUT_FILENO][1]; + } } if (io_fds[SFD_STDERR] == -1 || !isatty(STDERR_FILENO)) { - sudo_debug_printf(SUDO_DEBUG_INFO, "stderr not a tty, creating a pipe"); - if (pipe(io_pipe[STDERR_FILENO]) != 0) - sudo_fatal(U_("unable to create pipe")); - io_buf_new(io_pipe[STDERR_FILENO][0], STDERR_FILENO, - log_stderr, &iobufs); - io_fds[SFD_STDERR] = io_pipe[STDERR_FILENO][1]; + 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) + sudo_fatal(U_("unable to create pipe")); + io_buf_new(io_pipe[STDERR_FILENO][0], STDERR_FILENO, + log_stderr, &iobufs); + io_fds[SFD_STDERR] = io_pipe[STDERR_FILENO][1]; + } } if (foreground) {