]> granicus.if.org Git - sudo/commitdiff
When not logging I/O, use a signal handler that only forwards SIGINT,
authorTodd C. Miller <Todd.Miller@courtesan.com>
Tue, 17 Jan 2012 17:20:28 +0000 (12:20 -0500)
committerTodd C. Miller <Todd.Miller@courtesan.com>
Tue, 17 Jan 2012 17:20:28 +0000 (12:20 -0500)
SIGQUIT and SIGHUP when they are user-generated signals.  Fixes a
race in the non-I/O logging path where the command may receive two
keyboard-generated signals; one from the kernel and one from the
sudo process.

--HG--
branch : 1.7

exec.c

diff --git a/exec.c b/exec.c
index 8235829cfb2904d4bb9c82e61df446936897b56f..289c3de07b7bf34f7262ecb44e2fdf394a8d54f9 100644 (file)
--- a/exec.c
+++ b/exec.c
@@ -86,6 +86,9 @@ static int log_io;
 
 static int handle_signals __P((int fd, pid_t child,
     struct command_status *cstat));
+#ifdef SA_SIGINFO
+static void handler_nofwd __P((int s, siginfo_t *info, void *context));
+#endif
 
 /*
  * Like execve(2) but falls back to running through /bin/sh
@@ -296,14 +299,31 @@ sudo_execve(path, argv, envp, uid, cstat, dowait, bgmode)
     sa.sa_handler = handler;
     sigaction(SIGALRM, &sa, NULL);
     sigaction(SIGCHLD, &sa, NULL);
-    sigaction(SIGHUP, &sa, NULL);
-    sigaction(SIGINT, &sa, NULL);
     sigaction(SIGPIPE, &sa, NULL);
-    sigaction(SIGQUIT, &sa, NULL);
     sigaction(SIGTERM, &sa, NULL);
     sigaction(SIGUSR1, &sa, NULL);
     sigaction(SIGUSR2, &sa, NULL);
 
+    /*
+     * When not running the command in a pty, we do not want to
+     * forward signals generated by the kernel that the child will
+     * already have received either by virtue of being in the
+     * controlling tty's process group (SIGINT, SIGQUIT) or because
+     * the session is terminating (SIGHUP).
+     */
+#ifdef SA_SIGINFO
+# ifdef _PATH_SUDO_IO_LOGDIR
+    if (!log_io)
+# endif
+    {
+       sa.sa_flags |= SA_SIGINFO;
+       sa.sa_sigaction = handler_nofwd;
+    }
+#endif /* SA_SIGINFO */
+    sigaction(SIGHUP, &sa, NULL);
+    sigaction(SIGINT, &sa, NULL);
+    sigaction(SIGQUIT, &sa, NULL);
+
     /* Max fd we will be selecting on. */
     maxfd = MAX(sv[0], signal_pipe[0]);
 
@@ -631,6 +651,33 @@ handler(s)
        /* shut up glibc */;
 }
 
+#ifdef SA_SIGINFO
+/*
+ * Generic handler for signals passed from parent -> child.
+ * The other end of signal_pipe is checked in the main event loop.
+ * This version is for the non-pty case and does not forward
+ * signals that are generated by the kernel.
+ */
+static RETSIGTYPE
+handler_nofwd(s, info, context)
+    int s;
+    siginfo_t *info;
+    void *context;
+{
+    unsigned char signo = (unsigned char)s;
+
+    /* Only forward user-generated signals. */
+    if (info->si_code <= 0) {
+       /*
+        * The pipe is non-blocking, if we overflow the kernel's pipe
+        * buffer we drop the signal.  This is not a problem in practice.
+        */
+       if (write(signal_pipe[1], &signo, sizeof(signo)) == -1)
+           /* shut up glibc */;
+    }
+}
+#endif /* SA_SIGINFO */
+
 /*
  * Open a pipe and make both ends non-blocking.
  * Returns 0 on success and -1 on error.