Package: release.debian.org
Severity: normal
Tags: bookworm
X-Debbugs-Cc: [email protected]
Control: affects -1 + src:openssh
User: [email protected]
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, but 
unlike in the trixie case I had to make some edits of my own.  
%-expansion of usernames was only introduced in OpenSSH 10.0, so that 
part of the problem isn't relevant to bookworm.  I tried to stay as 
close to the upstream changes as I could, and just dropped the parts 
that were only relevant to %-expansion.

[ 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 ]
* Refuse usernames that include control characters.  Add corresponding 
  regression tests.
* Don't allow \0 characters in URL-encoded strings.

Thanks,

-- 
Colin Watson (he/him)                              [[email protected]]
diff -Nru openssh-9.2p1/debian/.git-dpm openssh-9.2p1/debian/.git-dpm
--- openssh-9.2p1/debian/.git-dpm       2025-07-28 12:58:38.000000000 +0100
+++ openssh-9.2p1/debian/.git-dpm       2026-01-08 19:17:36.000000000 +0000
@@ -1,6 +1,6 @@
 # see git-dpm(1) from git-dpm package
-d69f6291ca7b1d7315a54aa50c1538f97b7b1f8f
-d69f6291ca7b1d7315a54aa50c1538f97b7b1f8f
+e5402601353303321fb2953e0b7d45f0838b94db
+e5402601353303321fb2953e0b7d45f0838b94db
 cf3c3acb2b8f74eeca7fcee269b1d33ac83f1188
 cf3c3acb2b8f74eeca7fcee269b1d33ac83f1188
 openssh_9.2p1.orig.tar.gz
diff -Nru openssh-9.2p1/debian/changelog openssh-9.2p1/debian/changelog
--- openssh-9.2p1/debian/changelog      2025-07-28 12:59:40.000000000 +0100
+++ openssh-9.2p1/debian/changelog      2026-01-08 19:17:36.000000000 +0000
@@ -1,3 +1,12 @@
+openssh (1:9.2p1-2+deb12u8) UNRELEASED; urgency=medium
+
+  * CVE-2025-61984: ssh(1): disallow control characters in usernames passed
+    via the commandline (closes: #1117529).
+  * CVE-2025-61985: ssh(1): disallow \0 characters in ssh:// URIs (closes:
+    #1117530).
+
+ -- Colin Watson <[email protected]>  Thu, 08 Jan 2026 19:17:36 +0000
+
 openssh (1:9.2p1-2+deb12u7) bookworm; urgency=medium
 
   * Handle OpenSSL >=3 ABI compatibility; this helps to avoid new ssh
diff -Nru openssh-9.2p1/debian/patches/CVE-2025-61984-tests.patch 
openssh-9.2p1/debian/patches/CVE-2025-61984-tests.patch
--- openssh-9.2p1/debian/patches/CVE-2025-61984-tests.patch     1970-01-01 
01:00:00.000000000 +0100
+++ openssh-9.2p1/debian/patches/CVE-2025-61984-tests.patch     2026-01-08 
19:17:36.000000000 +0000
@@ -0,0 +1,82 @@
+From e5402601353303321fb2953e0b7d45f0838b94db Mon Sep 17 00:00:00 2001
+From: "[email protected]" <[email protected]>
+Date: Thu, 4 Sep 2025 03:04:44 +0000
+Subject: Add more username validity checks
+
+[cjwatson: Reduced from a more extensive upstream change, since OpenSSH
+< 10.0 doesn't support %-expansion of usernames.]
+
+OpenBSD-Regress-ID: ad4c12c70bdf1f959abfebd1637ecff1b49a484c
+
+Origin: backport, 
https://anongit.mindrot.org/openssh.git/commit/?id=f64701ca25795548a61614d0b13391d6dfa7f38c
+Author: Colin Watson <[email protected]>
+Bug-Debian: https://bugs.debian.org/1117530
+Last-Update: 2026-01-09
+
+Patch-Name: CVE-2025-61984-tests.patch
+---
+ regress/percent.sh | 37 +++++++++++++++++++++++++++++++++++--
+ 1 file changed, 35 insertions(+), 2 deletions(-)
+
+diff --git a/regress/percent.sh b/regress/percent.sh
+index 3dfa8d2df..6b9c492b0 100644
+--- a/regress/percent.sh
++++ b/regress/percent.sh
+@@ -34,6 +34,20 @@ trial()
+                   somehost true
+               got=`cat $OBJ/actual`
+               ;;
++      user)
++              got=`${SSH} -F $OBJ/ssh_proxy -o $opt="$arg" -G \
++                  remuser@somehost | awk '$1=="'$opt'"{print $2}'`
++              ;;
++      user-l)
++              # Also test ssh -l
++              got=`${SSH} -F $OBJ/ssh_proxy -l "$arg" -G \
++                  somehost | awk '$1=="'user'"{print $2}'`
++              ;;
++      user-at)
++              # Also test user@host
++              got=`${SSH} -F $OBJ/ssh_proxy -G "$arg@somehost" | \
++                  awk '$1=="'user'"{print $2}'`
++              ;;
+       userknownhostsfile)
+               # Move the userknownhosts file to what the expansion says,
+               # make sure ssh works then put it back.
+@@ -111,11 +125,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 \
+     userknownhostsfile; do
+       verbose $tid $i dollar
+-      FOO=bar
+-      export FOO
+       trial $i '${FOO}' $FOO
+ done
+ 
+@@ -126,3 +140,22 @@ for i in controlpath identityagent forwardagent; do
+       trial $i '~' $HOME/
+       trial $i '~/.ssh' $HOME/.ssh
+ 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"
diff -Nru openssh-9.2p1/debian/patches/CVE-2025-61984.patch 
openssh-9.2p1/debian/patches/CVE-2025-61984.patch
--- openssh-9.2p1/debian/patches/CVE-2025-61984.patch   1970-01-01 
01:00:00.000000000 +0100
+++ openssh-9.2p1/debian/patches/CVE-2025-61984.patch   2026-01-08 
19:17:36.000000000 +0000
@@ -0,0 +1,108 @@
+From cab036bedba20f6f11a9fd3baab79645a2c30d4c Mon Sep 17 00:00:00 2001
+From: "[email protected]" <[email protected]>
+Date: Thu, 4 Sep 2025 00:29:09 +0000
+Subject: Refuse usernames that include control characters
+
+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; 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 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@
+
+[cjwatson: The original upstream change also improved rules for
+%-expansion of usernames.  However, %-expansion of usernames was only
+introduced in OpenSSH 10.0 and so is not relevant to Debian 12 and
+earlier.]
+
+OpenBSD-Commit-ID: e2f0c871fbe664aba30607321575e7c7fc798362
+
+Origin: backport, 
https://anongit.mindrot.org/openssh.git/commit/?id=35d5917652106aede47621bb3f64044604164043
+Author: Colin Watson <[email protected]>
+Bug-Debian: https://bugs.debian.org/1117529
+Last-Update: 2026-01-08
+
+Patch-Name: CVE-2025-61984.patch
+---
+ ssh.c | 19 ++++++++++++++++---
+ 1 file changed, 16 insertions(+), 3 deletions(-)
+
+diff --git a/ssh.c b/ssh.c
+index 422405035..a45da5877 100644
+--- a/ssh.c
++++ b/ssh.c
+@@ -646,6 +646,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 */
+@@ -667,6 +669,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;
+       char *p, *cp, *line, *argv0, *logfile;
+       char cname[NI_MAXHOST], thishost[NI_MAXHOST];
+       struct stat st;
+@@ -1008,8 +1011,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':
+@@ -1112,6 +1117,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)
+@@ -1126,6 +1132,7 @@ main(int ac, char **av)
+                               if (options.user == NULL) {
+                                       options.user = p;
+                                       p = NULL;
++                                      user_on_commandline = 1;
+                               }
+                               *cp++ = '\0';
+                               host = xstrdup(cp);
+@@ -1147,8 +1154,6 @@ main(int ac, char **av)
+ 
+       if (!valid_hostname(host))
+               fatal("hostname contains invalid characters");
+-      if (options.user != NULL && !valid_ruser(options.user))
+-              fatal("remote username contains invalid characters");
+       options.host_arg = xstrdup(host);
+ 
+       /* Initialize the command to execute on remote host. */
+@@ -1428,6 +1433,14 @@ main(int ac, char **av)
+       cinfo->homedir = xstrdup(pw->pw_dir);
+       cinfo->locuser = xstrdup(pw->pw_name);
+ 
++      /*
++       * Usernames specified on the commandline must be validated.
++       * Conversely, usernames from getpwnam(3) or specified as literals
++       * via configuration are not subject to validation.
++       */
++      if (user_on_commandline && !valid_ruser(options.user))
++              fatal("remote username contains invalid characters");
++
+       /*
+        * Expand tokens in arguments. NB. LocalCommand is expanded later,
+        * after port-forwarding is set up, so it may pick up any local
diff -Nru openssh-9.2p1/debian/patches/CVE-2025-61985.patch 
openssh-9.2p1/debian/patches/CVE-2025-61985.patch
--- openssh-9.2p1/debian/patches/CVE-2025-61985.patch   1970-01-01 
01:00:00.000000000 +0100
+++ openssh-9.2p1/debian/patches/CVE-2025-61985.patch   2026-01-08 
19:17:36.000000000 +0000
@@ -0,0 +1,46 @@
+From 48b09ff880d30b95d18273b02601097abeb12b9d Mon Sep 17 00:00:00 2001
+From: "[email protected]" <[email protected]>
+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: backport, 
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 | 8 ++++++--
+ 1 file changed, 6 insertions(+), 2 deletions(-)
+
+diff --git a/misc.c b/misc.c
+index 36e72f5b5..a50119446 100644
+--- a/misc.c
++++ b/misc.c
+@@ -930,17 +930,21 @@ urldecode(const char *src)
+ {
+       char *ret, *dst;
+       int ch;
++      size_t srclen;
+ 
+-      ret = xmalloc(strlen(src) + 1);
++      if ((srclen = strlen(src)) >= SIZE_MAX)
++              return NULL;
++      ret = xmalloc(srclen + 1);
+       for (dst = ret; *src != '\0'; src++) {
+               switch (*src) {
+               case '+':
+                       *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-9.2p1/debian/patches/series 
openssh-9.2p1/debian/patches/series
--- openssh-9.2p1/debian/patches/series 2025-07-28 12:58:38.000000000 +0100
+++ openssh-9.2p1/debian/patches/series 2026-01-08 19:17:36.000000000 +0000
@@ -40,3 +40,6 @@
 CVE-2025-26465.patch
 incorrect-return-values.patch
 fix-disable-forwarding.patch
+CVE-2025-61984.patch
+CVE-2025-61985.patch
+CVE-2025-61984-tests.patch

Reply via email to