Linux select() may return ENOMEM if there is a kernel resource

shortage.  Older Solaris select() may return EIO instead of EBADF
when the tty goes away.  If we get an unhandled select() failure,
kill the child and exit cleanly.
This commit is contained in:
Todd C. Miller
2012-04-10 10:18:39 -04:00
parent 30fee3aade
commit df04ccb207
2 changed files with 14 additions and 8 deletions

View File

@@ -335,13 +335,18 @@ sudo_execute(struct command_details *details, struct command_status *cstat)
nready = select(maxfd + 1, fdsr, fdsw, NULL, NULL);
sudo_debug_printf(SUDO_DEBUG_DEBUG, "select returns %d", nready);
if (nready == -1) {
if (errno == EINTR)
if (errno == EINTR || errno == ENOMEM)
continue;
if (errno == EBADF) {
if (errno == EBADF || errno == EIO) {
/* One of the ttys must have gone away. */
goto do_tty_io;
}
error(1, _("select failed"));
warning(_("select failed"));
sudo_debug_printf(SUDO_DEBUG_ERROR,
"select failure, terminating child");
schedule_signal(SIGKILL);
forward_signals(sv[0]);
break;
}
if (FD_ISSET(sv[0], fdsw)) {
forward_signals(sv[0]);

View File

@@ -1015,9 +1015,10 @@ exec_monitor(struct command_details *details, int backchannel)
if (n <= 0) {
if (n == 0)
goto done;
if (errno == EINTR)
if (errno == EINTR || errno == ENOMEM)
continue;
error(1, "monitor: %s", _("select failed"));
warning("monitor: %s", _("select failed"));
break;
}
if (FD_ISSET(signal_pipe[0], fdsr)) {
@@ -1152,11 +1153,11 @@ flush_output(void)
if (nready <= 0) {
if (nready == 0)
break; /* all I/O flushed */
if (errno == EINTR)
if (errno == EINTR || errno == ENOMEM)
continue;
error(1, _("select failed"));
warning(_("select failed"));
}
if (perform_io(fdsr, fdsw, NULL) != 0)
if (perform_io(fdsr, fdsw, NULL) != 0 || nready == -1)
break;
}
efree(fdsr);