]> granicus.if.org Git - sudo/commitdiff
Linux select() may return ENOMEM if there is a kernel resource
authorTodd C. Miller <Todd.Miller@courtesan.com>
Tue, 10 Apr 2012 14:18:39 +0000 (10:18 -0400)
committerTodd C. Miller <Todd.Miller@courtesan.com>
Tue, 10 Apr 2012 14:18:39 +0000 (10:18 -0400)
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.

src/exec.c
src/exec_pty.c

index 2851760095b36344548a9f1838e256c9de0c0bac..1aa41ae548b33fec3bc3b38338a12008369d12bc 100644 (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]);
index dd14f8ad58da0182f42052745bd625e56014b660..51733f63a5620c5cb5a22fdc7ccc73a87e1966e8 100644 (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);