[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#1125139: trixie-pu: package openssh/1:10.0p1-7+deb13u1



Package: release.debian.org
Severity: normal
Tags: trixie
X-Debbugs-Cc: openssh@packages.debian.org
Control: affects -1 + src:openssh
User: release.debian.org@packages.debian.org
Usertags: pu

[ Reason ]
The security team asked me to fix CVE-2025-61984 and CVE-2025-61985 in 
the next available point release.

[ Impact ]
Control characters in usernames from some untrusted sources can result 
in code execution when a ProxyCommand is used.

[ Tests ]
I've included backports of upstream's regression tests for these cases.

[ Risks ]
I think the changes are all fairly readable and straightforward.  For 
trixie, they were all simple cherry-picks.

[ Checklist ]
  [x] *all* changes are documented in the d/changelog
  [x] I reviewed all changes and I approve them
  [x] attach debdiff against the package in (old)stable
  [x] the issue is verified as fixed in unstable

[ Changes ]
* Improve rules for %-expansion of username: usernames passed on the 
  command line will no longer be subject to %-expansion.  Add 
  corresponding regression tests.
* Don't allow \0 characters in URL-encoded strings.

Thanks,

-- 
Colin Watson (he/him)                              [cjwatson@debian.org]
diff -Nru openssh-10.0p1/debian/.git-dpm openssh-10.0p1/debian/.git-dpm
--- openssh-10.0p1/debian/.git-dpm	2025-08-01 16:02:27.000000000 +0100
+++ openssh-10.0p1/debian/.git-dpm	2026-01-08 17:39:42.000000000 +0000
@@ -1,6 +1,6 @@
 # see git-dpm(1) from git-dpm package
-f5c89caec93130da905a95602cf36a4e25f2303e
-f5c89caec93130da905a95602cf36a4e25f2303e
+4aa3f8603893eba6937b6ea2addc85bbf5f8f737
+4aa3f8603893eba6937b6ea2addc85bbf5f8f737
 860fa104f07024318a40065f07708daa5753f55d
 860fa104f07024318a40065f07708daa5753f55d
 openssh_10.0p1.orig.tar.gz
diff -Nru openssh-10.0p1/debian/changelog openssh-10.0p1/debian/changelog
--- openssh-10.0p1/debian/changelog	2025-08-01 16:02:27.000000000 +0100
+++ openssh-10.0p1/debian/changelog	2026-01-08 17:39:42.000000000 +0000
@@ -1,3 +1,13 @@
+openssh (1:10.0p1-7+deb13u1) UNRELEASED; urgency=medium
+
+  * CVE-2025-61984: ssh(1): disallow control characters in usernames passed
+    via the commandline or expanded using %-sequences from the configuration
+    file (closes: #1117529).
+  * CVE-2025-61985: ssh(1): disallow \0 characters in ssh:// URIs (closes:
+    #1117530).
+
+ -- Colin Watson <cjwatson@debian.org>  Thu, 08 Jan 2026 17:39:42 +0000
+
 openssh (1:10.0p1-7) unstable; urgency=medium
 
   * Make postinst logic for cleaning up the sshd diversion more robust.
diff -Nru openssh-10.0p1/debian/patches/CVE-2025-61984-tests.patch openssh-10.0p1/debian/patches/CVE-2025-61984-tests.patch
--- openssh-10.0p1/debian/patches/CVE-2025-61984-tests.patch	1970-01-01 01:00:00.000000000 +0100
+++ openssh-10.0p1/debian/patches/CVE-2025-61984-tests.patch	2026-01-08 17:39:42.000000000 +0000
@@ -0,0 +1,106 @@
+From 4aa3f8603893eba6937b6ea2addc85bbf5f8f737 Mon Sep 17 00:00:00 2001
+From: "djm@openbsd.org" <djm@openbsd.org>
+Date: Thu, 4 Sep 2025 03:04:44 +0000
+Subject: upstream: repair test after changes to percent expansion of usernames
+
+on the commandline.
+
+Test more cases that should/shouldn't expand and lightly test
+username validity checks.
+
+OpenBSD-Regress-ID: ad4c12c70bdf1f959abfebd1637ecff1b49a484c
+
+Origin: https://anongit.mindrot.org/openssh.git/commit/?id=f64701ca25795548a61614d0b13391d6dfa7f38c
+Bug-Debian: https://bugs.debian.org/1117530
+Last-Update: 2026-01-08
+
+Patch-Name: CVE-2025-61984-tests.patch
+---
+ regress/percent.sh | 45 +++++++++++++++++++++++++++++++++++++--------
+ 1 file changed, 37 insertions(+), 8 deletions(-)
+
+diff --git a/regress/percent.sh b/regress/percent.sh
+index 7ce9e8a1d..c607c8d23 100644
+--- a/regress/percent.sh
++++ b/regress/percent.sh
+@@ -1,4 +1,4 @@
+-#	$OpenBSD: percent.sh,v 1.21 2025/04/08 23:10:46 djm Exp $
++#	$OpenBSD: percent.sh,v 1.22 2025/09/04 03:04:44 djm Exp $
+ #	Placed in the Public Domain.
+ 
+ tid="percent expansions"
+@@ -33,14 +33,14 @@ trial()
+ 		if [ "$arg" = '%r' ] || [ "$arg" = '%C' ]; then
+ 			# User does not support %r, ie itself or %C.  Skip test.
+ 			got="$expect"
+-		elif [ "$i" = "user" ]; then
++		elif [ "$opt" = "user" ]; then
+ 			got=`${SSH} -F $OBJ/ssh_proxy -o $opt="$arg" -G \
+ 			    remuser@somehost | awk '$1=="'$opt'"{print $2}'`
+-		elif [ "$i" = "user-l" ]; then
++		elif [ "$opt" = "user-l" ]; then
+ 			# Also test ssh -l
+ 			got=`${SSH} -F $OBJ/ssh_proxy -l "$arg" -G \
+ 			    somehost | awk '$1=="'user'"{print $2}'`
+-		elif [ "$i" = "user-at" ]; then
++		elif [ "$opt" = "user-at" ]; then
+ 			# Also test user@host
+ 			got=`${SSH} -F $OBJ/ssh_proxy -G "$arg@somehost" | \
+ 			    awk '$1=="'user'"{print $2}'`
+@@ -91,7 +91,7 @@ trial()
+ 
+ for i in matchexec localcommand remotecommand controlpath identityagent \
+     forwardagent localforward remoteforward revokedhostkeys \
+-    user user-l user-at setenv userknownhostsfile; do
++    user setenv userknownhostsfile; do
+ 	verbose $tid $i percent
+ 	case "$i" in
+ 	localcommand|userknownhostsfile)
+@@ -137,11 +137,11 @@ done
+ 
+ # Subset of above since we don't expand shell-style variables on anything that
+ # runs a command because the shell will expand those.
++FOO=bar
++export FOO
+ for i in controlpath identityagent forwardagent localforward remoteforward \
+-    user user-l user-at setenv userknownhostsfile; do
++    user setenv userknownhostsfile; do
+ 	verbose $tid $i dollar
+-	FOO=bar
+-	export FOO
+ 	trial $i '${FOO}' $FOO
+ done
+ 
+@@ -152,3 +152,32 @@ for i in controlpath identityagent forwardagent; do
+ 	trial $i '~' $HOME/
+ 	trial $i '~/.ssh' $HOME/.ssh
+ done
++
++for i in user-l user-at; do
++	verbose $tid $i noexpand
++	trial $i '%u' '%u'
++done
++
++# These should be not be expanded but rejected for containing shell characters.
++verbose $tid user-l noenv
++${SSH} -F $OBJ/ssh_proxy -l '${FOO}' -G somehost && fail "user-l expanded env"
++verbose $tid user-at noenv
++${SSH} -F $OBJ/ssh_proxy -G '${FOO}@somehost' && fail "user-at expanded env"
++
++FOO=`printf 'x\ay'`
++export FOO
++
++# These should be rejected as containing control characters.
++verbose $tid user-l badchar
++${SSH} -F $OBJ/ssh_proxy -l "${FOO}" -G somehost && fail "user-l expanded env"
++verbose $tid user-at badchar
++${SSH} -F $OBJ/ssh_proxy -G "${FOO}@somehost" && fail "user-at expanded env"
++
++# Literal control characters in config is acceptable
++verbose $tid user control-literal
++trial user "$FOO" "$FOO"
++
++# Control characters expanded from config aren't.
++${SSH} -F $OBJ/ssh_proxy -G '-oUser=${FOO}' somehost && \
++    fail "user expanded ctrl"
++
diff -Nru openssh-10.0p1/debian/patches/CVE-2025-61984.patch openssh-10.0p1/debian/patches/CVE-2025-61984.patch
--- openssh-10.0p1/debian/patches/CVE-2025-61984.patch	1970-01-01 01:00:00.000000000 +0100
+++ openssh-10.0p1/debian/patches/CVE-2025-61984.patch	2026-01-08 17:39:42.000000000 +0000
@@ -0,0 +1,132 @@
+From 7e076cb419a27153e81243b339ce2efbc3c1f6f3 Mon Sep 17 00:00:00 2001
+From: "djm@openbsd.org" <djm@openbsd.org>
+Date: Thu, 4 Sep 2025 00:29:09 +0000
+Subject: upstream: Improve rules for %-expansion of username.
+
+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
+
+Origin: upstream, https://anongit.mindrot.org/openssh.git/commit/?id=35d5917652106aede47621bb3f64044604164043
+Bug-Debian: https://bugs.debian.org/1117529
+Last-Update: 2026-01-08
+
+Patch-Name: CVE-2025-61984.patch
+---
+ ssh.c | 31 +++++++++++++++++++++++++------
+ 1 file changed, 25 insertions(+), 6 deletions(-)
+
+diff --git a/ssh.c b/ssh.c
+index 55463e5ad..9a8267869 100644
+--- a/ssh.c
++++ b/ssh.c
+@@ -654,6 +654,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 */
+@@ -675,6 +677,7 @@ main(int ac, char **av)
+ 	struct ssh *ssh = NULL;
+ 	int i, r, opt, exit_status, use_syslog, direct, timeout_ms;
+ 	int was_addr, config_test = 0, opt_terminated = 0, want_final_pass = 0;
++	int user_on_commandline = 0, user_was_default = 0, user_expanded = 0;
+ 	char *p, *cp, *line, *argv0, *logfile, *args;
+ 	char cname[NI_MAXHOST], thishost[NI_MAXHOST];
+ 	struct stat st;
+@@ -1026,8 +1029,10 @@ main(int ac, char **av)
+ 			}
+ 			break;
+ 		case 'l':
+-			if (options.user == NULL)
++			if (options.user == NULL) {
+ 				options.user = xstrdup(optarg);
++				user_on_commandline = 1;
++			}
+ 			break;
+ 
+ 		case 'L':
+@@ -1130,6 +1135,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)
+@@ -1144,6 +1150,7 @@ main(int ac, char **av)
+ 				if (options.user == NULL) {
+ 					options.user = p;
+ 					p = NULL;
++					user_on_commandline = 1;
+ 				}
+ 				*cp++ = '\0';
+ 				host = xstrdup(cp);
+@@ -1303,8 +1310,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.
+@@ -1451,20 +1460,30 @@ main(int ac, char **av)
+ 	    "" : options.jump_host);
+ 
+ 	/*
+-	 * Expand User. It cannot contain %r (itself) or %C since User is
++	 * If the user was specified via a configuration directive then attempt
++	 * to expand it. It cannot contain %r (itself) or %C since User is
+ 	 * a component of the hash.
+ 	 */
+-	if (options.user != NULL) {
++	if (!user_on_commandline && !user_was_default) {
+ 		if ((p = percent_dollar_expand(options.user,
+ 		    DEFAULT_CLIENT_PERCENT_EXPAND_ARGS_NOUSER(cinfo),
+ 		    (char *)NULL)) == NULL)
+ 			fatal("invalid environment variable expansion");
++		user_expanded = strcmp(p, options.user) != 0;
+ 		free(options.user);
+ 		options.user = p;
+-		if (!valid_ruser(options.user))
+-			fatal("remote username contains invalid characters");
+ 	}
+ 
++	/*
++	 * Usernames specified on the commandline or expanded from the
++	 * configuration file 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 || user_expanded) &&
++	    !valid_ruser(options.user))
++		fatal("remote username contains invalid characters");
++
+ 	/* Now User is expanded, store it and calculate hash. */
+ 	cinfo->remuser = xstrdup(options.user);
+ 	cinfo->conn_hash_hex = ssh_connection_hash(cinfo->thishost,
diff -Nru openssh-10.0p1/debian/patches/CVE-2025-61985.patch openssh-10.0p1/debian/patches/CVE-2025-61985.patch
--- openssh-10.0p1/debian/patches/CVE-2025-61985.patch	1970-01-01 01:00:00.000000000 +0100
+++ openssh-10.0p1/debian/patches/CVE-2025-61985.patch	2026-01-08 17:39:42.000000000 +0000
@@ -0,0 +1,43 @@
+From 0bd8630712ee27da7aebfec79c96239657ae9369 Mon Sep 17 00:00:00 2001
+From: "djm@openbsd.org" <djm@openbsd.org>
+Date: Thu, 4 Sep 2025 00:30:06 +0000
+Subject: upstream: don't allow \0 characters in url-encoded strings.
+
+Suggested by David Leadbeater, ok deraadt@
+
+OpenBSD-Commit-ID: c92196cef0f970ceabc1e8007a80b01e9b7cd49c
+
+Origin: upstream, https://anongit.mindrot.org/openssh.git/commit/?id=43b3bff47bb029f2299bacb6a36057981b39fdb0
+Bug-Debian: https://bugs.debian.org/1117530
+Last-Update: 2026-01-08
+
+Patch-Name: CVE-2025-61985.patch
+---
+ misc.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/misc.c b/misc.c
+index 081d07993..3b02281bb 100644
+--- a/misc.c
++++ b/misc.c
+@@ -990,7 +990,7 @@ urldecode(const char *src)
+ 	size_t srclen;
+ 
+ 	if ((srclen = strlen(src)) >= SIZE_MAX)
+-		fatal_f("input too large");
++		return NULL;
+ 	ret = xmalloc(srclen + 1);
+ 	for (dst = ret; *src != '\0'; src++) {
+ 		switch (*src) {
+@@ -998,9 +998,10 @@ urldecode(const char *src)
+ 			*dst++ = ' ';
+ 			break;
+ 		case '%':
++			/* note: don't allow \0 characters */
+ 			if (!isxdigit((unsigned char)src[1]) ||
+ 			    !isxdigit((unsigned char)src[2]) ||
+-			    (ch = hexchar(src + 1)) == -1) {
++			    (ch = hexchar(src + 1)) == -1 || ch == 0) {
+ 				free(ret);
+ 				return NULL;
+ 			}
diff -Nru openssh-10.0p1/debian/patches/series openssh-10.0p1/debian/patches/series
--- openssh-10.0p1/debian/patches/series	2025-08-01 16:02:27.000000000 +0100
+++ openssh-10.0p1/debian/patches/series	2026-01-08 17:39:42.000000000 +0000
@@ -26,3 +26,6 @@
 regress-conch-dev-zero.patch
 configure-cache-vars.patch
 pam-avoid-unknown-host.patch
+CVE-2025-61984.patch
+CVE-2025-61985.patch
+CVE-2025-61984-tests.patch

Reply to: