From ff18c65862ff8453aa0fb51aafd3482caf2f9ec6 Mon Sep 17 00:00:00 2001 From: "Todd C. Miller" Date: Sat, 12 Oct 2013 05:39:02 -0600 Subject: [PATCH] Use SOCK_STREAM for socketpair, not SOCK_DGRAM so we get consistent semantics when the other end closes. This should make the conversion to poll() less problematic. --- src/exec.c | 34 ++++++++++++++-------------------- src/exec_pty.c | 15 ++++++++++----- 2 files changed, 24 insertions(+), 25 deletions(-) diff --git a/src/exec.c b/src/exec.c index f70ad77f8..2d966ca28 100644 --- a/src/exec.c +++ b/src/exec.c @@ -255,7 +255,7 @@ sudo_execute(struct command_details *details, struct command_status *cstat) * We communicate with the child over a bi-directional pair of sockets. * Parent sends signal info to child and child sends back wait status. */ - if (socketpair(PF_UNIX, SOCK_DGRAM, 0, sv) == -1) + if (socketpair(PF_UNIX, SOCK_STREAM, 0, sv) == -1) fatal(_("unable to create sockets")); /* @@ -374,12 +374,7 @@ sudo_execute(struct command_details *details, struct command_status *cstat) if (n == -1) { if (errno == EINTR) continue; - /* - * If not logging I/O we may receive ECONNRESET when - * the command is executed and sv is closed. - * It is safe to ignore this. - */ - if (log_io && errno != EAGAIN) { + if (errno != EAGAIN) { cstat->type = CMD_ERRNO; cstat->val = errno; break; @@ -391,8 +386,16 @@ sudo_execute(struct command_details *details, struct command_status *cstat) sudo_debug_printf(SUDO_DEBUG_ERROR, "failed to read child status: %s", n ? "short read" : "EOF"); - /* XXX - should set cstat */ - break; + /* + * If not logging I/O we may get EOF when the command is + * executed and sv is closed. It is safe to ignore this. + */ + if (log_io || n != 0) { + /* XXX - need new CMD_ type for monitor errors. */ + cstat->type = CMD_ERRNO; + cstat->val = n ? EIO : ECONNRESET; + break; + } } } if (cstat->type == CMD_PID) { @@ -505,17 +508,8 @@ dispatch_signals(int sv[2], pid_t child, int log_io, struct command_status *csta do { pid = waitpid(child, &status, WUNTRACED|WNOHANG); } while (pid == -1 && errno == EINTR); - if (pid == child) { - if (log_io) { - /* - * On BSD we get ECONNRESET on sv[0] if monitor dies - * and select() will return with sv[0] readable. - * On Linux that doesn't appear to happen so if the - * monitor dies, shut down the socketpair to force a - * select() notification. - */ - (void) shutdown(sv[0], SHUT_WR); - } else if (WIFSTOPPED(status)) { + if (pid == child && !log_io) { + if (WIFSTOPPED(status)) { /* * Save the controlling terminal's process group * so we can restore it after we resume, if needed. diff --git a/src/exec_pty.c b/src/exec_pty.c index f8940e5be..286fe4e5b 100644 --- a/src/exec_pty.c +++ b/src/exec_pty.c @@ -1170,11 +1170,16 @@ exec_monitor(struct command_details *details, int backchannel) /* read command from backchannel, should be a signal */ n = recv(backchannel, &cstmp, sizeof(cstmp), 0); - if (n == -1) { - if (errno == EINTR) - continue; - warning(_("error reading from socketpair")); - goto done; + if (n != sizeof(cstmp)) { + if (n == -1) { + if (errno == EINTR) + continue; + warning(_("error reading from socketpair")); + goto done; + } else { + /* /* short read or EOF, parent process died? */ + goto done; + } } if (cstmp.type != CMD_SIGNO) { warningx(_("unexpected reply type on backchannel: %d"), -- 2.49.0