diff -up openssh-8.0p1/channels.c.restore-nonblock openssh-8.0p1/channels.c
--- openssh-8.0p1/channels.c.restore-nonblock 2021-04-26 11:31:44.037740711 +0200
+++ openssh-8.0p1/channels.c 2021-04-26 11:43:48.429606396 +0200
@@ -298,32 +298,38 @@ channel_lookup(struct ssh *ssh, int id)
}
/*
- * Register filedescriptors for a channel, used when allocating a channel or
- * when the channel consumer/producer is ready, e.g. shell exec'd
+ * Register a filedescriptor.
*/
static void
-channel_register_fds(struct ssh *ssh, Channel *c, int rfd, int wfd, int efd,
- int extusage, int nonblock, int is_tty)
+channel_register_fd(struct ssh *ssh, int fd, int nonblock)
{
struct ssh_channels *sc = ssh->chanctxt;
/* Update the maximum file descriptor value. */
- sc->channel_max_fd = MAXIMUM(sc->channel_max_fd, rfd);
- sc->channel_max_fd = MAXIMUM(sc->channel_max_fd, wfd);
- sc->channel_max_fd = MAXIMUM(sc->channel_max_fd, efd);
-
- if (rfd != -1)
- fcntl(rfd, F_SETFD, FD_CLOEXEC);
- if (wfd != -1 && wfd != rfd)
- fcntl(wfd, F_SETFD, FD_CLOEXEC);
- if (efd != -1 && efd != rfd && efd != wfd)
- fcntl(efd, F_SETFD, FD_CLOEXEC);
+ sc->channel_max_fd = MAXIMUM(sc->channel_max_fd, fd);
+
+ if (fd != -1)
+ fcntl(fd, F_SETFD, FD_CLOEXEC);
+ /* enable nonblocking mode */
+ if (nonblock && fd != -1 && !isatty(fd))
+ set_nonblock(fd);
+}
+
+/*
+ * Register filedescriptors for a channel, used when allocating a channel or
+ * when the channel consumer/producer is ready, e.g. shell exec'd
+ */
+static void
+channel_register_fds(struct ssh *ssh, Channel *c, int rfd, int wfd, int efd,
+ int extusage, int nonblock, int is_tty)
+{
c->rfd = rfd;
c->wfd = wfd;
c->sock = (rfd == wfd) ? rfd : -1;
c->efd = efd;
c->extended_usage = extusage;
+ c->nonblock = 0;
if ((c->isatty = is_tty) != 0)
debug2("channel %d: rfd %d isatty", c->self, c->rfd);
@@ -332,14 +338,20 @@ channel_register_fds(struct ssh *ssh, Ch
c->wfd_isatty = is_tty || isatty(c->wfd);
#endif
- /* enable nonblocking mode */
- if (nonblock) {
- if (rfd != -1)
- set_nonblock(rfd);
- if (wfd != -1)
- set_nonblock(wfd);
- if (efd != -1)
- set_nonblock(efd);
+ if (rfd != -1) {
+ if ((fcntl(rfd, F_GETFL) & O_NONBLOCK) == 0)
+ c->nonblock |= NEED_RESTORE_STDIN_NONBLOCK;
+ channel_register_fd(ssh, rfd, nonblock);
+ }
+ if (wfd != -1 && wfd != rfd) {
+ if ((fcntl(wfd, F_GETFL) & O_NONBLOCK) == 0)
+ c->nonblock |= NEED_RESTORE_STDOUT_NONBLOCK;
+ channel_register_fd(ssh, wfd, nonblock);
+ }
+ if (efd != -1 && efd != rfd && efd != wfd) {
+ if ((fcntl(efd, F_GETFL) & O_NONBLOCK) == 0)
+ c->nonblock |= NEED_RESTORE_STDERR_NONBLOCK;
+ channel_register_fd(ssh, efd, nonblock);
}
}
@@ -422,11 +434,15 @@ channel_find_maxfd(struct ssh_channels *
}
int
-channel_close_fd(struct ssh *ssh, int *fdp)
+channel_close_fd(struct ssh *ssh, int *fdp, int nonblock)
{
struct ssh_channels *sc = ssh->chanctxt;
int ret = 0, fd = *fdp;
+ /* As the fd is duped, restoring the block mode
+ * affects the original fd */
+ if (nonblock && fd != -1 && !isatty(fd))
+ unset_nonblock(fd);
if (fd != -1) {
ret = close(fd);
*fdp = -1;
@@ -442,13 +458,13 @@ channel_close_fds(struct ssh *ssh, Chann
{
int sock = c->sock, rfd = c->rfd, wfd = c->wfd, efd = c->efd;
- channel_close_fd(ssh, &c->sock);
+ channel_close_fd(ssh, &c->sock, 0);
if (rfd != sock)
- channel_close_fd(ssh, &c->rfd);
+ channel_close_fd(ssh, &c->rfd, c->nonblock & NEED_RESTORE_STDIN_NONBLOCK);
if (wfd != sock && wfd != rfd)
- channel_close_fd(ssh, &c->wfd);
+ channel_close_fd(ssh, &c->wfd, c->nonblock & NEED_RESTORE_STDOUT_NONBLOCK);
if (efd != sock && efd != rfd && efd != wfd)
- channel_close_fd(ssh, &c->efd);
+ channel_close_fd(ssh, &c->efd, c->nonblock & NEED_RESTORE_STDERR_NONBLOCK);
}
static void
@@ -681,7 +697,7 @@ channel_stop_listening(struct ssh *ssh)
case SSH_CHANNEL_X11_LISTENER:
case SSH_CHANNEL_UNIX_LISTENER:
case SSH_CHANNEL_RUNIX_LISTENER:
- channel_close_fd(ssh, &c->sock);
+ channel_close_fd(ssh, &c->sock, 0);
channel_free(ssh, c);
break;
}
@@ -1650,7 +1666,7 @@ channel_post_x11_listener(struct ssh *ss
if (c->single_connection) {
oerrno = errno;
debug2("single_connection: closing X11 listener.");
- channel_close_fd(ssh, &c->sock);
+ channel_close_fd(ssh, &c->sock, 0);
chan_mark_dead(ssh, c);
errno = oerrno;
}
@@ -2087,7 +2103,7 @@ channel_handle_efd_write(struct ssh *ssh
return 1;
if (len <= 0) {
debug2("channel %d: closing write-efd %d", c->self, c->efd);
- channel_close_fd(ssh, &c->efd);
+ channel_close_fd(ssh, &c->efd, c->nonblock & NEED_RESTORE_STDERR_NONBLOCK);
} else {
if ((r = sshbuf_consume(c->extended, len)) != 0) {
fatal("%s: channel %d: consume: %s",
@@ -2119,7 +2135,7 @@ channel_handle_efd_read(struct ssh *ssh,
if (len <= 0) {
debug2("channel %d: closing read-efd %d",
c->self, c->efd);
- channel_close_fd(ssh, &c->efd);
+ channel_close_fd(ssh, &c->efd, c->nonblock & NEED_RESTORE_STDERR_NONBLOCK);
} else {
if (c->extended_usage == CHAN_EXTENDED_IGNORE) {
debug3("channel %d: discard efd",
diff -up openssh-8.0p1/channels.h.restore-nonblock openssh-8.0p1/channels.h
--- openssh-8.0p1/channels.h.restore-nonblock 2021-04-26 11:31:44.038740719 +0200
+++ openssh-8.0p1/channels.h 2021-04-26 11:38:18.151932008 +0200
@@ -180,8 +180,15 @@ struct Channel {
void *mux_ctx;
int mux_pause;
int mux_downstream_id;
+
+ /* whether non-blocking is set to descriptors */
+ int nonblock;
};
+#define NEED_RESTORE_STDIN_NONBLOCK 1
+#define NEED_RESTORE_STDOUT_NONBLOCK 2
+#define NEED_RESTORE_STDERR_NONBLOCK 4
+
#define CHAN_EXTENDED_IGNORE 0
#define CHAN_EXTENDED_READ 1
#define CHAN_EXTENDED_WRITE 2
@@ -258,7 +265,7 @@ void channel_register_filter(struct ssh
void channel_register_status_confirm(struct ssh *, int,
channel_confirm_cb *, channel_confirm_abandon_cb *, void *);
void channel_cancel_cleanup(struct ssh *, int);
-int channel_close_fd(struct ssh *, int *);
+int channel_close_fd(struct ssh *, int *, int);
void channel_send_window_changes(struct ssh *);
/* mux proxy support */
diff -up openssh-8.0p1/nchan.c.restore-nonblock openssh-8.0p1/nchan.c
--- openssh-8.0p1/nchan.c.restore-nonblock 2021-04-26 11:31:44.047740792 +0200
+++ openssh-8.0p1/nchan.c 2021-04-26 11:42:33.636000753 +0200
@@ -387,7 +387,7 @@ chan_shutdown_write(struct ssh *ssh, Cha
strerror(errno));
}
} else {
- if (channel_close_fd(ssh, &c->wfd) < 0) {
+ if (channel_close_fd(ssh, &c->wfd, c->nonblock & NEED_RESTORE_STDOUT_NONBLOCK) < 0) {
logit("channel %d: %s: close() failed for "
"fd %d [i%d o%d]: %.100s",
c->self, __func__, c->wfd, c->istate, c->ostate,
@@ -417,7 +417,7 @@ chan_shutdown_read(struct ssh *ssh, Chan
strerror(errno));
}
} else {
- if (channel_close_fd(ssh, &c->rfd) < 0) {
+ if (channel_close_fd(ssh, &c->rfd, c->nonblock & NEED_RESTORE_STDIN_NONBLOCK) < 0) {
logit("channel %d: %s: close() failed for "
"fd %d [i%d o%d]: %.100s",
c->self, __func__, c->rfd, c->istate, c->ostate,
@@ -437,7 +437,7 @@ chan_shutdown_extended_read(struct ssh *
debug2("channel %d: %s (i%d o%d sock %d wfd %d efd %d [%s])",
c->self, __func__, c->istate, c->ostate, c->sock, c->rfd, c->efd,
channel_format_extended_usage(c));
- if (channel_close_fd(ssh, &c->efd) < 0) {
+ if (channel_close_fd(ssh, &c->efd, c->nonblock & NEED_RESTORE_STDERR_NONBLOCK) < 0) {
logit("channel %d: %s: close() failed for "
"extended fd %d [i%d o%d]: %.100s",
c->self, __func__, c->efd, c->istate, c->ostate,
diff -up openssh-8.0p1/ssh.c.restore-nonblock openssh-8.0p1/ssh.c
--- openssh-8.0p1/ssh.c.restore-nonblock 2021-04-26 11:31:44.047740792 +0200
+++ openssh-8.0p1/ssh.c 2021-04-26 11:39:58.081741180 +0200
@@ -1862,14 +1862,6 @@ ssh_session2_open(struct ssh *ssh)
if (in < 0 || out < 0 || err < 0)
fatal("dup() in/out/err failed");
- /* enable nonblocking unless tty */
- if (!isatty(in))
- set_nonblock(in);
- if (!isatty(out))
- set_nonblock(out);
- if (!isatty(err))
- set_nonblock(err);
-
window = CHAN_SES_WINDOW_DEFAULT;
packetmax = CHAN_SES_PACKET_DEFAULT;
if (tty_flag) {
@@ -1879,7 +1871,7 @@ ssh_session2_open(struct ssh *ssh)
c = channel_new(ssh,
"session", SSH_CHANNEL_OPENING, in, out, err,
window, packetmax, CHAN_EXTENDED_WRITE,
- "client-session", /*nonblock*/0);
+ "client-session", /*nonblock*/1);
debug3("%s: channel_new: %d", __func__, c->self);