[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