]> granicus.if.org Git - sudo/commitdiff
Use SOCK_STREAM for socketpair, not SOCK_DGRAM so we get consistent
authorTodd C. Miller <Todd.Miller@courtesan.com>
Sat, 12 Oct 2013 11:39:02 +0000 (05:39 -0600)
committerTodd C. Miller <Todd.Miller@courtesan.com>
Sat, 12 Oct 2013 11:39:02 +0000 (05:39 -0600)
semantics when the other end closes.  This should make the conversion
to poll() less problematic.

src/exec.c
src/exec_pty.c

index f70ad77f89ec4bfb59ab89c6efa9880d488d23c7..2d966ca285b2af0a1bda50c46f6d5bbdc9676392 100644 (file)
@@ -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.
index f8940e5be8221b6e4bb80e3d477d0164cd5bbc6e..286fe4e5b681c2b493e9f95664c68934e977e3be 100644 (file)
@@ -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"),