Skip to content

Commit bb781f0

Browse files
committed
upstream: Move banner exchange to sshd-auth process
Previously, exchange of the initial SSH- banners was performed by the privileged sshd-session monitor. This moves it to the unprivileged sshd-auth subprocess, removing ~200 LoC from the monitor's privileged attack surface. The monitor gains a new "setcompat" RPC to allow sshd-auth to inform it of bug compat flags picked up from the client's banner. feedback dtucker@, ok markus@ deraadt@ OpenBSD-Commit-ID: d767eb1183630d754d521d9f0d84a6c72fbe7fc8
1 parent b50b881 commit bb781f0

File tree

8 files changed

+63
-17
lines changed

8 files changed

+63
-17
lines changed

compat.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* $OpenBSD: compat.c,v 1.127 2026/02/14 00:18:34 jsg Exp $ */
1+
/* $OpenBSD: compat.c,v 1.128 2026/03/02 02:40:15 djm Exp $ */
22
/*
33
* Copyright (c) 1999, 2000, 2001, 2002 Markus Friedl. All rights reserved.
44
*
@@ -27,6 +27,7 @@
2727

2828
#include <sys/types.h>
2929

30+
#include <stdint.h>
3031
#include <stdlib.h>
3132
#include <stdarg.h>
3233

@@ -43,7 +44,7 @@ compat_banner(struct ssh *ssh, const char *version)
4344
int i;
4445
static struct {
4546
char *pat;
46-
int bugs;
47+
uint32_t bugs;
4748
} check[] = {
4849
{ "OpenSSH_2.*,"
4950
"OpenSSH_3.0*,"

monitor.c

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* $OpenBSD: monitor.c,v 1.252 2026/02/08 19:54:31 dtucker Exp $ */
1+
/* $OpenBSD: monitor.c,v 1.253 2026/03/02 02:40:15 djm Exp $ */
22
/*
33
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
44
* Copyright 2002 Markus Friedl <markus@openbsd.org>
@@ -106,6 +106,7 @@ static struct sshbuf *child_state;
106106
/* Functions on the monitor that answer unprivileged requests */
107107

108108
int mm_answer_moduli(struct ssh *, int, struct sshbuf *);
109+
int mm_answer_setcompat(struct ssh *, int, struct sshbuf *);
109110
int mm_answer_sign(struct ssh *, int, struct sshbuf *);
110111
int mm_answer_pwnamallow(struct ssh *, int, struct sshbuf *);
111112
int mm_answer_auth2_read_banner(struct ssh *, int, struct sshbuf *);
@@ -157,6 +158,7 @@ static u_char *session_id2 = NULL;
157158
static pid_t monitor_child_pid;
158159
static int auth_attempted = 0;
159160
static int invalid_user = 0;
161+
static int compat_set = 0;
160162

161163
struct mon_table {
162164
enum monitor_reqtype type;
@@ -182,6 +184,7 @@ struct mon_table mon_dispatch_proto20[] = {
182184
#ifdef WITH_OPENSSL
183185
{MONITOR_REQ_MODULI, MON_ONCE, mm_answer_moduli},
184186
#endif
187+
{MONITOR_REQ_SETCOMPAT, MON_ONCE, mm_answer_setcompat},
185188
{MONITOR_REQ_SIGN, MON_ONCE, mm_answer_sign},
186189
{MONITOR_REQ_PWNAM, MON_ONCE, mm_answer_pwnamallow},
187190
{MONITOR_REQ_AUTHSERV, MON_ONCE, mm_answer_authserv},
@@ -283,6 +286,7 @@ monitor_child_preauth(struct ssh *ssh, struct monitor *pmonitor)
283286
/* Permit requests for state, moduli and signatures */
284287
monitor_permit(mon_dispatch, MONITOR_REQ_STATE, 1);
285288
monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1);
289+
monitor_permit(mon_dispatch, MONITOR_REQ_SETCOMPAT, 1);
286290
monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1);
287291

288292
/* The first few requests do not require asynchronous access */
@@ -701,6 +705,20 @@ mm_answer_moduli(struct ssh *ssh, int sock, struct sshbuf *m)
701705
}
702706
#endif
703707

708+
int
709+
mm_answer_setcompat(struct ssh *ssh, int sock, struct sshbuf *m)
710+
{
711+
int r;
712+
713+
debug3_f("entering");
714+
715+
if ((r = sshbuf_get_u32(m, &ssh->compat)) != 0)
716+
fatal_fr(r, "parse");
717+
compat_set = 1;
718+
719+
return (0);
720+
}
721+
704722
int
705723
mm_answer_sign(struct ssh *ssh, int sock, struct sshbuf *m)
706724
{
@@ -716,6 +734,10 @@ mm_answer_sign(struct ssh *ssh, int sock, struct sshbuf *m)
716734

717735
debug3_f("entering");
718736

737+
/* Make sure the unpriv process sent the compat bits already */
738+
if (!compat_set)
739+
fatal_f("state error: setcompat never called");
740+
719741
if ((r = sshkey_froms(m, &pubkey)) != 0 ||
720742
(r = sshbuf_get_string(m, &p, &datlen)) != 0 ||
721743
(r = sshbuf_get_cstring(m, &alg, NULL)) != 0 ||
@@ -843,6 +865,10 @@ mm_answer_pwnamallow(struct ssh *ssh, int sock, struct sshbuf *m)
843865

844866
debug3_f("entering");
845867

868+
/* Make sure the unpriv process sent the compat bits already */
869+
if (!compat_set)
870+
fatal_f("state error: setcompat never called");
871+
846872
if (authctxt->attempt++ != 0)
847873
fatal_f("multiple attempts for getpwnam");
848874

monitor.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* $OpenBSD: monitor.h,v 1.27 2026/02/09 21:23:35 dtucker Exp $ */
1+
/* $OpenBSD: monitor.h,v 1.28 2026/03/02 02:40:15 djm Exp $ */
22

33
/*
44
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
@@ -39,6 +39,7 @@ enum monitor_reqtype {
3939
MONITOR_REQ_AUTHPASSWORD = 12, MONITOR_ANS_AUTHPASSWORD = 13,
4040
MONITOR_REQ_BSDAUTHQUERY = 14, MONITOR_ANS_BSDAUTHQUERY = 15,
4141
MONITOR_REQ_BSDAUTHRESPOND = 16, MONITOR_ANS_BSDAUTHRESPOND = 17,
42+
MONITOR_REQ_SETCOMPAT = 18,
4243
MONITOR_REQ_KEYALLOWED = 22, MONITOR_ANS_KEYALLOWED = 23,
4344
MONITOR_REQ_KEYVERIFY = 24, MONITOR_ANS_KEYVERIFY = 25,
4445
MONITOR_REQ_KEYEXPORT = 26,

monitor_wrap.c

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* $OpenBSD: monitor_wrap.c,v 1.145 2026/02/08 19:54:31 dtucker Exp $ */
1+
/* $OpenBSD: monitor_wrap.c,v 1.146 2026/03/02 02:40:15 djm Exp $ */
22
/*
33
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
44
* Copyright 2002 Markus Friedl <markus@openbsd.org>
@@ -254,6 +254,21 @@ mm_choose_dh(int min, int nbits, int max)
254254
}
255255
#endif
256256

257+
void
258+
mm_sshkey_setcompat(struct ssh *ssh)
259+
{
260+
struct sshbuf *m;
261+
int r;
262+
263+
debug3_f("entering");
264+
if ((m = sshbuf_new()) == NULL)
265+
fatal_f("sshbuf_new failed");
266+
if ((r = sshbuf_put_u32(m, ssh->compat)) != 0)
267+
fatal_fr(r, "assemble");
268+
269+
mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_SETCOMPAT, m);
270+
}
271+
257272
int
258273
mm_sshkey_sign(struct ssh *ssh, struct sshkey *key, u_char **sigp, size_t *lenp,
259274
const u_char *data, size_t datalen, const char *hostkey_alg,

monitor_wrap.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* $OpenBSD: monitor_wrap.h,v 1.53 2025/07/04 07:47:35 djm Exp $ */
1+
/* $OpenBSD: monitor_wrap.h,v 1.54 2026/03/02 02:40:15 djm Exp $ */
22

33
/*
44
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
@@ -46,6 +46,7 @@ int mm_is_monitor(void);
4646
#ifdef WITH_OPENSSL
4747
DH *mm_choose_dh(int, int, int);
4848
#endif
49+
void mm_sshkey_setcompat(struct ssh *);
4950
int mm_sshkey_sign(struct ssh *, struct sshkey *, u_char **, size_t *,
5051
const u_char *, size_t, const char *, const char *,
5152
const char *, u_int compat);

packet.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* $OpenBSD: packet.h,v 1.105 2026/02/08 17:50:49 dtucker Exp $ */
1+
/* $OpenBSD: packet.h,v 1.106 2026/03/02 02:40:15 djm Exp $ */
22

33
/*
44
* Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -18,6 +18,7 @@
1818

1919
#include <sys/queue.h>
2020

21+
#include <stdint.h>
2122
#include <signal.h>
2223
#include <termios.h>
2324

@@ -74,7 +75,7 @@ struct ssh {
7475
int dispatch_skip_packets;
7576

7677
/* datafellows */
77-
int compat;
78+
uint32_t compat;
7879

7980
/* Lists for private and public keys */
8081
TAILQ_HEAD(, key_entry) private_keys;

sshd-auth.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* $OpenBSD: sshd-auth.c,v 1.12 2026/02/11 17:05:32 dtucker Exp $ */
1+
/* $OpenBSD: sshd-auth.c,v 1.13 2026/03/02 02:40:15 djm Exp $ */
22
/*
33
* SSH2 implementation:
44
* Privilege Separation:
@@ -811,6 +811,14 @@ do_ssh2_kex(struct ssh *ssh)
811811

812812
free(hkalgs);
813813

814+
if ((r = kex_exchange_identification(ssh, -1,
815+
options.version_addendum)) != 0)
816+
sshpkt_fatal(ssh, r, "banner exchange");
817+
mm_sshkey_setcompat(ssh); /* tell monitor */
818+
819+
if ((ssh->compat & SSH_BUG_NOREKEY))
820+
debug("client does not support rekeying");
821+
814822
/* start key exchange */
815823
if ((r = kex_setup(ssh, myproposal)) != 0)
816824
fatal_r(r, "kex_setup");

sshd-session.c

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* $OpenBSD: sshd-session.c,v 1.20 2026/02/09 21:38:14 dtucker Exp $ */
1+
/* $OpenBSD: sshd-session.c,v 1.21 2026/03/02 02:40:15 djm Exp $ */
22
/*
33
* SSH2 implementation:
44
* Privilege Separation:
@@ -1220,13 +1220,6 @@ main(int ac, char **av)
12201220
fatal("login grace time setitimer failed");
12211221
}
12221222

1223-
if ((r = kex_exchange_identification(ssh, -1,
1224-
options.version_addendum)) != 0)
1225-
sshpkt_fatal(ssh, r, "banner exchange");
1226-
1227-
if ((ssh->compat & SSH_BUG_NOREKEY))
1228-
debug("client does not support rekeying");
1229-
12301223
ssh_packet_set_nonblocking(ssh);
12311224

12321225
/* allocate authentication context */

0 commit comments

Comments
 (0)