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.
This commit is contained in:
Todd C. Miller
2018-03-25 06:03:19 -06:00
parent 6da40a7b5b
commit 4df454310d

View File

@@ -748,12 +748,19 @@ io_buf_new(int rfd, int wfd,
} }
static void static void
pty_close(struct command_status *cstat) pty_close(struct sudo_event_base *evbase, struct command_status *cstat)
{ {
struct io_buffer *iob; struct io_buffer *iob;
int n; int n;
debug_decl(pty_close, SUDO_DEBUG_EXEC); 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). */ /* Flush any remaining output (the plugin already got it). */
if (io_fds[SFD_USERTTY] != -1) { if (io_fds[SFD_USERTTY] != -1) {
n = fcntl(io_fds[SFD_USERTTY], F_GETFL, 0); n = fcntl(io_fds[SFD_USERTTY], F_GETFL, 0);
@@ -781,6 +788,11 @@ pty_close(struct command_status *cstat)
/* Update utmp */ /* Update utmp */
if (utmp_user != NULL) if (utmp_user != NULL)
utmp_logout(slavename, cstat->type == CMD_WSTATUS ? cstat->val : 0); 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; 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. */ /* Flush any remaining output, free I/O bufs and events, do logout. */
pty_close(cstat); pty_close(ec.evbase, cstat);
/* Free things up. */ /* Free things up. */
free_exec_closure_pty(&ec); 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); (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); (void) sudo_ev_dispatch(evbase);
/* We should now have flushed all write buffers. */ /* We should now have flushed all write buffers. */