From 4df454310dae96d01d09a05be89dc8c57fd4cef7 Mon Sep 17 00:00:00 2001 From: "Todd C. Miller" Date: Sun, 25 Mar 2018 06:03:19 -0600 Subject: [PATCH] In pty_close() close the slave and remove any events associated with it. Fixes a potential hang when performing the final flush on non-BSD systems. --- src/exec_pty.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/exec_pty.c b/src/exec_pty.c index 710877395..01466db86 100644 --- a/src/exec_pty.c +++ b/src/exec_pty.c @@ -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. */ -- 2.40.0