openssh: fix CVE-2025-61984

ssh in OpenSSH before 10.1 allows control characters in usernames that
originate from certain possibly untrusted sources, potentially leading
to code execution when a ProxyCommand is used. The untrusted sources
are the command line and %-sequence expansion of a configuration file.

Note:
openssh does not support variable expansion until 10.0, so backport
adapts for this.

Reference:
https://nvd.nist.gov/vuln/detail/CVE-2025-61984

Upstream patch:
35d5917652

(From OE-Core rev: 717d4c7609cdce2cc3a65b7ba69c316fa86a9333)

Signed-off-by: David Nyström <david.nystrom@est.tech>
Signed-off-by: Steve Sakoman <steve@sakoman.com>
This commit is contained in:
David Nyström 2025-10-15 14:20:28 +02:00 committed by Steve Sakoman
parent a7fdce2a68
commit 2142f17368
2 changed files with 126 additions and 0 deletions

View File

@ -0,0 +1,125 @@
From d45e13c956b296bf933901c4da2b61eb2ccd7582 Mon Sep 17 00:00:00 2001
From: "djm@openbsd.org" <djm@openbsd.org>
Date: Thu, 4 Sep 2025 00:29:09 +0000
Subject: [PATCH] upstream: Improve rules for %-expansion of username.
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Usernames passed on the commandline will no longer be subject to
% expansion. Some tools invoke ssh with connection information
(i.e. usernames and host names) supplied from untrusted sources.
These may contain % expansion sequences which could yield
unexpected results.
Since openssh-9.6, all usernames have been subject to validity
checking. This change tightens the validity checks by refusing
usernames that include control characters (again, these can cause
surprises when supplied adversarially).
This change also relaxes the validity checks in one small way:
usernames supplied via the configuration file as literals (i.e.
include no % expansion characters) are not subject to these
validity checks. This allows usernames that contain arbitrary
characters to be used, but only via configuration files. This
is done on the basis that ssh's configuration is trusted.
Pointed out by David Leadbeater, ok deraadt@
OpenBSD-Commit-ID: e2f0c871fbe664aba30607321575e7c7fc798362
Slightly modified since variable expansion of user names was
first released in 10.0, commit bd30cf784d6e8"
Upstream-Status: Backport [Upstream commit https://github.com/openssh/openssh-portable/commit/35d5917652106aede47621bb3f64044604164043]
CVE: CVE-2025-61984
Signed-off-by: David Nyström <david.nystrom@est.tech>
---
ssh.c | 26 +++++++++++++++++++++++---
1 file changed, 23 insertions(+), 3 deletions(-)
diff --git a/ssh.c b/ssh.c
index 48d93ddf2..9c49f98a8 100644
--- a/ssh.c
+++ b/ssh.c
@@ -649,6 +649,8 @@ valid_ruser(const char *s)
if (*s == '-')
return 0;
for (i = 0; s[i] != 0; i++) {
+ if (iscntrl((u_char)s[i]))
+ return 0;
if (strchr("'`\";&<>|(){}", s[i]) != NULL)
return 0;
/* Disallow '-' after whitespace */
@@ -671,6 +673,7 @@ main(int ac, char **av)
int i, r, opt, exit_status, use_syslog, direct, timeout_ms;
int was_addr, config_test = 0, opt_terminated = 0, want_final_pass = 0;
char *p, *cp, *line, *argv0, *logfile;
+ int user_on_commandline = 0, user_was_default = 0;
char cname[NI_MAXHOST], thishost[NI_MAXHOST];
struct stat st;
struct passwd *pw;
@@ -1016,8 +1019,10 @@ main(int ac, char **av)
}
break;
case 'l':
- if (options.user == NULL)
+ if (options.user == NULL) {
options.user = optarg;
+ user_on_commandline = 1;
+ }
break;
case 'L':
@@ -1120,6 +1125,7 @@ main(int ac, char **av)
if (options.user == NULL) {
options.user = tuser;
tuser = NULL;
+ user_on_commandline = 1;
}
free(tuser);
if (options.port == -1 && tport != -1)
@@ -1134,6 +1140,7 @@ main(int ac, char **av)
if (options.user == NULL) {
options.user = p;
p = NULL;
+ user_on_commandline = 1;
}
*cp++ = '\0';
host = xstrdup(cp);
@@ -1288,8 +1295,10 @@ main(int ac, char **av)
if (fill_default_options(&options) != 0)
cleanup_exit(255);
- if (options.user == NULL)
+ if (options.user == NULL) {
+ user_was_default = 1;
options.user = xstrdup(pw->pw_name);
+ }
/*
* If ProxyJump option specified, then construct a ProxyCommand now.
@@ -1430,11 +1439,22 @@ main(int ac, char **av)
options.host_key_alias : options.host_arg);
cinfo->host_arg = xstrdup(options.host_arg);
cinfo->remhost = xstrdup(host);
- cinfo->remuser = xstrdup(options.user);
cinfo->homedir = xstrdup(pw->pw_dir);
cinfo->locuser = xstrdup(pw->pw_name);
cinfo->jmphost = xstrdup(options.jump_host == NULL ?
"" : options.jump_host);
+
+ /*
+ * Usernames specified on the commandline must be validated.
+ * Conversely, usernames from getpwnam(3) or specified as literals
+ * via configuration (i.e. not expanded) are not subject to validation.
+ */
+ if (user_on_commandline && !valid_ruser(options.user))
+ fatal("remote username contains invalid characters");
+
+ /* Store it and calculate hash. */
+ cinfo->remuser = xstrdup(options.user);
+
cinfo->conn_hash_hex = ssh_connection_hash(cinfo->thishost,
cinfo->remhost, cinfo->portstr, cinfo->remuser, cinfo->jmphost);

View File

@ -33,6 +33,7 @@ SRC_URI = "http://ftp.openbsd.org/pub/OpenBSD/OpenSSH/portable/openssh-${PV}.tar
file://CVE-2025-26465.patch \
file://CVE-2025-32728.patch \
file://CVE-2025-61985.patch \
file://CVE-2025-61984.patch \
"
SRC_URI[sha256sum] = "910211c07255a8c5ad654391b40ee59800710dd8119dd5362de09385aa7a777c"