[openssh-commits] [openssh] 13/87: upstream: correct timeout accounting for ConnectTimeout and

git+noreply at mindrot.org git+noreply at mindrot.org
Fri Oct 30 20:20:50 AEDT 2026


This is an automated email from the git hooks/post-receive script.

djm pushed a commit to branch master
in repository openssh.

commit 287415219119341d039793052336b1d63ce15a0a
Author: djm at openbsd.org <djm at openbsd.org>
AuthorDate: Fri Oct 30 01:16:44 2026 +0000

    upstream: correct timeout accounting for ConnectTimeout and
    
    banner exchange that was broken in openssh-9.5, which caused the timeout to
    be erroneously reset between successful reads.
    
    Anthropic ANT-2026-2UMTJC7S
    
    OpenBSD-Commit-ID: 7bc429b079b89ef82f5902ae40e39bc66debb369
---
 kex.c  | 17 +++++++++++++++--
 misc.c | 27 +++++++++++++++++++++------
 2 files changed, 36 insertions(+), 8 deletions(-)

diff --git a/kex.c b/kex.c
index d3015e8af..0e87a9f6a 100644
--- a/kex.c
+++ b/kex.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kex.c,v 1.196 2026/09/22 00:24:47 dtucker Exp $ */
+/* $OpenBSD: kex.c,v 1.197 2026/10/30 01:16:44 djm Exp $ */
 /*
  * Copyright (c) 2000, 2001 Markus Friedl.  All rights reserved.
  *
@@ -1279,6 +1279,8 @@ kex_exchange_identification(struct ssh *ssh, int timeout_ms,
     const char *version_addendum)
 {
 	int remote_major, remote_minor, mismatch, oerrno = 0;
+	int have_timeout = timeout_ms > 0;
+	struct timespec now, remain, deadline;
 	size_t len, n;
 	int r, expect_nl;
 	u_char c;
@@ -1289,6 +1291,13 @@ kex_exchange_identification(struct ssh *ssh, int timeout_ms,
 	char *our_version_string = NULL, *peer_version_string = NULL;
 	char *cp, *remote_version = NULL;
 
+	/* The timeout applies to the whole exchange, not to each read */
+	if (have_timeout) {
+		monotime_ts(&now);
+		ms_to_timespec(&remain, timeout_ms);
+		timespecadd(&now, &remain, &deadline);
+	}
+
 	/* Prepare and send our banner */
 	sshbuf_reset(our_version);
 	if (version_addendum != NULL && *version_addendum == '\0')
@@ -1336,7 +1345,11 @@ kex_exchange_identification(struct ssh *ssh, int timeout_ms,
 		sshbuf_reset(peer_version);
 		expect_nl = 0;
 		for (;;) {
-			if (timeout_ms > 0) {
+			if (have_timeout) {
+				ptimeout_init(&remain);
+				ptimeout_deadline_monotime_tsp(&remain,
+				    &deadline);
+				timeout_ms = ptimeout_get_ms(&remain);
 				r = waitrfd(ssh_packet_get_connection_in(ssh),
 				    &timeout_ms, NULL);
 				if (r == -1 && errno == ETIMEDOUT) {
diff --git a/misc.c b/misc.c
index d49c7100a..bc83e39fc 100644
--- a/misc.c
+++ b/misc.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: misc.c,v 1.221 2026/09/16 17:31:27 dtucker Exp $ */
+/* $OpenBSD: misc.c,v 1.222 2026/10/30 01:16:44 djm Exp $ */
 /*
  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
  * Copyright (c) 2005-2020 Damien Miller.  All rights reserved.
@@ -374,7 +374,7 @@ static int
 waitfd(int fd, int *timeoutp, short events, volatile sig_atomic_t *stop)
 {
 	struct pollfd pfd;
-	struct timespec timeout;
+	struct timespec timeout, now, deadline;
 	int oerrno, r;
 	sigset_t nsigset, osigset;
 
@@ -382,12 +382,18 @@ waitfd(int fd, int *timeoutp, short events, volatile sig_atomic_t *stop)
 		timeoutp = NULL;
 	pfd.fd = fd;
 	pfd.events = events;
-	ptimeout_init(&timeout);
-	if (timeoutp != NULL)
-		ptimeout_deadline_ms(&timeout, *timeoutp);
+	if (timeoutp != NULL) {
+		/* Turn the relative timeout into an absolute deadline */
+		monotime_ts(&now);
+		ms_to_timespec(&timeout, *timeoutp);
+		timespecadd(&now, &timeout, &deadline);
+	}
 	if (stop != NULL)
 		sigfillset(&nsigset);
 	for (; timeoutp == NULL || *timeoutp >= 0;) {
+		ptimeout_init(&timeout);
+		if (timeoutp != NULL)
+			ptimeout_deadline_monotime_tsp(&timeout, &deadline);
 		if (stop != NULL) {
 			sigprocmask(SIG_BLOCK, &nsigset, &osigset);
 			if (*stop) {
@@ -401,8 +407,17 @@ waitfd(int fd, int *timeoutp, short events, volatile sig_atomic_t *stop)
 		oerrno = errno;
 		if (stop != NULL)
 			sigprocmask(SIG_SETMASK, &osigset, NULL);
-		if (timeoutp)
+		if (timeoutp != NULL) {
+			ptimeout_init(&timeout);
+			ptimeout_deadline_monotime_tsp(&timeout, &deadline);
 			*timeoutp = ptimeout_get_ms(&timeout);
+			/*
+			 * Callers treat a timeout <= 0 as "no timeout", so
+			 * never report that none remains when fd is ready.
+			 */
+			if (r > 0 && *timeoutp == 0)
+				*timeoutp = 1;
+		}
 		errno = oerrno;
 		if (r > 0)
 			return 0;

-- 
To stop receiving notification emails like this one, please contact
djm at mindrot.org.


More information about the openssh-commits mailing list