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.
This commit is contained in:
Todd C. Miller
2016-04-22 16:36:36 -06:00
parent 70cf5674b5
commit b4309d4aea
8 changed files with 29 additions and 37 deletions

View File

@@ -1111,6 +1111,7 @@ DDEESSCCRRIIPPTTIIOONN
++oo SIGALRM ++oo SIGALRM
++oo SIGHUP ++oo SIGHUP
++oo SIGINT ++oo SIGINT
++oo SIGPIPE
++oo SIGQUIT ++oo SIGQUIT
++oo SIGTERM ++oo SIGTERM
++oo SIGTSTP ++oo SIGTSTP
@@ -1121,7 +1122,8 @@ DDEESSCCRRIIPPTTIIOONN
call the plugin's cclloossee() function with an exit status of 128 plus the 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 value of the signal that was received. This allows for consistent
logging of commands killed by a signal for plugins that log such 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 A plugin may temporarily install its own signal handlers but must restore
the original handler before the plugin function returns. the original handler before the plugin function returns.

View File

@@ -1978,6 +1978,9 @@ executed:
\fRSIGINT\fR \fRSIGINT\fR
.TP 4n .TP 4n
\fB\(bu\fR \fB\(bu\fR
\fRSIGPIPE\fR
.TP 4n
\fB\(bu\fR
\fRSIGQUIT\fR \fRSIGQUIT\fR
.TP 4n .TP 4n
\fB\(bu\fR \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 for plugins that log such information in their
\fBclose\fR() \fBclose\fR()
function. function.
An exception to this is
\fRSIGPIPE\fR,
which is ignored until the command is executed.
.PP .PP
A plugin may temporarily install its own signal handlers but must A plugin may temporarily install its own signal handlers but must
restore the original handler before the plugin function returns. restore the original handler before the plugin function returns.

View File

@@ -1735,6 +1735,8 @@ executed:
.It .It
.Dv SIGINT .Dv SIGINT
.It .It
.Dv SIGPIPE
.It
.Dv SIGQUIT .Dv SIGQUIT
.It .It
.Dv SIGTERM .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 for plugins that log such information in their
.Fn close .Fn close
function. function.
An exception to this is
.Ev SIGPIPE ,
which is ignored until the command is executed.
.Pp .Pp
A plugin may temporarily install its own signal handlers but must A plugin may temporarily install its own signal handlers but must
restore the original handler before the plugin function returns. restore the original handler before the plugin function returns.

View File

@@ -2975,17 +2975,10 @@ sudo_ldap_open(struct sudo_nss *nss)
{ {
LDAP *ld; LDAP *ld;
int rc = -1; int rc = -1;
sigaction_t sa, saved_sa_pipe;
bool ldapnoinit = false; bool ldapnoinit = false;
struct sudo_ldap_handle *handle; struct sudo_ldap_handle *handle;
debug_decl(sudo_ldap_open, SUDOERS_DEBUG_LDAP) 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()) if (!sudo_ldap_read_config())
goto done; goto done;
@@ -3071,7 +3064,6 @@ sudo_ldap_open(struct sudo_nss *nss)
nss->handle = handle; nss->handle = handle;
done: done:
(void) sigaction(SIGPIPE, &saved_sa_pipe, NULL);
debug_return_int(rc == LDAP_SUCCESS ? 0 : -1); debug_return_int(rc == LDAP_SUCCESS ? 0 : -1);
} }

View File

@@ -542,7 +542,6 @@ send_mail(const char *fmt, ...)
const char *timestr; const char *timestr;
int fd, pfd[2], status; int fd, pfd[2], status;
pid_t pid, rv; pid_t pid, rv;
sigaction_t sa;
struct stat sb; struct stat sb;
va_list ap; va_list ap;
#ifndef NO_ROOT_MAILER #ifndef NO_ROOT_MAILER
@@ -619,13 +618,6 @@ send_mail(const char *fmt, ...)
sudo_endgrent(); sudo_endgrent();
closefrom(STDERR_FILENO + 1); 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) { if (pipe(pfd) == -1) {
mysyslog(LOG_ERR, _("unable to open pipe: %m")); mysyslog(LOG_ERR, _("unable to open pipe: %m"));
sudo_debug_printf(SUDO_DEBUG_ERROR, "unable to open pipe: %s", sudo_debug_printf(SUDO_DEBUG_ERROR, "unable to open pipe: %s",

View File

@@ -30,6 +30,7 @@
#include <signal.h> #include <signal.h>
#include "sudo.h" #include "sudo.h"
#include "sudo_exec.h"
int signal_pipe[2]; int signal_pipe[2];
@@ -151,6 +152,13 @@ init_signals(void)
break; 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; debug_return;
} }

View File

@@ -188,10 +188,13 @@ main(int argc, char *argv[], char *envp[])
/* Make sure we are setuid root. */ /* Make sure we are setuid root. */
sudo_check_suid(argc > 0 ? argv[0] : "sudo"); 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) sigemptyset(&mask);
(void) sigprocmask(SIG_SETMASK, &mask, NULL); (void) sigprocmask(SIG_SETMASK, &mask, NULL);
save_signals();
/* Parse the rest of sudo.conf. */ /* Parse the rest of sudo.conf. */
sudo_conf_read(NULL, SUDO_CONF_ALL & ~SUDO_CONF_DEBUG); 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")); sudo_fatalx(U_("unable to initialize policy plugin"));
} }
init_signals();
switch (sudo_mode & MODE_MASK) { switch (sudo_mode & MODE_MASK) {
case MODE_VERSION: case MODE_VERSION:
policy_show_version(&policy_plugin, !user_details.uid); policy_show_version(&policy_plugin, !user_details.uid);

View File

@@ -85,7 +85,7 @@ tgetpass(const char *prompt, int timeout, int flags,
struct sudo_conv_callback *callback) struct sudo_conv_callback *callback)
{ {
sigaction_t sa, savealrm, saveint, savehup, savequit, saveterm; sigaction_t sa, savealrm, saveint, savehup, savequit, saveterm;
sigaction_t savetstp, savettin, savettou, savepipe; sigaction_t savetstp, savettin, savettou;
char *pass; char *pass;
static const char *askpass; static const char *askpass;
static char buf[SUDO_CONV_REPL_MAX + 1]; static char buf[SUDO_CONV_REPL_MAX + 1];
@@ -168,10 +168,6 @@ restart:
(void) sigaction(SIGTTIN, &sa, &savettin); (void) sigaction(SIGTTIN, &sa, &savettin);
(void) sigaction(SIGTTOU, &sa, &savettou); (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 (prompt) {
if (write(output, prompt, strlen(prompt)) == -1) if (write(output, prompt, strlen(prompt)) == -1)
goto restore; goto restore;
@@ -198,7 +194,6 @@ restore:
(void) sigaction(SIGTSTP, &savetstp, NULL); (void) sigaction(SIGTSTP, &savetstp, NULL);
(void) sigaction(SIGTTIN, &savettin, NULL); (void) sigaction(SIGTTIN, &savettin, NULL);
(void) sigaction(SIGTTOU, &savettou, NULL); (void) sigaction(SIGTTOU, &savettou, NULL);
(void) sigaction(SIGPIPE, &savepipe, NULL);
/* Restore old tty settings. */ /* Restore old tty settings. */
if (!ISSET(flags, TGP_ECHO)) { if (!ISSET(flags, TGP_ECHO)) {
@@ -252,7 +247,6 @@ static char *
sudo_askpass(const char *askpass, const char *prompt) sudo_askpass(const char *askpass, const char *prompt)
{ {
static char buf[SUDO_CONV_REPL_MAX + 1], *pass; static char buf[SUDO_CONV_REPL_MAX + 1], *pass;
sigaction_t sa, saved_sa_pipe;
int pfd[2], status; int pfd[2], status;
pid_t child; pid_t child;
debug_decl(sudo_askpass, SUDO_DEBUG_CONV) debug_decl(sudo_askpass, SUDO_DEBUG_CONV)
@@ -286,18 +280,10 @@ sudo_askpass(const char *askpass, const char *prompt)
_exit(255); _exit(255);
} }
/* Ignore SIGPIPE in case child exits prematurely */ /* Get response from child (askpass). */
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 */
(void) close(pfd[1]); (void) close(pfd[1]);
pass = getln(pfd[0], buf, sizeof(buf), 0); pass = getln(pfd[0], buf, sizeof(buf), 0);
(void) close(pfd[0]); (void) close(pfd[0]);
(void) sigaction(SIGPIPE, &saved_sa_pipe, NULL);
/* Wait for child to exit. */ /* Wait for child to exit. */
for (;;) { for (;;) {