From b4309d4aea1ec349e86f637b99a68763d64daf58 Mon Sep 17 00:00:00 2001 From: "Todd C. Miller" Date: Fri, 22 Apr 2016 16:36:36 -0600 Subject: [PATCH] Ignore SIGPIPE for the duration of sudo and not just in a few select places. We have no control over what nss, PAM modules or sudo plugins might do so ignoring SIGPIPE is safest. --- doc/sudo_plugin.cat | 4 +++- doc/sudo_plugin.man.in | 6 ++++++ doc/sudo_plugin.mdoc.in | 5 +++++ plugins/sudoers/ldap.c | 8 -------- plugins/sudoers/logging.c | 8 -------- src/signal.c | 8 ++++++++ src/sudo.c | 9 +++++---- src/tgetpass.c | 18 ++---------------- 8 files changed, 29 insertions(+), 37 deletions(-) diff --git a/doc/sudo_plugin.cat b/doc/sudo_plugin.cat index c20fae152..4e2359c64 100644 --- a/doc/sudo_plugin.cat +++ b/doc/sudo_plugin.cat @@ -1111,6 +1111,7 @@ DDEESSCCRRIIPPTTIIOONN ++oo SIGALRM ++oo SIGHUP ++oo SIGINT + ++oo SIGPIPE ++oo SIGQUIT ++oo SIGTERM ++oo SIGTSTP @@ -1121,7 +1122,8 @@ DDEESSCCRRIIPPTTIIOONN call the plugin's cclloossee() function with an exit status of 128 plus the value of the signal that was received. This allows for consistent logging of commands killed by a signal for plugins that log such - information in their cclloossee() function. + information in their cclloossee() function. An exception to this is SIGPIPE, + which is ignored until the command is executed. A plugin may temporarily install its own signal handlers but must restore the original handler before the plugin function returns. diff --git a/doc/sudo_plugin.man.in b/doc/sudo_plugin.man.in index 67e5c16da..1c47fec55 100644 --- a/doc/sudo_plugin.man.in +++ b/doc/sudo_plugin.man.in @@ -1978,6 +1978,9 @@ executed: \fRSIGINT\fR .TP 4n \fB\(bu\fR +\fRSIGPIPE\fR +.TP 4n +\fB\(bu\fR \fRSIGQUIT\fR .TP 4n \fB\(bu\fR @@ -2003,6 +2006,9 @@ This allows for consistent logging of commands killed by a signal for plugins that log such information in their \fBclose\fR() function. +An exception to this is +\fRSIGPIPE\fR, +which is ignored until the command is executed. .PP A plugin may temporarily install its own signal handlers but must restore the original handler before the plugin function returns. diff --git a/doc/sudo_plugin.mdoc.in b/doc/sudo_plugin.mdoc.in index 87c933324..d5507ba73 100644 --- a/doc/sudo_plugin.mdoc.in +++ b/doc/sudo_plugin.mdoc.in @@ -1735,6 +1735,8 @@ executed: .It .Dv SIGINT .It +.Dv SIGPIPE +.It .Dv SIGQUIT .It .Dv SIGTERM @@ -1756,6 +1758,9 @@ This allows for consistent logging of commands killed by a signal for plugins that log such information in their .Fn close function. +An exception to this is +.Ev SIGPIPE , +which is ignored until the command is executed. .Pp A plugin may temporarily install its own signal handlers but must restore the original handler before the plugin function returns. diff --git a/plugins/sudoers/ldap.c b/plugins/sudoers/ldap.c index 97c2c756f..00fcb2105 100644 --- a/plugins/sudoers/ldap.c +++ b/plugins/sudoers/ldap.c @@ -2975,17 +2975,10 @@ sudo_ldap_open(struct sudo_nss *nss) { LDAP *ld; int rc = -1; - sigaction_t sa, saved_sa_pipe; bool ldapnoinit = false; struct sudo_ldap_handle *handle; debug_decl(sudo_ldap_open, SUDOERS_DEBUG_LDAP) - /* Ignore SIGPIPE if we cannot bind to the server. */ - memset(&sa, 0, sizeof(sa)); - sigemptyset(&sa.sa_mask); - sa.sa_handler = SIG_IGN; - (void) sigaction(SIGPIPE, &sa, &saved_sa_pipe); - if (!sudo_ldap_read_config()) goto done; @@ -3071,7 +3064,6 @@ sudo_ldap_open(struct sudo_nss *nss) nss->handle = handle; done: - (void) sigaction(SIGPIPE, &saved_sa_pipe, NULL); debug_return_int(rc == LDAP_SUCCESS ? 0 : -1); } diff --git a/plugins/sudoers/logging.c b/plugins/sudoers/logging.c index cbb18ce00..ed3c8be1e 100644 --- a/plugins/sudoers/logging.c +++ b/plugins/sudoers/logging.c @@ -542,7 +542,6 @@ send_mail(const char *fmt, ...) const char *timestr; int fd, pfd[2], status; pid_t pid, rv; - sigaction_t sa; struct stat sb; va_list ap; #ifndef NO_ROOT_MAILER @@ -619,13 +618,6 @@ send_mail(const char *fmt, ...) sudo_endgrent(); closefrom(STDERR_FILENO + 1); - /* Ignore SIGPIPE in case mailer exits prematurely (or is missing). */ - memset(&sa, 0, sizeof(sa)); - sigemptyset(&sa.sa_mask); - sa.sa_flags = SA_INTERRUPT; - sa.sa_handler = SIG_IGN; - (void) sigaction(SIGPIPE, &sa, NULL); - if (pipe(pfd) == -1) { mysyslog(LOG_ERR, _("unable to open pipe: %m")); sudo_debug_printf(SUDO_DEBUG_ERROR, "unable to open pipe: %s", diff --git a/src/signal.c b/src/signal.c index 888492fad..28a3b6e3f 100644 --- a/src/signal.c +++ b/src/signal.c @@ -30,6 +30,7 @@ #include #include "sudo.h" +#include "sudo_exec.h" int signal_pipe[2]; @@ -151,6 +152,13 @@ init_signals(void) break; } } + /* Ignore SIGPIPE until exec. */ + if (saved_signals[SAVED_SIGPIPE].sa.sa_handler != SIG_IGN) { + sa.sa_handler = SIG_IGN; + if (sigaction(SIGPIPE, &sa, NULL) != 0) + sudo_warn(U_("unable to set handler for signal %d"), SIGPIPE); + } + debug_return; } diff --git a/src/sudo.c b/src/sudo.c index d4be82acd..46e5ce44f 100644 --- a/src/sudo.c +++ b/src/sudo.c @@ -188,10 +188,13 @@ main(int argc, char *argv[], char *envp[]) /* Make sure we are setuid root. */ sudo_check_suid(argc > 0 ? argv[0] : "sudo"); - /* Reset signal mask and save signal state. */ + /* Save original signal state and setup default signal handlers. */ + save_signals(); + init_signals(); + + /* Reset signal mask to the default value (unblock). */ (void) sigemptyset(&mask); (void) sigprocmask(SIG_SETMASK, &mask, NULL); - save_signals(); /* Parse the rest of sudo.conf. */ sudo_conf_read(NULL, SUDO_CONF_ALL & ~SUDO_CONF_DEBUG); @@ -230,8 +233,6 @@ main(int argc, char *argv[], char *envp[]) sudo_fatalx(U_("unable to initialize policy plugin")); } - init_signals(); - switch (sudo_mode & MODE_MASK) { case MODE_VERSION: policy_show_version(&policy_plugin, !user_details.uid); diff --git a/src/tgetpass.c b/src/tgetpass.c index 47291bc1f..671c021d8 100644 --- a/src/tgetpass.c +++ b/src/tgetpass.c @@ -85,7 +85,7 @@ tgetpass(const char *prompt, int timeout, int flags, struct sudo_conv_callback *callback) { sigaction_t sa, savealrm, saveint, savehup, savequit, saveterm; - sigaction_t savetstp, savettin, savettou, savepipe; + sigaction_t savetstp, savettin, savettou; char *pass; static const char *askpass; static char buf[SUDO_CONV_REPL_MAX + 1]; @@ -168,10 +168,6 @@ restart: (void) sigaction(SIGTTIN, &sa, &savettin); (void) sigaction(SIGTTOU, &sa, &savettou); - /* Ignore SIGPIPE in case stdin is a pipe and TGP_STDIN is set */ - sa.sa_handler = SIG_IGN; - (void) sigaction(SIGPIPE, &sa, &savepipe); - if (prompt) { if (write(output, prompt, strlen(prompt)) == -1) goto restore; @@ -198,7 +194,6 @@ restore: (void) sigaction(SIGTSTP, &savetstp, NULL); (void) sigaction(SIGTTIN, &savettin, NULL); (void) sigaction(SIGTTOU, &savettou, NULL); - (void) sigaction(SIGPIPE, &savepipe, NULL); /* Restore old tty settings. */ if (!ISSET(flags, TGP_ECHO)) { @@ -252,7 +247,6 @@ static char * sudo_askpass(const char *askpass, const char *prompt) { static char buf[SUDO_CONV_REPL_MAX + 1], *pass; - sigaction_t sa, saved_sa_pipe; int pfd[2], status; pid_t child; debug_decl(sudo_askpass, SUDO_DEBUG_CONV) @@ -286,18 +280,10 @@ sudo_askpass(const char *askpass, const char *prompt) _exit(255); } - /* Ignore SIGPIPE in case child exits prematurely */ - memset(&sa, 0, sizeof(sa)); - sigemptyset(&sa.sa_mask); - sa.sa_flags = SA_INTERRUPT; - sa.sa_handler = SIG_IGN; - (void) sigaction(SIGPIPE, &sa, &saved_sa_pipe); - - /* Get response from child (askpass) and restore SIGPIPE handler */ + /* Get response from child (askpass). */ (void) close(pfd[1]); pass = getln(pfd[0], buf, sizeof(buf), 0); (void) close(pfd[0]); - (void) sigaction(SIGPIPE, &saved_sa_pipe, NULL); /* Wait for child to exit. */ for (;;) { -- 2.40.0