From 1c775f820398f265d97da958814b34660edee2bd Mon Sep 17 00:00:00 2001 From: Zoltan Fridrich Date: Tue, 14 Jul 2026 12:14:44 +0200 Subject: [PATCH] Fix CVE-2026-60002 Fix use-after-free in cached hostkey during key re-exchange Resolves: RHEL-193015 Signed-off-by: Zoltan Fridrich --- openssh-9.9p1-cve-2026-60002.patch | 191 +++++++++++++++++++++++++++++ openssh.spec | 5 + 2 files changed, 196 insertions(+) create mode 100644 openssh-9.9p1-cve-2026-60002.patch diff --git a/openssh-9.9p1-cve-2026-60002.patch b/openssh-9.9p1-cve-2026-60002.patch new file mode 100644 index 0000000..ab16479 --- /dev/null +++ b/openssh-9.9p1-cve-2026-60002.patch @@ -0,0 +1,191 @@ +diff --color -ruNp a/ssh.c b/ssh.c +--- a/ssh.c 2026-07-14 11:58:09.036496915 +0200 ++++ b/ssh.c 2026-07-14 12:00:55.044542741 +0200 +@@ -619,26 +619,6 @@ set_addrinfo_port(struct addrinfo *addrs + } + } + +-static void +-ssh_conn_info_free(struct ssh_conn_info *cinfo) +-{ +- if (cinfo == NULL) +- return; +- free(cinfo->conn_hash_hex); +- free(cinfo->shorthost); +- free(cinfo->uidstr); +- free(cinfo->keyalias); +- free(cinfo->thishost); +- free(cinfo->host_arg); +- free(cinfo->portstr); +- free(cinfo->remhost); +- free(cinfo->remuser); +- free(cinfo->homedir); +- free(cinfo->locuser); +- free(cinfo->jmphost); +- free(cinfo); +-} +- + /* + * Main program for the ssh client. + */ +@@ -1765,8 +1745,8 @@ main(int ac, char **av) + ssh_signal(SIGCHLD, main_sigchld_handler); + + /* Log into the remote system. Never returns if the login fails. */ +- ssh_login(ssh, &sensitive_data, host, (struct sockaddr *)&hostaddr, +- options.port, pw, timeout_ms, cinfo); ++ ssh_login(ssh, &sensitive_data, host, &hostaddr, options.port, ++ pw, timeout_ms, cinfo); + + /* We no longer need the private host keys. Clear them now. */ + if (sensitive_data.nkeys != 0) { +diff --color -ruNp a/sshconnect2.c b/sshconnect2.c +--- a/sshconnect2.c 2026-07-14 11:58:09.031477028 +0200 ++++ b/sshconnect2.c 2026-07-14 12:01:56.374803123 +0200 +@@ -89,7 +89,7 @@ extern Options options; + */ + + static char *xxx_host; +-static struct sockaddr *xxx_hostaddr; ++static struct sockaddr_storage xxx_hostaddr; + static const struct ssh_conn_info *xxx_conn_info; + static int key_type_allowed(struct sshkey *, const char *); + +@@ -105,7 +105,7 @@ verify_host_key_callback(struct sshkey * + fatal("Server host key %s not in HostKeyAlgorithms", + sshkey_ssh_name(hostkey)); + } +- if (verify_host_key(xxx_host, xxx_hostaddr, hostkey, ++ if (verify_host_key(xxx_host, (struct sockaddr *)&xxx_hostaddr, hostkey, + xxx_conn_info) != 0) + fatal("Host key verification failed."); + return 0; +@@ -222,8 +222,8 @@ order_hostkeyalgs(char *host, struct soc + } + + void +-ssh_kex2(struct ssh *ssh, char *host, struct sockaddr *hostaddr, u_short port, +- const struct ssh_conn_info *cinfo) ++ssh_kex2(struct ssh *ssh, char *host, struct sockaddr_storage *hostaddr, ++ u_short port, const struct ssh_conn_info *cinfo) + { + char *myproposal[PROPOSAL_MAX]; + char *all_key, *hkalgs = NULL, *filtered_algs = NULL; +@@ -234,9 +234,9 @@ ssh_kex2(struct ssh *ssh, char *host, st + char *gss_host = NULL; + #endif + +- xxx_host = host; +- xxx_hostaddr = hostaddr; +- xxx_conn_info = cinfo; ++ xxx_host = xstrdup(host); ++ xxx_hostaddr = *hostaddr; ++ xxx_conn_info = ssh_conn_info_dup(cinfo); + + if (options.rekey_limit || options.rekey_interval) + ssh_packet_set_rekey_limits(ssh, options.rekey_limit, +@@ -259,8 +259,10 @@ ssh_kex2(struct ssh *ssh, char *host, st + fatal_fr(r, "kex_assemble_namelist"); + free(all_key); + +- if (use_known_hosts_order) +- hkalgs = order_hostkeyalgs(host, hostaddr, port, cinfo); ++ if (use_known_hosts_order) { ++ hkalgs = order_hostkeyalgs(host, (struct sockaddr *)hostaddr, ++ port, cinfo); ++ } + + filtered_algs = hkalgs ? match_filter_allowlist(hkalgs, options.pubkey_accepted_algos) + : match_filter_allowlist(options.hostkeyalgorithms, +diff --color -ruNp a/sshconnect.c b/sshconnect.c +--- a/sshconnect.c 2026-07-14 11:58:08.892659011 +0200 ++++ b/sshconnect.c 2026-07-14 12:00:55.045767462 +0200 +@@ -84,6 +84,49 @@ extern char *__progname; + static int show_other_keys(struct hostkeys *, struct sshkey *); + static void warn_changed_key(struct sshkey *); + ++void ++ssh_conn_info_free(struct ssh_conn_info *cinfo) ++{ ++ if (cinfo == NULL) ++ return; ++ free(cinfo->conn_hash_hex); ++ free(cinfo->shorthost); ++ free(cinfo->uidstr); ++ free(cinfo->keyalias); ++ free(cinfo->thishost); ++ free(cinfo->host_arg); ++ free(cinfo->portstr); ++ free(cinfo->remhost); ++ free(cinfo->remuser); ++ free(cinfo->homedir); ++ free(cinfo->locuser); ++ free(cinfo->jmphost); ++ freezero(cinfo, sizeof(*cinfo)); ++} ++ ++struct ssh_conn_info * ++ssh_conn_info_dup(const struct ssh_conn_info *cinfo) ++{ ++ struct ssh_conn_info *ret; ++ ++ if (cinfo == NULL) ++ return NULL; ++ ret = xcalloc(1, sizeof(*ret)); ++ ret->conn_hash_hex = xstrdup(cinfo->conn_hash_hex); ++ ret->shorthost = xstrdup(cinfo->shorthost); ++ ret->uidstr = xstrdup(cinfo->uidstr); ++ ret->keyalias = xstrdup(cinfo->keyalias); ++ ret->thishost = xstrdup(cinfo->thishost); ++ ret->host_arg = xstrdup(cinfo->host_arg); ++ ret->portstr = xstrdup(cinfo->portstr); ++ ret->remhost = xstrdup(cinfo->remhost); ++ ret->remuser = xstrdup(cinfo->remuser); ++ ret->homedir = xstrdup(cinfo->homedir); ++ ret->locuser = xstrdup(cinfo->locuser); ++ ret->jmphost = xstrdup(cinfo->jmphost); ++ return ret; ++} ++ + /* Expand a proxy command */ + static char * + expand_proxy_command(const char *proxy_command, const char *user, +@@ -1589,8 +1632,8 @@ out: + */ + void + ssh_login(struct ssh *ssh, Sensitive *sensitive, const char *orighost, +- struct sockaddr *hostaddr, u_short port, struct passwd *pw, int timeout_ms, +- const struct ssh_conn_info *cinfo) ++ struct sockaddr_storage *hostaddr, u_short port, struct passwd *pw, ++ int timeout_ms, const struct ssh_conn_info *cinfo) + { + char *host; + char *server_user, *local_user; +diff --color -ruNp a/sshconnect.h b/sshconnect.h +--- a/sshconnect.h 2024-09-20 00:20:48.000000000 +0200 ++++ b/sshconnect.h 2026-07-14 12:00:55.045948953 +0200 +@@ -73,7 +73,7 @@ int ssh_connect(struct ssh *, const cha + void ssh_kill_proxy_command(void); + + void ssh_login(struct ssh *, Sensitive *, const char *, +- struct sockaddr *, u_short, struct passwd *, int, ++ struct sockaddr_storage *, u_short, struct passwd *, int, + const struct ssh_conn_info *); + + int verify_host_key(char *, struct sockaddr *, struct sshkey *, +@@ -82,7 +82,7 @@ int verify_host_key(char *, struct sock + void get_hostfile_hostname_ipaddr(char *, struct sockaddr *, u_short, + char **, char **); + +-void ssh_kex2(struct ssh *ssh, char *, struct sockaddr *, u_short, ++void ssh_kex2(struct ssh *ssh, char *, struct sockaddr_storage *, u_short, + const struct ssh_conn_info *); + + void ssh_userauth2(struct ssh *ssh, const char *, const char *, +@@ -98,3 +98,6 @@ void load_hostkeys_command(struct hostk + const struct sshkey *, const char *); + + int hostkey_accepted_by_hostkeyalgs(const struct sshkey *); ++ ++void ssh_conn_info_free(struct ssh_conn_info *); ++struct ssh_conn_info *ssh_conn_info_dup(const struct ssh_conn_info *); diff --git a/openssh.spec b/openssh.spec index c1254a1..c082bda 100644 --- a/openssh.spec +++ b/openssh.spec @@ -254,6 +254,8 @@ Patch1043: openssh-9.9p1-authorized-keys-principles-option.patch Patch1044: openssh-9.9p1-proxyjump-username-validity-checks.patch # upstream 36480181fa22f98e180b4f9e10203480c0346c78 Patch1045: openssh-9.9p1-scp-remote-glob.patch +# upstream e8bdfb151a356d0171fea4194dd205fbb252be23 +Patch1046: openssh-9.9p1-cve-2026-60002.patch License: BSD-3-Clause AND BSD-2-Clause AND ISC AND SSH-OpenSSH AND ssh-keyscan AND snprintf AND LicenseRef-Fedora-Public-Domain AND X11-distribute-modifications-variant Requires: /sbin/nologin @@ -463,6 +465,7 @@ gpgv2 --quiet --keyring %{SOURCE3} %{SOURCE1} %{SOURCE0} %patch -P 1043 -p1 -b .authorized-keys-principles-option %patch -P 1044 -p1 -b .proxyjump-username-validity-checks %patch -P 1045 -p1 -b .scp-remote-glob +%patch -P 1046 -p1 -b .cve-2026-60002 %patch -P 100 -p1 -b .coverity @@ -757,6 +760,8 @@ test -f %{sysconfig_anaconda} && \ in unintended parent directories when scp performs remote-to-remote copy via the local host Resolves: RHEL-193172 +- CVE-2026-60002: Fix use-after-free in cached hostkey during key re-exchange + Resolves: RHEL-193015 * Tue Apr 14 2026 Dmitry Belyavskiy - 9.9p1-26 - Improve keytab detection when obtaining Kerberos tickets on behalf of user on SSH authentication