git: a4439dc6c872 - stable/13 - ssh: fix OpenSSH 9.4 regression with multiplexed sessions

From: Ed Maste <emaste_at_FreeBSD.org>
Date: Mon, 08 Jan 2024 04:10:22 UTC
The branch stable/13 has been updated by emaste:

URL: https://cgit.FreeBSD.org/src/commit/?id=a4439dc6c87259c0b82ee8ad9d756452abb671fa

commit a4439dc6c87259c0b82ee8ad9d756452abb671fa
Author:     Ed Maste <emaste@FreeBSD.org>
AuthorDate: 2023-08-20 19:16:54 +0000
Commit:     Ed Maste <emaste@FreeBSD.org>
CommitDate: 2024-01-08 00:49:07 +0000

    ssh: fix OpenSSH 9.4 regression with multiplexed sessions
    
    Upstream commit message:
    upstream: fix regression in OpenSSH 9.4 (mux.c r1.99) that caused
    multiplexed sessions to ignore SIGINT under some circumstances.
    Reported by / feedback naddy@, ok dtucker@
    
    OpenBSD-Commit-ID: 4d5c6c894664f50149153fd4764f21f43e7d7e5a
    
    Fixes: 535af610a4fd ("ssh: Update to OpenSSH 9.4p1")
    Obtained from:  OpenSSH 803e22eabd3b
    Sponsored by:   The FreeBSD Foundation
    
    (cherry picked from commit 1b91d634a58c45d7b33dee044034260f747c80d9)
---
 crypto/openssh/kex.c  |  4 ++--
 crypto/openssh/misc.c | 42 ++++++++++++++++++++++++++++++------------
 crypto/openssh/misc.h |  5 +++--
 crypto/openssh/mux.c  |  6 ++++--
 4 files changed, 39 insertions(+), 18 deletions(-)

diff --git a/crypto/openssh/kex.c b/crypto/openssh/kex.c
index 251cff7af530..7c47c84ba5e6 100644
--- a/crypto/openssh/kex.c
+++ b/crypto/openssh/kex.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kex.c,v 1.178 2023/03/12 10:40:39 dtucker Exp $ */
+/* $OpenBSD: kex.c,v 1.179 2023/08/18 01:37:41 djm Exp $ */
 /*
  * Copyright (c) 2000, 2001 Markus Friedl.  All rights reserved.
  *
@@ -1362,7 +1362,7 @@ kex_exchange_identification(struct ssh *ssh, int timeout_ms,
 		for (;;) {
 			if (timeout_ms > 0) {
 				r = waitrfd(ssh_packet_get_connection_in(ssh),
-				    &timeout_ms);
+				    &timeout_ms, NULL);
 				if (r == -1 && errno == ETIMEDOUT) {
 					send_error(ssh, "Timed out waiting "
 					    "for SSH identification string.");
diff --git a/crypto/openssh/misc.c b/crypto/openssh/misc.c
index 4b87c4090804..956587035517 100644
--- a/crypto/openssh/misc.c
+++ b/crypto/openssh/misc.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: misc.c,v 1.185 2023/08/04 06:32:40 dtucker Exp $ */
+/* $OpenBSD: misc.c,v 1.186 2023/08/18 01:37:41 djm Exp $ */
 /*
  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
  * Copyright (c) 2005-2020 Damien Miller.  All rights reserved.
@@ -313,20 +313,38 @@ set_sock_tos(int fd, int tos)
  * Returns 0 if fd ready or -1 on timeout or error (see errno).
  */
 static int
-waitfd(int fd, int *timeoutp, short events)
+waitfd(int fd, int *timeoutp, short events, volatile sig_atomic_t *stop)
 {
 	struct pollfd pfd;
-	struct timeval t_start;
-	int oerrno, r, have_timeout = (*timeoutp >= 0);
+	struct timespec timeout;
+	int oerrno, r;
+	sigset_t nsigset, osigset;
 
+	if (timeoutp && *timeoutp == -1)
+		timeoutp = NULL;
 	pfd.fd = fd;
 	pfd.events = events;
-	for (; !have_timeout || *timeoutp >= 0;) {
-		monotime_tv(&t_start);
-		r = poll(&pfd, 1, *timeoutp);
+	ptimeout_init(&timeout);
+	if (timeoutp != NULL)
+		ptimeout_deadline_ms(&timeout, *timeoutp);
+	if (stop != NULL)
+		sigfillset(&nsigset);
+	for (; timeoutp == NULL || *timeoutp >= 0;) {
+		if (stop != NULL) {
+			sigprocmask(SIG_BLOCK, &nsigset, &osigset);
+			if (*stop) {
+				sigprocmask(SIG_SETMASK, &osigset, NULL);
+				errno = EINTR;
+				return -1;
+			}
+		}
+		r = ppoll(&pfd, 1, ptimeout_get_tsp(&timeout),
+		    stop != NULL ? &osigset : NULL);
 		oerrno = errno;
-		if (have_timeout)
-			ms_subtract_diff(&t_start, timeoutp);
+		if (stop != NULL)
+			sigprocmask(SIG_SETMASK, &osigset, NULL);
+		if (timeoutp)
+			*timeoutp = ptimeout_get_ms(&timeout);
 		errno = oerrno;
 		if (r > 0)
 			return 0;
@@ -346,8 +364,8 @@ waitfd(int fd, int *timeoutp, short events)
  * Returns 0 if fd ready or -1 on timeout or error (see errno).
  */
 int
-waitrfd(int fd, int *timeoutp) {
-	return waitfd(fd, timeoutp, POLLIN);
+waitrfd(int fd, int *timeoutp, volatile sig_atomic_t *stop) {
+	return waitfd(fd, timeoutp, POLLIN, stop);
 }
 
 /*
@@ -381,7 +399,7 @@ timeout_connect(int sockfd, const struct sockaddr *serv_addr,
 		break;
 	}
 
-	if (waitfd(sockfd, timeoutp, POLLIN | POLLOUT) == -1)
+	if (waitfd(sockfd, timeoutp, POLLIN | POLLOUT, NULL) == -1)
 		return -1;
 
 	/* Completed or failed */
diff --git a/crypto/openssh/misc.h b/crypto/openssh/misc.h
index fd77a7fd7273..f9bdc6eb51bd 100644
--- a/crypto/openssh/misc.h
+++ b/crypto/openssh/misc.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: misc.h,v 1.103 2023/07/19 14:02:27 djm Exp $ */
+/* $OpenBSD: misc.h,v 1.104 2023/08/18 01:37:41 djm Exp $ */
 
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -19,6 +19,7 @@
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <stdio.h>
+#include <signal.h>
 
 /* Data structure for representing a forwarding request. */
 struct Forward {
@@ -57,7 +58,7 @@ char	*get_rdomain(int);
 int	 set_rdomain(int, const char *);
 int	 get_sock_af(int);
 void	 set_sock_tos(int, int);
-int	 waitrfd(int, int *);
+int	 waitrfd(int, int *, volatile sig_atomic_t *);
 int	 timeout_connect(int, const struct sockaddr *, socklen_t, int *);
 int	 a2port(const char *);
 int	 a2tun(const char *, int *);
diff --git a/crypto/openssh/mux.c b/crypto/openssh/mux.c
index 3a0f87674b95..d9d5e7d994ca 100644
--- a/crypto/openssh/mux.c
+++ b/crypto/openssh/mux.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: mux.c,v 1.99 2023/08/04 06:32:40 dtucker Exp $ */
+/* $OpenBSD: mux.c,v 1.100 2023/08/18 01:37:41 djm Exp $ */
 /*
  * Copyright (c) 2002-2008 Damien Miller <djm@openbsd.org>
  *
@@ -1480,7 +1480,9 @@ mux_client_read(int fd, struct sshbuf *b, size_t need, int timeout_ms)
 			case EWOULDBLOCK:
 #endif
 			case EAGAIN:
-				if (waitrfd(fd, &timeout_ms) == -1)
+				if (waitrfd(fd, &timeout_ms,
+				    &muxclient_terminate) == -1 &&
+				    errno != EINTR)
 					return -1;	/* timeout */
 				/* FALLTHROUGH */
 			case EINTR: