Always resume the command in the foreground if sudo itself is the

foreground process.  This helps work around poorly behaved programs
that catch SIGTTOU/SIGTTIN but suspend themselves with SIGSTOP.  At
worst, sudo will go into the background but upon resume the command
will be runnable.  Otherwise, we can get into a situation where the
command will immediately suspend itself.
This commit is contained in:
Todd C. Miller
2013-01-11 10:09:06 -05:00
parent adbc8a574f
commit 8b3edcc4a8

View File

@@ -348,15 +348,15 @@ suspend_parent(int signo)
{ {
char signame[SIG2STR_MAX]; char signame[SIG2STR_MAX];
sigaction_t sa, osa; sigaction_t sa, osa;
int n, oldmode = ttymode, rval = 0; int n, rval = 0;
debug_decl(suspend_parent, SUDO_DEBUG_EXEC); debug_decl(suspend_parent, SUDO_DEBUG_EXEC);
switch (signo) { switch (signo) {
case SIGTTOU: case SIGTTOU:
case SIGTTIN: case SIGTTIN:
/* /*
* If we are the foreground process, just resume the command. * If sudo is already the foreground process, just resume the command
* Otherwise, re-send the signal with the handler disabled. * in the foreground. If not, we'll suspend sudo and resume later.
*/ */
if (!foreground) if (!foreground)
check_foreground(); check_foreground();
@@ -370,7 +370,6 @@ suspend_parent(int signo)
rval = SIGCONT_FG; /* resume command in foreground */ rval = SIGCONT_FG; /* resume command in foreground */
break; break;
} }
ttymode = TERM_RAW;
/* FALLTHROUGH */ /* FALLTHROUGH */
case SIGSTOP: case SIGSTOP:
case SIGTSTP: case SIGTSTP:
@@ -378,7 +377,7 @@ suspend_parent(int signo)
flush_output(); flush_output();
/* Restore original tty mode before suspending. */ /* Restore original tty mode before suspending. */
if (oldmode != TERM_COOKED) { if (ttymode != TERM_COOKED) {
do { do {
n = term_restore(io_fds[SFD_USERTTY], 0); n = term_restore(io_fds[SFD_USERTTY], 0);
} while (!n && errno == EINTR); } while (!n && errno == EINTR);
@@ -403,23 +402,27 @@ suspend_parent(int signo)
check_foreground(); check_foreground();
/* /*
* Only modify term if we are foreground process and either * We always resume the command in the foreground if sudo itself
* the old tty mode was not cooked or command got SIGTT{IN,OU} * is the foreground process. This helps work around poorly behaved
* programs that catch SIGTTOU/SIGTTIN but suspend themselves with
* SIGSTOP. At worst, sudo will go into the background but upon
* resume the command will be runnable. Otherwise, we can get into
* a situation where the command will immediately suspend itself.
*/ */
sudo_debug_printf(SUDO_DEBUG_INFO, "parent is in %s, ttymode %d -> %d", sudo_debug_printf(SUDO_DEBUG_INFO, "parent is in %s, ttymode %d -> %d",
foreground ? "foreground" : "background", oldmode, ttymode); foreground ? "foreground" : "background", ttymode,
foreground ? TERM_RAW : TERM_COOKED);
if (ttymode != TERM_COOKED) {
if (foreground) { if (foreground) {
/* Set raw mode. */ /* Foreground process, set tty to raw mode. */
do { do {
n = term_raw(io_fds[SFD_USERTTY], 0); n = term_raw(io_fds[SFD_USERTTY], 0);
} while (!n && errno == EINTR); } while (!n && errno == EINTR);
ttymode = TERM_RAW;
} else { } else {
/* Background process, no access to tty. */ /* Background process, no access to tty. */
ttymode = TERM_COOKED; ttymode = TERM_COOKED;
} }
}
if (signo != SIGSTOP) if (signo != SIGSTOP)
sigaction(signo, &osa, NULL); sigaction(signo, &osa, NULL);