Version in base suite: 10.0p1-7 Base version: openssh_10.0p1-7 Target version: openssh_10.0p1-7+deb13u1 Base file: /srv/ftp-master.debian.org/ftp/pool/main/o/openssh/openssh_10.0p1-7.dsc Target file: /srv/ftp-master.debian.org/policy/pool/main/o/openssh/openssh_10.0p1-7+deb13u1.dsc .git-dpm | 4 changelog | 12 ++ patches/CVE-2025-61984-tests.patch | 106 +++++++++++++++++++++++++ patches/CVE-2025-61984.patch | 132 ++++++++++++++++++++++++++++++++ patches/CVE-2025-61985.patch | 43 ++++++++++ patches/fix-max-startups-tracking.patch | 96 +++++++++++++++++++++++ patches/series | 4 7 files changed, 395 insertions(+), 2 deletions(-) dpkg-source: warning: cannot verify inline signature for /srv/release.debian.org/tmp/tmpuqb2hyg2/openssh_10.0p1-7.dsc: no acceptable signature found dpkg-source: warning: cannot verify inline signature for /srv/release.debian.org/tmp/tmpuqb2hyg2/openssh_10.0p1-7+deb13u1.dsc: no acceptable signature found diff -Nru openssh-10.0p1/debian/.git-dpm openssh-10.0p1/debian/.git-dpm --- openssh-10.0p1/debian/.git-dpm 2025-08-01 15:02:27.000000000 +0000 +++ openssh-10.0p1/debian/.git-dpm 2026-02-03 13:15:29.000000000 +0000 @@ -1,6 +1,6 @@ # see git-dpm(1) from git-dpm package -f5c89caec93130da905a95602cf36a4e25f2303e -f5c89caec93130da905a95602cf36a4e25f2303e +f9aa1828af2d4cb16246a9f98efb5239c094d8b3 +f9aa1828af2d4cb16246a9f98efb5239c094d8b3 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 15:02:27.000000000 +0000 +++ openssh-10.0p1/debian/changelog 2026-02-03 13:15:29.000000000 +0000 @@ -1,3 +1,15 @@ +openssh (1:10.0p1-7+deb13u1) trixie; 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). + * Fix mistracking of MaxStartups process exits in some situations (closes: + #1080350). + + -- Colin Watson Tue, 03 Feb 2026 13:15:29 +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 00:00:00.000000000 +0000 +++ openssh-10.0p1/debian/patches/CVE-2025-61984-tests.patch 2026-02-03 13:15:29.000000000 +0000 @@ -0,0 +1,106 @@ +From 68dfc2656e933f1571999e340da8db1137a27a78 Mon Sep 17 00:00:00 2001 +From: "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: upstream, 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 00:00:00.000000000 +0000 +++ openssh-10.0p1/debian/patches/CVE-2025-61984.patch 2026-02-03 13:15:29.000000000 +0000 @@ -0,0 +1,132 @@ +From 7e076cb419a27153e81243b339ce2efbc3c1f6f3 Mon Sep 17 00:00:00 2001 +From: "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 00:00:00.000000000 +0000 +++ openssh-10.0p1/debian/patches/CVE-2025-61985.patch 2026-02-03 13:15:29.000000000 +0000 @@ -0,0 +1,43 @@ +From 0bd8630712ee27da7aebfec79c96239657ae9369 Mon Sep 17 00:00:00 2001 +From: "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/fix-max-startups-tracking.patch openssh-10.0p1/debian/patches/fix-max-startups-tracking.patch --- openssh-10.0p1/debian/patches/fix-max-startups-tracking.patch 1970-01-01 00:00:00.000000000 +0000 +++ openssh-10.0p1/debian/patches/fix-max-startups-tracking.patch 2026-02-03 13:15:29.000000000 +0000 @@ -0,0 +1,96 @@ +From f9aa1828af2d4cb16246a9f98efb5239c094d8b3 Mon Sep 17 00:00:00 2001 +From: "djm@openbsd.org" +Date: Fri, 4 Jul 2025 09:51:01 +0000 +Subject: upstream: Fix mistracking of MaxStartups process exits in some + +situations. At worst, this can cause all MaxStartups slots to fill and sshd +to refuse new connections. + +Diagnosis by xnor; ok dtucker@ + +OpenBSD-Commit-ID: 10273033055552557196730f898ed6308b36a78d + +Origin: upstream, https://anongit.mindrot.org/openssh.git/commit/?id=eddd1d2daa64a6ab1a915ca88436fa41aede44d4 +Bug-Debian: https://bugs.debian.org/1080350 +Last-Update: 2025-08-08 + +Patch-Name: fix-max-startups-tracking.patch +--- + sshd.c | 28 ++++++++++++++++------------ + 1 file changed, 16 insertions(+), 12 deletions(-) + +diff --git a/sshd.c b/sshd.c +index 802cbe760..73afe3174 100644 +--- a/sshd.c ++++ b/sshd.c +@@ -297,8 +297,10 @@ child_finish(struct early_child *child) + { + if (children_active == 0) + fatal_f("internal error: children_active underflow"); +- if (child->pipefd != -1) ++ if (child->pipefd != -1) { ++ srclimit_done(child->pipefd); + close(child->pipefd); ++ } + sshbuf_free(child->config); + sshbuf_free(child->keys); + free(child->id); +@@ -319,6 +321,7 @@ child_close(struct early_child *child, int force_final, int quiet) + if (!quiet) + debug_f("enter%s", force_final ? " (forcing)" : ""); + if (child->pipefd != -1) { ++ srclimit_done(child->pipefd); + close(child->pipefd); + child->pipefd = -1; + } +@@ -1142,7 +1145,6 @@ server_accept_loop(int *sock_in, int *sock_out, int *newsock, int *config_s, + if (ret <= 0) { + if (children[i].early) + listening--; +- srclimit_done(children[i].pipefd); + child_close(&(children[i]), 0, 0); + continue; + } +@@ -1181,23 +1183,19 @@ server_accept_loop(int *sock_in, int *sock_out, int *newsock, int *config_s, + } + /* FALLTHROUGH */ + case 0: +- /* child exited preauth */ ++ /* child closed pipe */ + if (children[i].early) + listening--; +- srclimit_done(children[i].pipefd); ++ debug3_f("child %lu for %s closed pipe", ++ (long)children[i].pid, children[i].id); + child_close(&(children[i]), 0, 0); + break; + case 1: + if (children[i].config) { + error_f("startup pipe %d (fd=%d)" +- " early read", i, children[i].pipefd); +- if (children[i].early) +- listening--; +- if (children[i].pid > 0) +- kill(children[i].pid, SIGTERM); +- srclimit_done(children[i].pipefd); +- child_close(&(children[i]), 0, 0); +- break; ++ " early read", ++ i, children[i].pipefd); ++ goto problem_child; + } + if (children[i].early && c == '\0') { + /* child has finished preliminaries */ +@@ -1217,6 +1215,12 @@ server_accept_loop(int *sock_in, int *sock_out, int *newsock, int *config_s, + "child %ld for %s in state %d", + (int)c, (long)children[i].pid, + children[i].id, children[i].early); ++ problem_child: ++ if (children[i].early) ++ listening--; ++ if (children[i].pid > 0) ++ kill(children[i].pid, SIGTERM); ++ child_close(&(children[i]), 0, 0); + } + break; + } diff -Nru openssh-10.0p1/debian/patches/series openssh-10.0p1/debian/patches/series --- openssh-10.0p1/debian/patches/series 2025-08-01 15:02:27.000000000 +0000 +++ openssh-10.0p1/debian/patches/series 2026-02-03 13:15:29.000000000 +0000 @@ -26,3 +26,7 @@ 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 +fix-max-startups-tracking.patch