]> git.ipfire.org Git - thirdparty/openssh-portable.git/commitdiff
upstream: fix ownership and lifetime of several bits of client
authordjm@openbsd.org <djm@openbsd.org>
Mon, 6 Jul 2026 07:49:58 +0000 (07:49 +0000)
committerDamien Miller <djm@mindrot.org>
Mon, 6 Jul 2026 07:55:31 +0000 (17:55 +1000)
state that need to persist for the life of the connection, especially the
cached hostkey that was being incorrectly freed early on some paths, possibly
allowing its use after free.

Reported by Zhenpeng (Leo) Lin from depthfirst.com

OpenBSD-Commit-ID: faaa6ad72e7d69d41fa8b197b606265b7d9bc73f

ssh.c
sshconnect.c
sshconnect.h
sshconnect2.c

diff --git a/ssh.c b/ssh.c
index 5a160c8c1352e26a3678f089ef0315cc124a702a..7c644c23c2140aacbd9b86b402dcb215374c586f 100644 (file)
--- a/ssh.c
+++ b/ssh.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh.c,v 1.633 2026/06/14 03:59:34 djm Exp $ */
+/* $OpenBSD: ssh.c,v 1.634 2026/07/06 07:49:58 djm Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -613,26 +613,6 @@ set_addrinfo_port(struct addrinfo *addrs, int port)
        }
 }
 
-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.
  */
@@ -1803,8 +1783,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) {
index 2fc1f6026eb2816e7434f7735a2b507ee7351a99..0ddfc76b367ba71342419f0c48641eda323cdb76 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: sshconnect.c,v 1.383 2026/06/14 03:59:34 djm Exp $ */
+/* $OpenBSD: sshconnect.c,v 1.384 2026/07/06 07:49:58 djm Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -70,6 +70,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,
@@ -1585,8 +1628,8 @@ warn_nonpq_kex(void)
  */
 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;
index 4c19490da487ab3f974eb71e9de19b851d2e6c1c..2ac2c07e005a128c3b19c8b599db4bb7ca583f2f 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: sshconnect.h,v 1.50 2026/02/13 01:04:47 jsg Exp $ */
+/* $OpenBSD: sshconnect.h,v 1.51 2026/07/06 07:49:58 djm Exp $ */
 
 /*
  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
@@ -76,7 +76,7 @@ int    ssh_connect(struct ssh *, const char *, const char *,
 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 *,
@@ -85,7 +85,7 @@ int    verify_host_key(char *, struct sockaddr *, struct sshkey *,
 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 *,
@@ -101,3 +101,6 @@ void         load_hostkeys_command(struct hostkeys *, const char *,
     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 *);
index ecb4ae524ee7e8b05aca7c146efd76e59e79665e..d1555ee972743ae9bd83f2a01baf4268921c626a 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: sshconnect2.c,v 1.387 2026/06/28 23:31:28 djm Exp $ */
+/* $OpenBSD: sshconnect2.c,v 1.388 2026/07/06 07:49:58 djm Exp $ */
 /*
  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
  * Copyright (c) 2008 Damien Miller.  All rights reserved.
@@ -83,7 +83,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 *);
 
@@ -99,7 +99,7 @@ verify_host_key_callback(struct sshkey *hostkey, struct ssh *ssh)
                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;
@@ -216,16 +216,16 @@ order_hostkeyalgs(char *host, struct sockaddr *hostaddr, u_short port,
 }
 
 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;
        int r, use_known_hosts_order = 0;
 
-       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,
@@ -248,8 +248,10 @@ ssh_kex2(struct ssh *ssh, char *host, struct sockaddr *hostaddr, u_short port,
                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);
+       }
 
        kex_proposal_populate_entries(ssh, myproposal,
            options.kex_algorithms, options.ciphers, options.macs,