Dmitry Belyavskiy c3e6e4
diff -up openssh-8.6p1/channels.c.restore-nonblock openssh-8.6p1/channels.c
Dmitry Belyavskiy c3e6e4
--- openssh-8.6p1/channels.c.restore-nonblock	2021-05-10 10:55:46.981156096 +0200
Dmitry Belyavskiy c3e6e4
+++ openssh-8.6p1/channels.c	2021-05-10 11:05:14.674641053 +0200
Dmitry Belyavskiy c3e6e4
@@ -298,32 +298,38 @@ channel_lookup(struct ssh *ssh, int id)
Dmitry Belyavskiy c3e6e4
 }
Dmitry Belyavskiy c3e6e4
 
Dmitry Belyavskiy c3e6e4
 /*
Dmitry Belyavskiy c3e6e4
- * Register filedescriptors for a channel, used when allocating a channel or
Dmitry Belyavskiy c3e6e4
- * when the channel consumer/producer is ready, e.g. shell exec'd
Dmitry Belyavskiy c3e6e4
+ * Register a filedescriptor.
Dmitry Belyavskiy c3e6e4
  */
Dmitry Belyavskiy c3e6e4
 static void
Dmitry Belyavskiy c3e6e4
-channel_register_fds(struct ssh *ssh, Channel *c, int rfd, int wfd, int efd,
Dmitry Belyavskiy c3e6e4
-    int extusage, int nonblock, int is_tty)
Dmitry Belyavskiy c3e6e4
+channel_register_fd(struct ssh *ssh, int fd, int nonblock)
Dmitry Belyavskiy c3e6e4
 {
Dmitry Belyavskiy c3e6e4
 	struct ssh_channels *sc = ssh->chanctxt;
Dmitry Belyavskiy c3e6e4
 
Dmitry Belyavskiy c3e6e4
 	/* Update the maximum file descriptor value. */
Dmitry Belyavskiy c3e6e4
-	sc->channel_max_fd = MAXIMUM(sc->channel_max_fd, rfd);
Dmitry Belyavskiy c3e6e4
-	sc->channel_max_fd = MAXIMUM(sc->channel_max_fd, wfd);
Dmitry Belyavskiy c3e6e4
-	sc->channel_max_fd = MAXIMUM(sc->channel_max_fd, efd);
Dmitry Belyavskiy c3e6e4
-
Dmitry Belyavskiy c3e6e4
-	if (rfd != -1)
Dmitry Belyavskiy c3e6e4
-		fcntl(rfd, F_SETFD, FD_CLOEXEC);
Dmitry Belyavskiy c3e6e4
-	if (wfd != -1 && wfd != rfd)
Dmitry Belyavskiy c3e6e4
-		fcntl(wfd, F_SETFD, FD_CLOEXEC);
Dmitry Belyavskiy c3e6e4
-	if (efd != -1 && efd != rfd && efd != wfd)
Dmitry Belyavskiy c3e6e4
-		fcntl(efd, F_SETFD, FD_CLOEXEC);
Dmitry Belyavskiy c3e6e4
+	sc->channel_max_fd = MAXIMUM(sc->channel_max_fd, fd);
Dmitry Belyavskiy c3e6e4
+
Dmitry Belyavskiy c3e6e4
+	if (fd != -1)
Dmitry Belyavskiy c3e6e4
+		fcntl(fd, F_SETFD, FD_CLOEXEC);
Dmitry Belyavskiy c3e6e4
 
Dmitry Belyavskiy c3e6e4
+	/* enable nonblocking mode */
Dmitry Belyavskiy c3e6e4
+	if (nonblock && fd != -1 && !isatty(fd))
Dmitry Belyavskiy c3e6e4
+		set_nonblock(fd);
Dmitry Belyavskiy c3e6e4
+}
Dmitry Belyavskiy c3e6e4
+
Dmitry Belyavskiy c3e6e4
+/*
Dmitry Belyavskiy c3e6e4
+ * Register filedescriptors for a channel, used when allocating a channel or
Dmitry Belyavskiy c3e6e4
+ * when the channel consumer/producer is ready, e.g. shell exec'd
Dmitry Belyavskiy c3e6e4
+ */
Dmitry Belyavskiy c3e6e4
+static void
Dmitry Belyavskiy c3e6e4
+channel_register_fds(struct ssh *ssh, Channel *c, int rfd, int wfd, int efd,
Dmitry Belyavskiy c3e6e4
+    int extusage, int nonblock, int is_tty)
Dmitry Belyavskiy c3e6e4
+{
Dmitry Belyavskiy c3e6e4
 	c->rfd = rfd;
Dmitry Belyavskiy c3e6e4
 	c->wfd = wfd;
Dmitry Belyavskiy c3e6e4
 	c->sock = (rfd == wfd) ? rfd : -1;
Dmitry Belyavskiy c3e6e4
 	c->efd = efd;
Dmitry Belyavskiy c3e6e4
 	c->extended_usage = extusage;
Dmitry Belyavskiy c3e6e4
+	c->nonblock = 0;
Dmitry Belyavskiy c3e6e4
 
Dmitry Belyavskiy c3e6e4
 	if ((c->isatty = is_tty) != 0)
Dmitry Belyavskiy c3e6e4
 		debug2("channel %d: rfd %d isatty", c->self, c->rfd);
Dmitry Belyavskiy c3e6e4
@@ -332,14 +338,20 @@ channel_register_fds(struct ssh *ssh, Ch
Dmitry Belyavskiy c3e6e4
 	c->wfd_isatty = is_tty || isatty(c->wfd);
Dmitry Belyavskiy c3e6e4
 #endif
Dmitry Belyavskiy c3e6e4
 
Dmitry Belyavskiy c3e6e4
-	/* enable nonblocking mode */
Dmitry Belyavskiy c3e6e4
-	if (nonblock) {
Dmitry Belyavskiy c3e6e4
-		if (rfd != -1)
Dmitry Belyavskiy c3e6e4
-			set_nonblock(rfd);
Dmitry Belyavskiy c3e6e4
-		if (wfd != -1)
Dmitry Belyavskiy c3e6e4
-			set_nonblock(wfd);
Dmitry Belyavskiy c3e6e4
-		if (efd != -1)
Dmitry Belyavskiy c3e6e4
-			set_nonblock(efd);
Dmitry Belyavskiy c3e6e4
+	if (rfd != -1) {
Dmitry Belyavskiy c3e6e4
+		if ((fcntl(rfd, F_GETFL) & O_NONBLOCK) == 0)
Dmitry Belyavskiy c3e6e4
+			c->nonblock |= NEED_RESTORE_STDIN_NONBLOCK;
Dmitry Belyavskiy c3e6e4
+		channel_register_fd(ssh, rfd, nonblock);
Dmitry Belyavskiy c3e6e4
+	}
Dmitry Belyavskiy c3e6e4
+	if (wfd != -1 && wfd != rfd) {
Dmitry Belyavskiy c3e6e4
+		if ((fcntl(wfd, F_GETFL) & O_NONBLOCK) == 0)
Dmitry Belyavskiy c3e6e4
+			c->nonblock |= NEED_RESTORE_STDOUT_NONBLOCK;
Dmitry Belyavskiy c3e6e4
+		channel_register_fd(ssh, wfd, nonblock);
Dmitry Belyavskiy c3e6e4
+	}
Dmitry Belyavskiy c3e6e4
+	if (efd != -1 && efd != rfd && efd != wfd) {
Dmitry Belyavskiy c3e6e4
+		if ((fcntl(efd, F_GETFL) & O_NONBLOCK) == 0)
Dmitry Belyavskiy c3e6e4
+			c->nonblock |= NEED_RESTORE_STDERR_NONBLOCK;
Dmitry Belyavskiy c3e6e4
+		channel_register_fd(ssh, efd, nonblock);
Dmitry Belyavskiy c3e6e4
 	}
Dmitry Belyavskiy c3e6e4
 }
Dmitry Belyavskiy c3e6e4
 
Dmitry Belyavskiy c3e6e4
@@ -422,11 +434,15 @@ channel_find_maxfd(struct ssh_channels *
Dmitry Belyavskiy c3e6e4
 }
Dmitry Belyavskiy c3e6e4
 
Dmitry Belyavskiy c3e6e4
 int
Dmitry Belyavskiy c3e6e4
-channel_close_fd(struct ssh *ssh, int *fdp)
Dmitry Belyavskiy c3e6e4
+channel_close_fd(struct ssh *ssh, int *fdp, int nonblock)
Dmitry Belyavskiy c3e6e4
 {
Dmitry Belyavskiy c3e6e4
 	struct ssh_channels *sc = ssh->chanctxt;
Dmitry Belyavskiy c3e6e4
 	int ret = 0, fd = *fdp;
Dmitry Belyavskiy c3e6e4
 
Dmitry Belyavskiy c3e6e4
+	/* As the fd is duped, restoring the block mode
Dmitry Belyavskiy c3e6e4
+	 * affects the original fd */
Dmitry Belyavskiy c3e6e4
+	if (nonblock && fd != -1 && !isatty(fd))
Dmitry Belyavskiy c3e6e4
+		unset_nonblock(fd);
Dmitry Belyavskiy c3e6e4
 	if (fd != -1) {
Dmitry Belyavskiy c3e6e4
 		ret = close(fd);
Dmitry Belyavskiy c3e6e4
 		*fdp = -1;
Dmitry Belyavskiy c3e6e4
@@ -442,13 +458,13 @@ channel_close_fds(struct ssh *ssh, Chann
Dmitry Belyavskiy c3e6e4
 {
Dmitry Belyavskiy c3e6e4
 	int sock = c->sock, rfd = c->rfd, wfd = c->wfd, efd = c->efd;
Dmitry Belyavskiy c3e6e4
 
Dmitry Belyavskiy c3e6e4
-	channel_close_fd(ssh, &c->sock);
Dmitry Belyavskiy c3e6e4
+	channel_close_fd(ssh, &c->sock, 0);
Dmitry Belyavskiy c3e6e4
 	if (rfd != sock)
Dmitry Belyavskiy c3e6e4
-		channel_close_fd(ssh, &c->rfd);
Dmitry Belyavskiy c3e6e4
+		channel_close_fd(ssh, &c->rfd, c->nonblock & NEED_RESTORE_STDIN_NONBLOCK);
Dmitry Belyavskiy c3e6e4
 	if (wfd != sock && wfd != rfd)
Dmitry Belyavskiy c3e6e4
-		channel_close_fd(ssh, &c->wfd);
Dmitry Belyavskiy c3e6e4
+		channel_close_fd(ssh, &c->wfd, c->nonblock & NEED_RESTORE_STDOUT_NONBLOCK);
Dmitry Belyavskiy c3e6e4
 	if (efd != sock && efd != rfd && efd != wfd)
Dmitry Belyavskiy c3e6e4
-		channel_close_fd(ssh, &c->efd);
Dmitry Belyavskiy c3e6e4
+		channel_close_fd(ssh, &c->efd, c->nonblock & NEED_RESTORE_STDERR_NONBLOCK);
Dmitry Belyavskiy c3e6e4
 }
Dmitry Belyavskiy c3e6e4
 
Dmitry Belyavskiy c3e6e4
 static void
Dmitry Belyavskiy c3e6e4
@@ -702,7 +718,7 @@ channel_stop_listening(struct ssh *ssh)
Dmitry Belyavskiy c3e6e4
 			case SSH_CHANNEL_X11_LISTENER:
Dmitry Belyavskiy c3e6e4
 			case SSH_CHANNEL_UNIX_LISTENER:
Dmitry Belyavskiy c3e6e4
 			case SSH_CHANNEL_RUNIX_LISTENER:
Dmitry Belyavskiy c3e6e4
-				channel_close_fd(ssh, &c->sock);
Dmitry Belyavskiy c3e6e4
+				channel_close_fd(ssh, &c->sock, 0);
Dmitry Belyavskiy c3e6e4
 				channel_free(ssh, c);
Dmitry Belyavskiy c3e6e4
 				break;
Dmitry Belyavskiy c3e6e4
 			}
Dmitry Belyavskiy c3e6e4
@@ -1649,7 +1665,7 @@ channel_post_x11_listener(struct ssh *ss
Dmitry Belyavskiy c3e6e4
 	if (c->single_connection) {
Dmitry Belyavskiy c3e6e4
 		oerrno = errno;
Dmitry Belyavskiy c3e6e4
 		debug2("single_connection: closing X11 listener.");
Dmitry Belyavskiy c3e6e4
-		channel_close_fd(ssh, &c->sock);
Dmitry Belyavskiy c3e6e4
+		channel_close_fd(ssh, &c->sock, 0);
Dmitry Belyavskiy c3e6e4
 		chan_mark_dead(ssh, c);
Dmitry Belyavskiy c3e6e4
 		errno = oerrno;
Dmitry Belyavskiy c3e6e4
 	}
Dmitry Belyavskiy c3e6e4
@@ -2058,7 +2074,7 @@ channel_handle_efd_write(struct ssh *ssh
Dmitry Belyavskiy c3e6e4
 		return 1;
Dmitry Belyavskiy c3e6e4
 	if (len <= 0) {
Dmitry Belyavskiy c3e6e4
 		debug2("channel %d: closing write-efd %d", c->self, c->efd);
Dmitry Belyavskiy c3e6e4
-		channel_close_fd(ssh, &c->efd);
Dmitry Belyavskiy c3e6e4
+		channel_close_fd(ssh, &c->efd, c->nonblock & NEED_RESTORE_STDERR_NONBLOCK);
Dmitry Belyavskiy c3e6e4
 	} else {
Dmitry Belyavskiy c3e6e4
 		if ((r = sshbuf_consume(c->extended, len)) != 0)
Dmitry Belyavskiy c3e6e4
 			fatal_fr(r, "channel %i: consume", c->self);
Dmitry Belyavskiy c3e6e4
@@ -2087,7 +2103,7 @@ channel_handle_efd_read(struct ssh *ssh,
Dmitry Belyavskiy c3e6e4
 		return 1;
Dmitry Belyavskiy c3e6e4
 	if (len <= 0) {
Dmitry Belyavskiy c3e6e4
 		debug2("channel %d: closing read-efd %d", c->self, c->efd);
Dmitry Belyavskiy c3e6e4
-		channel_close_fd(ssh, &c->efd);
Dmitry Belyavskiy c3e6e4
+		channel_close_fd(ssh, &c->efd, c->nonblock & NEED_RESTORE_STDERR_NONBLOCK);
Dmitry Belyavskiy c3e6e4
 	} else if (c->extended_usage == CHAN_EXTENDED_IGNORE)
Dmitry Belyavskiy c3e6e4
 		debug3("channel %d: discard efd", c->self);
Dmitry Belyavskiy c3e6e4
 	else if ((r = sshbuf_put(c->extended, buf, len)) != 0)
Dmitry Belyavskiy c3e6e4
diff -up openssh-8.6p1/channels.h.restore-nonblock openssh-8.6p1/channels.h
Dmitry Belyavskiy c3e6e4
--- openssh-8.6p1/channels.h.restore-nonblock	2021-05-10 10:55:46.942155788 +0200
Dmitry Belyavskiy c3e6e4
+++ openssh-8.6p1/channels.h	2021-05-10 11:01:41.123953937 +0200
Dmitry Belyavskiy c3e6e4
@@ -188,8 +188,15 @@ struct Channel {
Dmitry Belyavskiy c3e6e4
 	void			*mux_ctx;
Dmitry Belyavskiy c3e6e4
 	int			mux_pause;
Dmitry Belyavskiy c3e6e4
 	int			mux_downstream_id;
Dmitry Belyavskiy c3e6e4
+
Dmitry Belyavskiy c3e6e4
+	/* whether non-blocking is set to descriptors */
Dmitry Belyavskiy c3e6e4
+	int 			nonblock;
Dmitry Belyavskiy c3e6e4
 };
Dmitry Belyavskiy c3e6e4
 
Dmitry Belyavskiy c3e6e4
+#define NEED_RESTORE_STDIN_NONBLOCK  1
Dmitry Belyavskiy c3e6e4
+#define NEED_RESTORE_STDOUT_NONBLOCK 2
Dmitry Belyavskiy c3e6e4
+#define NEED_RESTORE_STDERR_NONBLOCK 4
Dmitry Belyavskiy c3e6e4
+
Dmitry Belyavskiy c3e6e4
 #define CHAN_EXTENDED_IGNORE		0
Dmitry Belyavskiy c3e6e4
 #define CHAN_EXTENDED_READ		1
Dmitry Belyavskiy c3e6e4
 #define CHAN_EXTENDED_WRITE		2
Dmitry Belyavskiy c3e6e4
@@ -266,7 +273,7 @@ void	 channel_register_filter(struct ssh
Dmitry Belyavskiy c3e6e4
 void	 channel_register_status_confirm(struct ssh *, int,
Dmitry Belyavskiy c3e6e4
 	    channel_confirm_cb *, channel_confirm_abandon_cb *, void *);
Dmitry Belyavskiy c3e6e4
 void	 channel_cancel_cleanup(struct ssh *, int);
Dmitry Belyavskiy c3e6e4
-int	 channel_close_fd(struct ssh *, int *);
Dmitry Belyavskiy c3e6e4
+int	 channel_close_fd(struct ssh *, int *, int);
Dmitry Belyavskiy c3e6e4
 void	 channel_send_window_changes(struct ssh *);
Dmitry Belyavskiy c3e6e4
 
Dmitry Belyavskiy c3e6e4
 /* mux proxy support */
Dmitry Belyavskiy c3e6e4
diff -up openssh-8.6p1/nchan.c.restore-nonblock openssh-8.6p1/nchan.c
Dmitry Belyavskiy c3e6e4
--- openssh-8.6p1/nchan.c.restore-nonblock	2021-05-10 10:55:46.990156168 +0200
Dmitry Belyavskiy c3e6e4
+++ openssh-8.6p1/nchan.c	2021-05-10 11:03:46.679945863 +0200
Dmitry Belyavskiy c3e6e4
@@ -384,7 +384,7 @@ chan_shutdown_write(struct ssh *ssh, Cha
Dmitry Belyavskiy c3e6e4
 			    c->istate, c->ostate, strerror(errno));
Dmitry Belyavskiy c3e6e4
 		}
Dmitry Belyavskiy c3e6e4
 	} else {
Dmitry Belyavskiy c3e6e4
-		if (channel_close_fd(ssh, &c->wfd) < 0) {
Dmitry Belyavskiy c3e6e4
+		if (channel_close_fd(ssh, &c->wfd, c->nonblock & NEED_RESTORE_STDOUT_NONBLOCK) < 0) {
Dmitry Belyavskiy c3e6e4
 			logit_f("channel %d: close() failed for "
Dmitry Belyavskiy c3e6e4
 			    "fd %d [i%d o%d]: %.100s", c->self, c->wfd,
Dmitry Belyavskiy c3e6e4
 			    c->istate, c->ostate, strerror(errno));
Dmitry Belyavskiy c3e6e4
@@ -412,7 +412,7 @@ chan_shutdown_read(struct ssh *ssh, Chan
Dmitry Belyavskiy c3e6e4
 			    c->istate, c->ostate, strerror(errno));
Dmitry Belyavskiy c3e6e4
 		}
Dmitry Belyavskiy c3e6e4
 	} else {
Dmitry Belyavskiy c3e6e4
-		if (channel_close_fd(ssh, &c->rfd) < 0) {
Dmitry Belyavskiy c3e6e4
+		if (channel_close_fd(ssh, &c->rfd, c->nonblock & NEED_RESTORE_STDIN_NONBLOCK) < 0) {
Dmitry Belyavskiy c3e6e4
 			logit_f("channel %d: close() failed for "
Dmitry Belyavskiy c3e6e4
 			    "fd %d [i%d o%d]: %.100s", c->self, c->rfd,
Dmitry Belyavskiy c3e6e4
 			    c->istate, c->ostate, strerror(errno));
Dmitry Belyavskiy c3e6e4
@@ -431,7 +431,7 @@ chan_shutdown_extended_read(struct ssh *
Dmitry Belyavskiy c3e6e4
 	debug_f("channel %d: (i%d o%d sock %d wfd %d efd %d [%s])",
Dmitry Belyavskiy c3e6e4
 	    c->self, c->istate, c->ostate, c->sock, c->rfd, c->efd,
Dmitry Belyavskiy c3e6e4
 	    channel_format_extended_usage(c));
Dmitry Belyavskiy c3e6e4
-	if (channel_close_fd(ssh, &c->efd) < 0) {
Dmitry Belyavskiy c3e6e4
+	if (channel_close_fd(ssh, &c->efd, c->nonblock & NEED_RESTORE_STDERR_NONBLOCK) < 0) {
Dmitry Belyavskiy c3e6e4
 		logit_f("channel %d: close() failed for "
Dmitry Belyavskiy c3e6e4
 		    "extended fd %d [i%d o%d]: %.100s", c->self, c->efd,
Dmitry Belyavskiy c3e6e4
 		    c->istate, c->ostate, strerror(errno));
Dmitry Belyavskiy c3e6e4
diff -up openssh-8.6p1/ssh.c.restore-nonblock openssh-8.6p1/ssh.c
Dmitry Belyavskiy c3e6e4
--- openssh-8.6p1/ssh.c.restore-nonblock	2021-05-10 10:55:46.991156175 +0200
Dmitry Belyavskiy c3e6e4
+++ openssh-8.6p1/ssh.c	2021-05-10 11:06:28.315222828 +0200
Dmitry Belyavskiy c3e6e4
@@ -2085,14 +2085,6 @@ ssh_session2_open(struct ssh *ssh)
Dmitry Belyavskiy c3e6e4
 	if (in == -1 || out == -1 || err == -1)
Dmitry Belyavskiy c3e6e4
 		fatal("dup() in/out/err failed");
Dmitry Belyavskiy c3e6e4
 
Dmitry Belyavskiy c3e6e4
-	/* enable nonblocking unless tty */
Dmitry Belyavskiy c3e6e4
-	if (!isatty(in))
Dmitry Belyavskiy c3e6e4
-		set_nonblock(in);
Dmitry Belyavskiy c3e6e4
-	if (!isatty(out))
Dmitry Belyavskiy c3e6e4
-		set_nonblock(out);
Dmitry Belyavskiy c3e6e4
-	if (!isatty(err))
Dmitry Belyavskiy c3e6e4
-		set_nonblock(err);
Dmitry Belyavskiy c3e6e4
-
Dmitry Belyavskiy c3e6e4
 	window = CHAN_SES_WINDOW_DEFAULT;
Dmitry Belyavskiy c3e6e4
 	packetmax = CHAN_SES_PACKET_DEFAULT;
Dmitry Belyavskiy c3e6e4
 	if (tty_flag) {
Dmitry Belyavskiy c3e6e4
@@ -2102,7 +2094,7 @@ ssh_session2_open(struct ssh *ssh)
Dmitry Belyavskiy c3e6e4
 	c = channel_new(ssh,
Dmitry Belyavskiy c3e6e4
 	    "session", SSH_CHANNEL_OPENING, in, out, err,
Dmitry Belyavskiy c3e6e4
 	    window, packetmax, CHAN_EXTENDED_WRITE,
Dmitry Belyavskiy c3e6e4
-	    "client-session", /*nonblock*/0);
Dmitry Belyavskiy c3e6e4
+	    "client-session", /*nonblock*/1);
Dmitry Belyavskiy c3e6e4
 
Dmitry Belyavskiy c3e6e4
 	debug3_f("channel_new: %d", c->self);
Dmitry Belyavskiy c3e6e4