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:
@@ -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);
|
||||||
|
Reference in New Issue
Block a user