]> granicus.if.org Git - sudo/commitdiff
Always resume the command in the foreground if sudo itself is the
authorTodd C. Miller <Todd.Miller@courtesan.com>
Fri, 11 Jan 2013 15:09:06 +0000 (10:09 -0500)
committerTodd C. Miller <Todd.Miller@courtesan.com>
Fri, 11 Jan 2013 15:09:06 +0000 (10:09 -0500)
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.

src/exec_pty.c

index a80dbb20d908fd461522e1ee0262464d1d253389..cb5c11dc11bd0602392514d45bfa06af419043d7 100644 (file)
@@ -348,15 +348,15 @@ suspend_parent(int signo)
 {
     char signame[SIG2STR_MAX];
     sigaction_t sa, osa;
-    int n, oldmode = ttymode, rval = 0;
+    int n, rval = 0;
     debug_decl(suspend_parent, SUDO_DEBUG_EXEC);
 
     switch (signo) {
     case SIGTTOU:
     case SIGTTIN:
        /*
-        * If we are the foreground process, just resume the command.
-        * Otherwise, re-send the signal with the handler disabled.
+        * If sudo is already the foreground process, just resume the command
+        * in the foreground.  If not, we'll suspend sudo and resume later.
         */
        if (!foreground)
            check_foreground();
@@ -370,7 +370,6 @@ suspend_parent(int signo)
            rval = SIGCONT_FG; /* resume command in foreground */
            break;
        }
-       ttymode = TERM_RAW;
        /* FALLTHROUGH */
     case SIGSTOP:
     case SIGTSTP:
@@ -378,7 +377,7 @@ suspend_parent(int signo)
        flush_output();
 
        /* Restore original tty mode before suspending. */
-       if (oldmode != TERM_COOKED) {
+       if (ttymode != TERM_COOKED) {
            do {
                n = term_restore(io_fds[SFD_USERTTY], 0);
            } while (!n && errno == EINTR);
@@ -403,22 +402,26 @@ suspend_parent(int signo)
        check_foreground();
 
        /*
-        * Only modify term if we are foreground process and either
-        * the old tty mode was not cooked or command got SIGTT{IN,OU}
+        * We 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.
         */
        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) {
-               /* Set raw mode. */
-               do {
-                   n = term_raw(io_fds[SFD_USERTTY], 0);
-               } while (!n && errno == EINTR);
-           } else {
-               /* Background process, no access to tty. */
-               ttymode = TERM_COOKED;
-           }
+       if (foreground) {
+           /* Foreground process, set tty to raw mode. */
+           do {
+               n = term_raw(io_fds[SFD_USERTTY], 0);
+           } while (!n && errno == EINTR);
+           ttymode = TERM_RAW;
+       } else {
+           /* Background process, no access to tty. */
+           ttymode = TERM_COOKED;
        }
 
        if (signo != SIGSTOP)