diff --git a/src/exec.c b/src/exec.c index 2020babf0..39d83774c 100644 --- a/src/exec.c +++ b/src/exec.c @@ -377,26 +377,23 @@ sudo_needs_pty(const struct command_details *details) } /* - * Check whether the specified fd matches the device file that - * corresponds to tty_sb. If tty_sb is NULL, just check whether - * fd is a tty. Always fills in fd_sb (zeroed on error). + * Check whether the specified fd is a terminal with the specified + * controlling process group. Always fills in sb (zeroed on error). * Returns true on match, else false. */ bool -fd_matches_tty(int fd, struct stat *tty_sb, struct stat *fd_sb) +fd_matches_pgrp(int fd, pid_t pgrp, struct stat *sb) { - debug_decl(fd_is_user_tty, SUDO_DEBUG_EXEC); + debug_decl(fd_matches_pgrp, SUDO_DEBUG_EXEC); - if (fstat(fd, fd_sb) == -1) { - /* Always initialize fd_sb. */ - memset(fd_sb, 0, sizeof(*fd_sb)); + if (!sudo_isatty(fd, sb)) debug_return_bool(false); + + if (pgrp != -1) { + if (pgrp != tcgetpgrp(fd)) + debug_return_bool(false); } - if (!S_ISCHR(fd_sb->st_mode)) - debug_return_bool(false); - - /* Compare with tty_sb if available, else just check that fd is a tty. */ - debug_return_bool(tty_sb ? tty_sb->st_rdev == fd_sb->st_rdev : isatty(fd)); + debug_return_bool(true); } /* diff --git a/src/exec_nopty.c b/src/exec_nopty.c index 1b1ae6d55..4de17fb08 100644 --- a/src/exec_nopty.c +++ b/src/exec_nopty.c @@ -470,9 +470,10 @@ static void interpose_pipes(struct exec_closure *ec, const char *tty, int io_pipe[3][2]) { bool interpose[3] = { false, false, false }; - struct stat sb, tty_sbuf, *tty_sb = NULL; struct plugin_container *plugin; + const pid_t pgrp = getpgrp(); bool want_winch = false; + struct stat sb; debug_decl(interpose_pipes, SUDO_DEBUG_EXEC); /* @@ -496,11 +497,8 @@ interpose_pipes(struct exec_closure *ec, const char *tty, int io_pipe[3][2]) * If stdin, stdout or stderr is not the user's tty and logging is * enabled, use a pipe to interpose ourselves. */ - if (tty != NULL && stat(tty, &tty_sbuf) != -1) - tty_sb = &tty_sbuf; - if (interpose[STDIN_FILENO]) { - if (!fd_matches_tty(STDIN_FILENO, tty_sb, &sb)) { + if (!fd_matches_pgrp(STDIN_FILENO, pgrp, &sb)) { sudo_debug_printf(SUDO_DEBUG_INFO, "stdin not user's tty, creating a pipe"); if (pipe2(io_pipe[STDIN_FILENO], O_CLOEXEC) != 0) @@ -510,7 +508,7 @@ interpose_pipes(struct exec_closure *ec, const char *tty, int io_pipe[3][2]) } } if (interpose[STDOUT_FILENO]) { - if (!fd_matches_tty(STDOUT_FILENO, tty_sb, &sb)) { + if (!fd_matches_pgrp(STDOUT_FILENO, pgrp, &sb)) { sudo_debug_printf(SUDO_DEBUG_INFO, "stdout not user's tty, creating a pipe"); if (pipe2(io_pipe[STDOUT_FILENO], O_CLOEXEC) != 0) @@ -520,7 +518,7 @@ interpose_pipes(struct exec_closure *ec, const char *tty, int io_pipe[3][2]) } } if (interpose[STDERR_FILENO]) { - if (!fd_matches_tty(STDERR_FILENO, tty_sb, &sb)) { + if (!fd_matches_pgrp(STDERR_FILENO, pgrp, &sb)) { sudo_debug_printf(SUDO_DEBUG_INFO, "stderr not user's tty, creating a pipe"); if (pipe2(io_pipe[STDERR_FILENO], O_CLOEXEC) != 0) diff --git a/src/exec_pty.c b/src/exec_pty.c index 8a5b9446f..833c7b4d1 100644 --- a/src/exec_pty.c +++ b/src/exec_pty.c @@ -1095,7 +1095,7 @@ exec_pty(struct command_details *details, { int io_pipe[3][2] = { { -1, -1 }, { -1, -1 }, { -1, -1 } }; bool interpose[3] = { false, false, false }; - struct stat sb, tty_sbuf, *tty_sb = NULL; + struct stat sb; int sv[2], intercept_sv[2] = { -1, -1 }; struct exec_closure *ec = &pty_ec; struct plugin_container *plugin; @@ -1203,10 +1203,7 @@ exec_pty(struct command_details *details, * enabled, use a pipe to interpose ourselves instead of using the * pty fd. We always use a pipe for stdin when in background mode. */ - if (user_details->tty != NULL && stat(user_details->tty, &tty_sbuf) != -1) - tty_sb = &tty_sbuf; - - if (!fd_matches_tty(STDIN_FILENO, tty_sb, &sb)) { + if (!fd_matches_pgrp(STDIN_FILENO, ppgrp, &sb)) { if (!interpose[STDIN_FILENO]) { /* Not logging stdin, do not interpose. */ sudo_debug_printf(SUDO_DEBUG_INFO, @@ -1253,7 +1250,7 @@ exec_pty(struct command_details *details, close(io_pipe[STDIN_FILENO][1]); io_pipe[STDIN_FILENO][1] = -1; } - if (!fd_matches_tty(STDOUT_FILENO, tty_sb, &sb)) { + if (!fd_matches_pgrp(STDOUT_FILENO, ppgrp, &sb)) { if (!interpose[STDOUT_FILENO]) { /* Not logging stdout, do not interpose. */ sudo_debug_printf(SUDO_DEBUG_INFO, @@ -1277,7 +1274,7 @@ exec_pty(struct command_details *details, io_fds[SFD_STDOUT] = io_pipe[STDOUT_FILENO][1]; } } - if (!fd_matches_tty(STDERR_FILENO, tty_sb, &sb)) { + if (!fd_matches_pgrp(STDERR_FILENO, ppgrp, &sb)) { if (!interpose[STDERR_FILENO]) { /* Not logging stderr, do not interpose. */ sudo_debug_printf(SUDO_DEBUG_INFO, diff --git a/src/sudo_exec.h b/src/sudo_exec.h index 7dbda8aa8..23e65c0fe 100644 --- a/src/sudo_exec.h +++ b/src/sudo_exec.h @@ -179,7 +179,7 @@ void exec_cmnd(struct command_details *details, sigset_t *mask, int intercept_fd void terminate_command(pid_t pid, bool use_pgrp); bool sudo_terminated(struct command_status *cstat); void free_exec_closure(struct exec_closure *ec); -bool fd_matches_tty(int fd, struct stat *tty_sb, struct stat *fd_sb); +bool fd_matches_pgrp(int fd, pid_t pgrp, struct stat *sb); /* exec_common.c */ int sudo_execve(int fd, const char *path, char *const argv[], char *envp[], int intercept_fd, unsigned int flags);