]> granicus.if.org Git - sudo/commitdiff
Close the pty slave in the parent so that when the command and
authorTodd C. Miller <Todd.Miller@sudo.ws>
Mon, 20 Aug 2018 16:04:15 +0000 (10:04 -0600)
committerTodd C. Miller <Todd.Miller@sudo.ws>
Mon, 20 Aug 2018 16:04:15 +0000 (10:04 -0600)
monitor exit, the pty gets recycled without our having to close
it directly.

src/exec_monitor.c
src/exec_pty.c

index 4b4a7f92e8f83a0aea81b07e96a579257eb8521f..b0a362f50db9082f73e31ca584deb6d5ce5009a6 100644 (file)
@@ -594,6 +594,15 @@ exec_monitor(struct command_details *details, sigset_t *oset,
     if (pipe2(errpipe, O_CLOEXEC) != 0)
        sudo_fatal(U_("unable to create pipe"));
 
+    /*
+     * Before forking, wait for the main sudo process to tell us to go.
+     * Avoids race conditions when the command exits quickly.
+     */
+    while (recv(backchannel, &cstat, sizeof(cstat), MSG_WAITALL) == -1) {
+       if (errno != EINTR && errno != EAGAIN)
+           sudo_fatal(U_("unable to receive message from parent"));
+    }
+
     mc.cmnd_pid = sudo_debug_fork();
     switch (mc.cmnd_pid) {
     case -1:
index d3f96edaf8eb09b103140e888fe9d133239fc563..36b9e7d5d965358c3675d93986b30d90ed3242ef 100644 (file)
@@ -744,23 +744,15 @@ io_buf_new(int rfd, int wfd,
     debug_return;
 }
 
+/*
+ * We already closed the slave pty so reads from the master will not block.
+ */
 static void
-pty_close(struct command_status *cstat)
+pty_finish(struct command_status *cstat)
 {
     struct io_buffer *iob;
     int n;
-    debug_decl(pty_close, SUDO_DEBUG_EXEC);
-
-#ifndef _AIX
-    /*
-     * Close the pty slave first so reads from the master don't block.
-     * On AIX as it will cause us to lose *our* controlling tty too!
-     */
-    if (io_fds[SFD_SLAVE] != -1) {
-       close(io_fds[SFD_SLAVE]);
-       io_fds[SFD_SLAVE] = -1;
-    }
-#endif
+    debug_decl(pty_finish, SUDO_DEBUG_EXEC);
 
     /* Flush any remaining output (the plugin already got it). */
     if (io_fds[SFD_USERTTY] != -1) {
@@ -790,14 +782,6 @@ pty_close(struct command_status *cstat)
     if (utmp_user != NULL)
        utmp_logout(slavename, cstat->type == CMD_WSTATUS ? cstat->val : 0);
 
-#ifndef _AIX
-    /* Close pty master. */
-    if (io_fds[SFD_MASTER] != -1) {
-       close(io_fds[SFD_MASTER]);
-       io_fds[SFD_MASTER] = -1;
-    }
-#endif
-
     debug_return;
 }
 
@@ -1421,12 +1405,13 @@ exec_pty(struct command_details *details, struct command_status *cstat)
        if (!sudo_term_copy(io_fds[SFD_USERTTY], io_fds[SFD_SLAVE])) {
             sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_ERRNO,
                 "%s: unable to copy terminal settings to pty", __func__);
-       }
-
-       /* Start out in raw mode unless part of a pipeline or backgrounded. */
-       if (!pipeline && !ISSET(details->flags, CD_EXEC_BG)) {
-           if (sudo_term_raw(io_fds[SFD_USERTTY], 0))
-               ttymode = TERM_RAW;
+           foreground = false;
+       } else {
+           /* Start in raw mode unless part of a pipeline or backgrounded. */
+           if (!pipeline && !ISSET(details->flags, CD_EXEC_BG)) {
+               if (sudo_term_raw(io_fds[SFD_USERTTY], 0))
+                   ttymode = TERM_RAW;
+           }
        }
     }
 
@@ -1475,6 +1460,24 @@ exec_pty(struct command_details *details, struct command_status *cstat)
        _exit(1);
     }
 
+    /*
+     * We close the pty slave so only the monitor and command have a
+     * reference to it.  This ensures that we can don't block reading
+     * from the master when the command and monitor have exited.
+     */
+    if (io_fds[SFD_SLAVE] != -1) {
+       close(io_fds[SFD_SLAVE]);
+       io_fds[SFD_SLAVE] = -1;
+    }
+
+    /* Tell the monitor to continue now that the slave is closed. */
+    cstat->type = CMD_SIGNO;
+    cstat->val = 0;
+    while (send(sv[0], cstat, sizeof(*cstat), 0) == -1) {
+       if (errno != EINTR && errno != EAGAIN)
+           sudo_fatal(U_("unable to send message to monitor process"));
+    }
+
     /* Close the other end of the stdin/stdout/stderr pipes and socketpair. */
     if (io_pipe[STDIN_FILENO][0] != -1)
        close(io_pipe[STDIN_FILENO][0]);
@@ -1523,7 +1526,7 @@ exec_pty(struct command_details *details, struct command_status *cstat)
     }
 
     /* Flush any remaining output, free I/O bufs and events, do logout. */
-    pty_close(cstat);
+    pty_finish(cstat);
 
     /* Free things up. */
     free_exec_closure_pty(&ec);