From: Todd C. Miller Date: Tue, 17 Jan 2012 17:20:28 +0000 (-0500) Subject: When not logging I/O, use a signal handler that only forwards SIGINT, X-Git-Tag: SUDO_1_7_9~22 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=2e965cd606a75b697745fb67e3f83b1ff1c87adc;p=sudo When not logging I/O, use a signal handler that only forwards SIGINT, 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 --- diff --git a/exec.c b/exec.c index 8235829cf..289c3de07 100644 --- 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.