If event loop fails due to ENXIO, remove /dev/tty events and recover.
This fixes an issue on Solaris 11.4 (and probably others) with "sudo reboot" when I/O logging is enabled. Previously, sudo would kill the command if it was still running after the event loop terminated, leaving the system in a half-dead state.
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-License-Identifier: ISC
|
* SPDX-License-Identifier: ISC
|
||||||
*
|
*
|
||||||
* Copyright (c) 2009-2019 Todd C. Miller <Todd.Miller@sudo.ws>
|
* Copyright (c) 2009-2020 Todd C. Miller <Todd.Miller@sudo.ws>
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
@@ -1347,6 +1347,7 @@ exec_pty(struct command_details *details, struct command_status *cstat)
|
|||||||
bool interpose[3] = { false, false, false };
|
bool interpose[3] = { false, false, false };
|
||||||
struct exec_closure_pty ec = { 0 };
|
struct exec_closure_pty ec = { 0 };
|
||||||
struct plugin_container *plugin;
|
struct plugin_container *plugin;
|
||||||
|
int evloop_retries = -1;
|
||||||
sigset_t set, oset;
|
sigset_t set, oset;
|
||||||
struct sigaction sa;
|
struct sigaction sa;
|
||||||
struct stat sb;
|
struct stat sb;
|
||||||
@@ -1623,8 +1624,10 @@ exec_pty(struct command_details *details, struct command_status *cstat)
|
|||||||
/*
|
/*
|
||||||
* In the event loop we pass input from user tty to master
|
* In the event loop we pass input from user tty to master
|
||||||
* and pass output from master to stdout and IO plugin.
|
* and pass output from master to stdout and IO plugin.
|
||||||
|
* Try to recover on ENXIO, it means the tty was revoked.
|
||||||
*/
|
*/
|
||||||
add_io_events(ec.evbase);
|
add_io_events(ec.evbase);
|
||||||
|
do {
|
||||||
if (sudo_ev_dispatch(ec.evbase) == -1)
|
if (sudo_ev_dispatch(ec.evbase) == -1)
|
||||||
sudo_warn(U_("error in event loop"));
|
sudo_warn(U_("error in event loop"));
|
||||||
if (sudo_ev_got_break(ec.evbase)) {
|
if (sudo_ev_got_break(ec.evbase)) {
|
||||||
@@ -1639,7 +1642,20 @@ exec_pty(struct command_details *details, struct command_status *cstat)
|
|||||||
cstat->type = CMD_WSTATUS;
|
cstat->type = CMD_WSTATUS;
|
||||||
cstat->val = W_EXITCODE(1, SIGKILL);
|
cstat->val = W_EXITCODE(1, SIGKILL);
|
||||||
}
|
}
|
||||||
|
} else if (!sudo_ev_got_exit(ec.evbase)) {
|
||||||
|
switch (errno) {
|
||||||
|
case ENXIO:
|
||||||
|
case EIO:
|
||||||
|
case EBADF:
|
||||||
|
/* /dev/tty was revoked, remove tty events and retry (once) */
|
||||||
|
if (evloop_retries == -1 && io_fds[SFD_USERTTY] != -1) {
|
||||||
|
ev_free_by_fd(ec.evbase, io_fds[SFD_USERTTY]);
|
||||||
|
evloop_retries = 1;
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (evloop_retries-- > 0);
|
||||||
|
|
||||||
/* 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_finish(cstat);
|
pty_finish(cstat);
|
||||||
|
Reference in New Issue
Block a user