]> granicus.if.org Git - sudo/commitdiff
In pty_close() close the slave and remove any events associated
authorTodd C. Miller <Todd.Miller@sudo.ws>
Sun, 25 Mar 2018 12:03:19 +0000 (06:03 -0600)
committerTodd C. Miller <Todd.Miller@sudo.ws>
Sun, 25 Mar 2018 12:03:19 +0000 (06:03 -0600)
with it.  Fixes a potential hang when performing the final flush
on non-BSD systems.

src/exec_pty.c

index 710877395786afe57ac7dc47c7842745d3c90d46..01466db86e2c8bf9d5653942478970ed8c6942a2 100644 (file)
@@ -748,12 +748,19 @@ io_buf_new(int rfd, int wfd,
 }
 
 static void
-pty_close(struct command_status *cstat)
+pty_close(struct sudo_event_base *evbase, struct command_status *cstat)
 {
     struct io_buffer *iob;
     int n;
     debug_decl(pty_close, SUDO_DEBUG_EXEC);
 
+    /* Close the pty slave first so reads from the master don't block. */
+    if (io_fds[SFD_SLAVE] != -1) {
+       ev_free_by_fd(evbase, io_fds[SFD_SLAVE]);
+       close(io_fds[SFD_SLAVE]);
+       io_fds[SFD_SLAVE] = -1;
+    }
+
     /* Flush any remaining output (the plugin already got it). */
     if (io_fds[SFD_USERTTY] != -1) {
        n = fcntl(io_fds[SFD_USERTTY], F_GETFL, 0);
@@ -781,6 +788,11 @@ pty_close(struct command_status *cstat)
     /* Update utmp */
     if (utmp_user != NULL)
        utmp_logout(slavename, cstat->type == CMD_WSTATUS ? cstat->val : 0);
+
+    /* Close pty master. */
+    if (io_fds[SFD_MASTER] != -1)
+       close(io_fds[SFD_MASTER]);
+
     debug_return;
 }
 
@@ -1481,7 +1493,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_close(ec.evbase, cstat);
 
     /* Free things up. */
     free_exec_closure_pty(&ec);
@@ -1581,6 +1593,8 @@ del_io_events(bool nonblocking)
            }
        }
     }
+    sudo_debug_printf(SUDO_DEBUG_INFO,
+       "%s: flushing remaining I/O buffers (nonblocking)", __func__);
     (void) sudo_ev_loop(evbase, SUDO_EVLOOP_NONBLOCK);
 
     /*
@@ -1606,6 +1620,8 @@ del_io_events(bool nonblocking)
                }
            }
        }
+       sudo_debug_printf(SUDO_DEBUG_INFO,
+           "%s: flushing remaining write buffers (blocking)", __func__);
        (void) sudo_ev_dispatch(evbase);
      
        /* We should now have flushed all write buffers. */