]> granicus.if.org Git - sudo/commitdiff
Pass on SIGTSTP to the command if it was sent by a user process
authorTodd C. Miller <Todd.Miller@courtesan.com>
Mon, 27 Aug 2012 19:38:57 +0000 (15:38 -0400)
committerTodd C. Miller <Todd.Miller@courtesan.com>
Mon, 27 Aug 2012 19:38:57 +0000 (15:38 -0400)
(not the kernel or the terminal) when we are not I/O logging and
set the default SIGTSTP handler when we re-send the signal to
ourself, restoring our handler after we resume.

--HG--
branch : 1.7

exec.c

diff --git a/exec.c b/exec.c
index 65d505b02650e860af813865c87d7e0a2912417a..d737fce1e03b7ea9ffa8a9e1fe13cbf6be683922 100644 (file)
--- a/exec.c
+++ b/exec.c
@@ -130,8 +130,17 @@ static int fork_cmnd(path, argv, envp, sv, rbac_enabled)
     ppgrp = getpgrp(); /* parent's process group */
 
     /*
-     * XXX - should only send SIGCONT when command pgrp != parent pgrp 
-     *       OR we were suspended by a user (not kernel or tty) signal.
+     * Handle suspend/restore of sudo and the command.
+     * In most cases, the command will be in the same process group as
+     * sudo and job control will "just work".  However, if the command
+     * changes its process group ID and does not change it back (or is
+     * kill by SIGSTOP which is not catchable), we need to resume the
+     * command manually.  Also, if SIGTSTP is sent directly to sudo,
+     * we need to suspend the command, and then suspend ourself, restoring
+     * the default SIGTSTP handler temporarily.
+     *
+     * XXX - currently we send SIGCONT upon resume in some cases where
+     * we don't need to (e.g. command pgrp == parent pgrp).
      */
     zero_bytes(&sa, sizeof(sa));
     sigemptyset(&sa.sa_mask);
@@ -143,6 +152,10 @@ static int fork_cmnd(path, argv, envp, sv, rbac_enabled)
     sa.sa_handler = handler;
 #endif
     sigaction(SIGCONT, &sa, NULL);
+#ifdef SA_SIGINFO
+    sa.sa_sigaction = handler_user_only;
+#endif
+    sigaction(SIGTSTP, &sa, NULL);
 
     cmnd_pid = fork();
     switch (cmnd_pid) {
@@ -581,15 +594,25 @@ handle_signals(sv, child, cstat)
                         * with SIGTTOU while the command continues to run.
                         */
 #ifdef HAVE_TCSETPGRP
+                       sigaction_t sa, osa;
                        pid_t saved_pgrp = (pid_t)-1;
+                       int signo = WSTOPSIG(status);
                        int fd = open(_PATH_TTY, O_RDWR|O_NOCTTY, 0);
                        if (fd != -1) {
                            if ((saved_pgrp = tcgetpgrp(fd)) == ppgrp)
                                saved_pgrp = -1;
                        }
 #endif /* HAVE_TCSETPGRP */
-                       if (kill(getpid(), WSTOPSIG(status)) != 0)
-                           warning("kill(%d, %d)", getpid(), WSTOPSIG(status));
+                       if (signo == SIGTSTP) {
+                           zero_bytes(&sa, sizeof(sa));
+                           sigemptyset(&sa.sa_mask);
+                           sa.sa_handler = SIG_DFL;
+                           sigaction(SIGTSTP, &sa, NULL);
+                       }
+                       if (kill(getpid(), signo) != 0)
+                           warning("kill(%d, %d)", getpid(), signo);
+                       if (signo == SIGTSTP)
+                           sigaction(SIGTSTP, &osa, NULL);
 #ifdef HAVE_TCSETPGRP
                        if (fd != -1) {
                            /*