From 266174a6d36687b65cf90174f06af90b8b27c65f Mon Sep 17 00:00:00 2001
From: Francesco Rollo <eferollo@gmail.com>
Date: Thu, 24 Jul 2025 16:30:07 +0300
Subject: [PATCH] CVE-2025-8277: Fix memory leak of unused ephemeral key pair
 after client's wrong KEX guess

Signed-off-by: Francesco Rollo <eferollo@gmail.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit ccff22d3787c1355b3f0dcd09fe54d90acc55bf1)

Changes in file 'src/ecdh_crypto.c' excluded.
The relevant changes in `ecdh_crypto.c` are located within the function `static ssh_string ssh_ecdh_generate`. This function, however, is not present in the `libssh-0.10.6` version. It was introduced in `libssh` version 0.11 by the commit  `https://git.libssh.org/projects/libssh.git/commit/src/ecdh_crypto.c?h=stable-0.11&id=1eb3df5254a4348eae6edbc8a2bf08fef4015897`.

Consequently, these changes cannot be directly applied to the `libssh-0.10.6` version. This aligns with the approach taken by other distributions, as Suse also did not backport the `ecdh_crypto.c` file changes in their `libssh-0.10.6-3.1.src.rpm` package, which is available at `https://cdimage.debian.org/mirror/opensuse.org/distribution/leap-micro/6.0/product/repo/openSUSE-Leap-Micro-6.0-x86_64-Media3/src/libssh-0.10.6-3.1.src.rpm`.

Upstream-Status: Backport [https://git.libssh.org/projects/libssh.git/commit/?h=stable-0.11&id=266174a6d36687b65cf90174f06af90b8b27c65f]
CVE: CVE-2025-8277
Signed-off-by: Vijay Anusuri <vanusuri@mvista.com>
---
 src/dh_crypto.c       | 5 +++++
 src/dh_key.c          | 5 +++++
 src/ecdh_gcrypt.c     | 6 ++++++
 src/ecdh_mbedcrypto.c | 6 ++++++
 4 files changed, 22 insertions(+)

diff --git a/src/dh_crypto.c b/src/dh_crypto.c
index 4dd9b507..cedfbc81 100644
--- a/src/dh_crypto.c
+++ b/src/dh_crypto.c
@@ -407,6 +407,11 @@ int ssh_dh_init_common(struct ssh_crypto_struct *crypto)
     struct dh_ctx *ctx = NULL;
     int rc;
 
+    /* Cleanup any previously allocated dh_ctx */
+    if (crypto->dh_ctx != NULL) {
+        ssh_dh_cleanup(crypto);
+    }
+
     ctx = calloc(1, sizeof(*ctx));
     if (ctx == NULL) {
         return SSH_ERROR;
diff --git a/src/dh_key.c b/src/dh_key.c
index 20d24a31..d9743ceb 100644
--- a/src/dh_key.c
+++ b/src/dh_key.c
@@ -237,6 +237,11 @@ int ssh_dh_init_common(struct ssh_crypto_struct *crypto)
     struct dh_ctx *ctx = NULL;
     int rc;
 
+    /* Cleanup any previously allocated dh_ctx */
+    if (crypto->dh_ctx != NULL) {
+        ssh_dh_cleanup(crypto);
+    }
+
     ctx = calloc(1, sizeof(*ctx));
     if (ctx == NULL) {
         return SSH_ERROR;
diff --git a/src/ecdh_gcrypt.c b/src/ecdh_gcrypt.c
index 73fcd50f..b8d983c1 100644
--- a/src/ecdh_gcrypt.c
+++ b/src/ecdh_gcrypt.c
@@ -101,6 +101,12 @@ int ssh_client_ecdh_init(ssh_session session)
         goto out;
     }
 
+    /* Free any previously allocated privkey */
+    if (session->next_crypto->ecdh_privkey != NULL) {
+        gcry_sexp_release(session->next_crypto->ecdh_privkey);
+        session->next_crypto->ecdh_privkey = NULL;
+    }
+
     session->next_crypto->ecdh_privkey = key;
     key = NULL;
     session->next_crypto->ecdh_client_pubkey = client_pubkey;
diff --git a/src/ecdh_mbedcrypto.c b/src/ecdh_mbedcrypto.c
index dda73922..6074b93d 100644
--- a/src/ecdh_mbedcrypto.c
+++ b/src/ecdh_mbedcrypto.c
@@ -70,6 +70,12 @@ int ssh_client_ecdh_init(ssh_session session)
         return SSH_ERROR;
     }
 
+    /* Free any previously allocated privkey */
+    if (session->next_crypto->ecdh_privkey != NULL) {
+        mbedtls_ecp_keypair_free(session->next_crypto->ecdh_privkey);
+        SAFE_FREE(session->next_crypto->ecdh_privkey);
+    }
+
     session->next_crypto->ecdh_privkey = malloc(sizeof(mbedtls_ecp_keypair));
     if (session->next_crypto->ecdh_privkey == NULL) {
         return SSH_ERROR;
-- 
2.25.1

