[openssh-commits] [openssh] 42/87: upstream: make strict KEX errors return an error rather than

git+noreply at mindrot.org git+noreply at mindrot.org
Fri Oct 30 20:21:19 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 f7a2c31dbfc10c2d1111830f6756ff9b3a1318dd
Author: djm at openbsd.org <djm at openbsd.org>
AuthorDate: Fri Oct 30 04:36:21 2026 +0000

    upstream: make strict KEX errors return an error rather than
    
    fatal()ing the process. This avoids ssh-keyscan crashing out when one host of
    many fails strict KEX.
    
    To avoid the risk of continuing past such a failure in ssh or sshd, make
    such failures "poison" the packet code so that future attempts to send
    or receive packets always an error.
    
    Anthropic ANT-2026-TU0DN0EM (poisoning bit by me)
    
    OpenBSD-Commit-ID: 4eed6b3b2960add40227a6dd9d6b4ea2b053772c
---
 kex.c    | 12 +++++++-----
 packet.c | 42 +++++++++++++++++++++++++++++++++++++++++-
 packet.h |  4 +++-
 3 files changed, 51 insertions(+), 7 deletions(-)

diff --git a/kex.c b/kex.c
index 0e87a9f6a..d9959077f 100644
--- a/kex.c
+++ b/kex.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kex.c,v 1.197 2026/10/30 01:16:44 djm Exp $ */
+/* $OpenBSD: kex.c,v 1.198 2026/10/30 04:36:21 djm Exp $ */
 /*
  * Copyright (c) 2000, 2001 Markus Friedl.  All rights reserved.
  *
@@ -235,7 +235,7 @@ kex_protocol_error(int type, uint32_t seq, struct ssh *ssh)
 
 	/* If in strict mode, any unexpected message is an error */
 	if ((ssh->kex->flags & KEX_INITIAL) && ssh->kex->kex_strict) {
-		ssh_packet_disconnect(ssh, "strict KEX violation: "
+		return sshpkt_protocol_error(ssh, "strict KEX violation: "
 		    "unexpected packet type %u (seqnr %u)", type, seq);
 	}
 	error_f("type %u seq %u", type, seq);
@@ -660,7 +660,7 @@ kex_input_kexinit(int type, uint32_t seq, struct ssh *ssh)
 	free(kex->name);
 	kex->name = NULL;
 	if ((kex->flags & KEX_INIT_RECVD) != 0) {
-		ssh_packet_disconnect(ssh,
+		return sshpkt_protocol_error(ssh,
 		    "multiple KEXINIT received from peer");
 	}
 	kex->flags |= KEX_INIT_RECVD;
@@ -1004,10 +1004,12 @@ kex_choose_conf(struct ssh *ssh, uint32_t seq)
 		}
 		if (kex->kex_strict) {
 			debug3_f("will use strict KEX ordering");
-			if (seq != 0)
-				ssh_packet_disconnect(ssh,
+			if (seq != 0) {
+				r = sshpkt_protocol_error(ssh,
 				    "strict KEX violation: "
 				    "KEXINIT was not the first packet");
+				goto out;
+			}
 		}
 	}
 
diff --git a/packet.c b/packet.c
index d63c579de..462df2847 100644
--- a/packet.c
+++ b/packet.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: packet.c,v 1.346 2026/09/22 22:51:43 job Exp $ */
+/* $OpenBSD: packet.c,v 1.347 2026/10/30 04:36:21 djm Exp $ */
 /*
  * Author: Tatu Ylonen <ylo at cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo at cs.hut.fi>, Espoo, Finland
@@ -224,6 +224,9 @@ struct session_state {
 	/* Nagle disabled on socket */
 	int nodelay_set;
 
+	/* Set to permanently poison this connection instance */
+	int poisoned;
+
 	/* Hook for fuzzing inbound packets */
 	ssh_packet_hook_fn *hook_in;
 	void *hook_in_ctx;
@@ -1501,6 +1504,9 @@ ssh_packet_read_seqnr(struct ssh *ssh, u_char *typep, uint32_t *seqnr_p)
 
 	DBG(debug("packet_read()"));
 
+	if (state->poisoned)
+		return SSH_ERR_PROTOCOL_ERROR;
+
 	/*
 	 * Since we are blocking, ensure that all written packets have
 	 * been sent.
@@ -1592,6 +1598,8 @@ ssh_packet_read_poll2_mux(struct ssh *ssh, u_char *typep, uint32_t *seqnr_p)
 
 	if (ssh->kex)
 		return SSH_ERR_INTERNAL_ERROR;
+	if (state->poisoned)
+		return SSH_ERR_PROTOCOL_ERROR;
 	*typep = SSH_MSG_NONE;
 	cp = sshbuf_ptr(state->input);
 	if (state->packlen == 0) {
@@ -1634,6 +1642,8 @@ ssh_packet_read_poll2(struct ssh *ssh, u_char *typep, uint32_t *seqnr_p)
 
 	if (state->mux)
 		return ssh_packet_read_poll2_mux(ssh, typep, seqnr_p);
+	if (state->poisoned)
+		return SSH_ERR_PROTOCOL_ERROR;
 
 	*typep = SSH_MSG_NONE;
 
@@ -2937,6 +2947,8 @@ sshpkt_msg_ignore(struct ssh *ssh, u_int nbytes)
 int
 sshpkt_send(struct ssh *ssh)
 {
+	if (ssh->state && ssh->state->poisoned)
+		return SSH_ERR_PROTOCOL_ERROR;
 	if (ssh->state && ssh->state->mux)
 		return ssh_packet_send_mux(ssh);
 	return ssh_packet_send2(ssh);
@@ -2963,6 +2975,34 @@ sshpkt_disconnect(struct ssh *ssh, const char *fmt,...)
 	return 0;
 }
 
+/*
+ * Logs a protocol violation by the peer, sends a disconnect packet and
+ * returns SSH_ERR_PROTOCOL_ERROR for the caller to propagate.
+ * This does not terminate the connection, but does "poison" the packet
+ * code so further attempts to read/write will fail with the same error.
+ */
+int
+sshpkt_protocol_error(struct ssh *ssh, const char *fmt,...)
+{
+	char buf[1024], remote_id[512];
+	va_list args;
+	int r;
+
+	sshpkt_fmt_connection_id(ssh, remote_id, sizeof(remote_id));
+	va_start(args, fmt);
+	vsnprintf(buf, sizeof(buf), fmt, args);
+	va_end(args);
+
+	logit("Disconnecting %s: %.100s", remote_id, buf);
+	if ((r = sshpkt_disconnect(ssh, "%s", buf)) != 0 ||
+	    (r = ssh_packet_write_wait(ssh)) != 0)
+		return r;
+	if (ssh->state == NULL)
+		cleanup_exit(255); /* Can't poison? then exit */
+	ssh->state->poisoned = 1;
+	return SSH_ERR_PROTOCOL_ERROR;
+}
+
 /* roundup current message to pad bytes */
 int
 sshpkt_add_padding(struct ssh *ssh, u_char pad)
diff --git a/packet.h b/packet.h
index ecab22a2d..35a5f8a6e 100644
--- a/packet.h
+++ b/packet.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: packet.h,v 1.108 2026/09/22 00:24:47 dtucker Exp $ */
+/* $OpenBSD: packet.h,v 1.109 2026/10/30 04:36:21 djm Exp $ */
 
 /*
  * Author: Tatu Ylonen <ylo at cs.hut.fi>
@@ -174,6 +174,8 @@ int	sshpkt_start(struct ssh *ssh, u_char type);
 int	sshpkt_send(struct ssh *ssh);
 int     sshpkt_disconnect(struct ssh *, const char *fmt, ...)
 	    __attribute__((format(printf, 2, 3)));
+int     sshpkt_protocol_error(struct ssh *, const char *fmt, ...)
+	    __attribute__((format(printf, 2, 3)));
 int	sshpkt_add_padding(struct ssh *, u_char);
 void	sshpkt_fatal(struct ssh *ssh, int r, const char *fmt, ...)
 	    __attribute__((format(printf, 3, 4)))

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


More information about the openssh-commits mailing list