public inbox for openembedded-devel@lists.openembedded.org
 help / color / mirror / Atom feed
* [oe][meta-oe][whinlatter][PATCH 3/3] libssh: Fix CVE-2026-0965
@ 2026-04-06 11:55 Deepak Rathore -X (deeratho - E INFOCHIPS PRIVATE LIMITED at Cisco)
  2026-04-08  5:19 ` Ankur Tyagi
  0 siblings, 1 reply; 5+ messages in thread
From: Deepak Rathore -X (deeratho - E INFOCHIPS PRIVATE LIMITED at Cisco) @ 2026-04-06 11:55 UTC (permalink / raw)
  To: openembedded-devel

From: Deepak Rathore <deeratho@cisco.com>

Pick the patch [1] as mentioned in [2]

[1] https://git.libssh.org/projects/libssh.git/commit/?id=bf390a042623e02abc8f421c4c5fadc0429a8a76
[2] https://security-tracker.debian.org/tracker/CVE-2026-0965

Signed-off-by: Deepak Rathore <deeratho@cisco.com>
---
 .../libssh/libssh/CVE-2026-0965.patch         | 286 ++++++++++++++++++
 .../recipes-support/libssh/libssh_0.11.3.bb   |   1 +
 2 files changed, 287 insertions(+)
 create mode 100644 meta-oe/recipes-support/libssh/libssh/CVE-2026-0965.patch

diff --git a/meta-oe/recipes-support/libssh/libssh/CVE-2026-0965.patch b/meta-oe/recipes-support/libssh/libssh/CVE-2026-0965.patch
new file mode 100644
index 0000000000..57cb9d6170
--- /dev/null
+++ b/meta-oe/recipes-support/libssh/libssh/CVE-2026-0965.patch
@@ -0,0 +1,286 @@
+From 5858a988942d2e25985b34b8c40ce2792cbbe853 Mon Sep 17 00:00:00 2001
+From: Jakub Jelen <jjelen@redhat.com>
+Date: Thu, 11 Dec 2025 17:33:19 +0100
+Subject: [PATCH 4/4] CVE-2026-0965 config: Do not attempt to read non-regular
+ and too large configuration files
+
+Changes also the reading of known_hosts to use the new helper function
+
+CVE: CVE-2026-0965
+Upstream-Status: Backport [https://git.libssh.org/projects/libssh.git/commit/?id=bf390a042623e02abc8f421c4c5fadc0429a8a76]
+
+Signed-off-by: Jakub Jelen <jjelen@redhat.com>
+Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
+(cherry picked from commit a5eb30dbfd8f3526b2d04bd9f0a3803b665f5798)
+(cherry picked from commit bf390a042623e02abc8f421c4c5fadc0429a8a76)
+Signed-off-by: Deepak Rathore <deeratho@cisco.com>
+---
+ include/libssh/misc.h            |  3 ++
+ include/libssh/priv.h            |  3 ++
+ src/bind_config.c                |  4 +-
+ src/config.c                     |  8 ++--
+ src/dh-gex.c                     |  4 +-
+ src/known_hosts.c                |  2 +-
+ src/knownhosts.c                 |  2 +-
+ src/misc.c                       | 74 ++++++++++++++++++++++++++++++++
+ tests/unittests/torture_config.c | 20 +++++++++
+ 9 files changed, 110 insertions(+), 10 deletions(-)
+
+diff --git a/include/libssh/misc.h b/include/libssh/misc.h
+index ab726a0e..8eab94ee 100644
+--- a/include/libssh/misc.h
++++ b/include/libssh/misc.h
+@@ -36,6 +36,7 @@
+ #include <sys/types.h>
+ #include <stdbool.h>
+ #endif /* _WIN32 */
++#include <stdio.h>
+ 
+ #ifdef __cplusplus
+ extern "C" {
+@@ -136,6 +137,8 @@ int ssh_check_username_syntax(const char *username);
+ void ssh_proxyjumps_free(struct ssh_list *proxy_jump_list);
+ bool ssh_libssh_proxy_jumps(void);
+ 
++FILE *ssh_strict_fopen(const char *filename, size_t max_file_size);
++
+ #ifdef __cplusplus
+ }
+ #endif
+diff --git a/include/libssh/priv.h b/include/libssh/priv.h
+index 35fd8506..62069970 100644
+--- a/include/libssh/priv.h
++++ b/include/libssh/priv.h
+@@ -473,6 +473,9 @@ char *ssh_strerror(int err_num, char *buf, size_t buflen);
+ #define SSH_TTY_MODES_MAX_BUFSIZE   (55 * 5 + 1)
+ int encode_current_tty_opts(unsigned char *buf, size_t buflen);
+ 
++/** The default maximum file size for a configuration file */
++#define SSH_MAX_CONFIG_FILE_SIZE 16 * 1024 * 1024
++
+ #ifdef __cplusplus
+ }
+ #endif
+diff --git a/src/bind_config.c b/src/bind_config.c
+index 9e4a7fd4..c12f1003 100644
+--- a/src/bind_config.c
++++ b/src/bind_config.c
+@@ -212,7 +212,7 @@ local_parse_file(ssh_bind bind,
+         return;
+     }
+ 
+-    f = fopen(filename, "r");
++    f = ssh_strict_fopen(filename, SSH_MAX_CONFIG_FILE_SIZE);
+     if (f == NULL) {
+         SSH_LOG(SSH_LOG_RARE, "Cannot find file %s to load",
+                 filename);
+@@ -636,7 +636,7 @@ int ssh_bind_config_parse_file(ssh_bind bind, const char *filename)
+      * option to be redefined later by another file. */
+     uint8_t seen[BIND_CFG_MAX] = {0};
+ 
+-    f = fopen(filename, "r");
++    f = ssh_strict_fopen(filename, SSH_MAX_CONFIG_FILE_SIZE);
+     if (f == NULL) {
+         return 0;
+     }
+diff --git a/src/config.c b/src/config.c
+index b4171efd..1ffad537 100644
+--- a/src/config.c
++++ b/src/config.c
+@@ -223,10 +223,9 @@ local_parse_file(ssh_session session,
+         return;
+     }
+ 
+-    f = fopen(filename, "r");
++    f = ssh_strict_fopen(filename, SSH_MAX_CONFIG_FILE_SIZE);
+     if (f == NULL) {
+-        SSH_LOG(SSH_LOG_RARE, "Cannot find file %s to load",
+-                filename);
++        /* The underlying function logs the reasons */
+         return;
+     }
+ 
+@@ -1466,8 +1465,9 @@ int ssh_config_parse_file(ssh_session session, const char *filename)
+     int parsing, rv;
+     bool global = 0;
+ 
+-    f = fopen(filename, "r");
++    f = ssh_strict_fopen(filename, SSH_MAX_CONFIG_FILE_SIZE);
+     if (f == NULL) {
++        /* The underlying function logs the reasons */
+         return 0;
+     }
+ 
+diff --git a/src/dh-gex.c b/src/dh-gex.c
+index 46ba934e..428a5655 100644
+--- a/src/dh-gex.c
++++ b/src/dh-gex.c
+@@ -519,9 +519,9 @@ static int ssh_retrieve_dhgroup(char *moduli_file,
+     }
+ 
+     if (moduli_file != NULL)
+-        moduli = fopen(moduli_file, "r");
++        moduli = ssh_strict_fopen(moduli_file, SSH_MAX_CONFIG_FILE_SIZE);
+     else
+-        moduli = fopen(MODULI_FILE, "r");
++        moduli = ssh_strict_fopen(MODULI_FILE, SSH_MAX_CONFIG_FILE_SIZE);
+ 
+     if (moduli == NULL) {
+         char err_msg[SSH_ERRNO_MSG_MAX] = {0};
+diff --git a/src/known_hosts.c b/src/known_hosts.c
+index 3ef83e21..701576ce 100644
+--- a/src/known_hosts.c
++++ b/src/known_hosts.c
+@@ -83,7 +83,7 @@ static struct ssh_tokens_st *ssh_get_knownhost_line(FILE **file,
+     struct ssh_tokens_st *tokens = NULL;
+ 
+     if (*file == NULL) {
+-        *file = fopen(filename,"r");
++        *file = ssh_strict_fopen(filename, SSH_MAX_CONFIG_FILE_SIZE);
+         if (*file == NULL) {
+             return NULL;
+         }
+diff --git a/src/knownhosts.c b/src/knownhosts.c
+index a2d08a75..3ab468de 100644
+--- a/src/knownhosts.c
++++ b/src/knownhosts.c
+@@ -232,7 +232,7 @@ static int ssh_known_hosts_read_entries(const char *match,
+     FILE *fp = NULL;
+     int rc;
+ 
+-    fp = fopen(filename, "r");
++    fp = ssh_strict_fopen(filename, SSH_MAX_CONFIG_FILE_SIZE);
+     if (fp == NULL) {
+         char err_msg[SSH_ERRNO_MSG_MAX] = {0};
+         SSH_LOG(SSH_LOG_TRACE, "Failed to open the known_hosts file '%s': %s",
+diff --git a/src/misc.c b/src/misc.c
+index 774211fb..3968e6bc 100644
+--- a/src/misc.c
++++ b/src/misc.c
+@@ -37,6 +37,7 @@
+ #endif /* _WIN32 */
+ 
+ #include <errno.h>
++#include <fcntl.h>
+ #include <limits.h>
+ #include <stdio.h>
+ #include <string.h>
+@@ -2244,4 +2245,77 @@ ssh_libssh_proxy_jumps(void)
+     return !(t != NULL && t[0] == '1');
+ }
+ 
++/**
++ * @internal
++ *
++ * @brief Safely open a file containing some configuration.
++ *
++ * Runs checks if the file can be used as some configuration file (is regular
++ * file and is not too large). If so, returns the opened file (for reading).
++ * Otherwise logs error and returns `NULL`.
++ *
++ * @param filename      The path to the file to open.
++ * @param max_file_size Maximum file size that is accepted.
++ *
++ * @returns the opened file or `NULL` on error.
++ */
++FILE *ssh_strict_fopen(const char *filename, size_t max_file_size)
++{
++    FILE *f = NULL;
++    struct stat sb;
++    char err_msg[SSH_ERRNO_MSG_MAX] = {0};
++    int r, fd;
++
++    /* open first to avoid TOCTOU */
++    fd = open(filename, O_RDONLY);
++    if (fd == -1) {
++        SSH_LOG(SSH_LOG_RARE,
++                "Failed to open a file %s for reading: %s",
++                filename,
++                ssh_strerror(errno, err_msg, SSH_ERRNO_MSG_MAX));
++        return NULL;
++    }
++
++    /* Check the file is sensible for a configuration file */
++    r = fstat(fd, &sb);
++    if (r != 0) {
++        SSH_LOG(SSH_LOG_RARE,
++                "Failed to stat %s: %s",
++                filename,
++                ssh_strerror(errno, err_msg, SSH_ERRNO_MSG_MAX));
++        close(fd);
++        return NULL;
++    }
++    if ((sb.st_mode & S_IFMT) != S_IFREG) {
++        SSH_LOG(SSH_LOG_RARE,
++                "The file %s is not a regular file: skipping",
++                filename);
++        close(fd);
++        return NULL;
++    }
++
++    if ((size_t)sb.st_size > max_file_size) {
++        SSH_LOG(SSH_LOG_RARE,
++                "The file %s is too large (%jd MB > %zu MB): skipping",
++                filename,
++                (intmax_t)sb.st_size / 1024 / 1024,
++                max_file_size / 1024 / 1024);
++        close(fd);
++        return NULL;
++    }
++
++    f = fdopen(fd, "r");
++    if (f == NULL) {
++        SSH_LOG(SSH_LOG_RARE,
++                "Failed to open a file %s for reading: %s",
++                filename,
++                ssh_strerror(r, err_msg, SSH_ERRNO_MSG_MAX));
++        close(fd);
++        return NULL;
++    }
++
++    /* the flcose() will close also the underlying fd */
++    return f;
++}
++
+ /** @} */
+diff --git a/tests/unittests/torture_config.c b/tests/unittests/torture_config.c
+index fcfe8fbc..0cb31a76 100644
+--- a/tests/unittests/torture_config.c
++++ b/tests/unittests/torture_config.c
+@@ -2675,6 +2675,23 @@ static void torture_config_match_complex(void **state)
+     ssh_string_free_char(v);
+ }
+ 
++/* Invalid configuration files
++ */
++static void torture_config_invalid(void **state)
++{
++    ssh_session session = *state;
++
++    ssh_options_set(session, SSH_OPTIONS_HOST, "Bar");
++
++    /* non-regular file -- ignored (or missing on non-unix) so OK */
++    _parse_config(session, "/dev/random", NULL, SSH_OK);
++
++#ifndef _WIN32
++    /* huge file -- ignored (or missing on non-unix) so OK */
++    _parse_config(session, "/proc/kcore", NULL, SSH_OK);
++#endif
++}
++
+ int torture_run_tests(void)
+ {
+     int rc;
+@@ -2771,6 +2788,9 @@ int torture_run_tests(void)
+                                         setup, teardown),
+         cmocka_unit_test_setup_teardown(torture_config_match_complex,
+                                         setup, teardown),
++        cmocka_unit_test_setup_teardown(torture_config_invalid,
++                                        setup,
++                                        teardown),
+     };
+ 
+ 
+-- 
+2.51.0
+
diff --git a/meta-oe/recipes-support/libssh/libssh_0.11.3.bb b/meta-oe/recipes-support/libssh/libssh_0.11.3.bb
index 193ff3512d..c552692bde 100644
--- a/meta-oe/recipes-support/libssh/libssh_0.11.3.bb
+++ b/meta-oe/recipes-support/libssh/libssh_0.11.3.bb
@@ -14,6 +14,7 @@ SRC_URI = "git://git.libssh.org/projects/libssh.git;protocol=https;branch=stable
            file://CVE-2026-0968_p1.patch \
            file://CVE-2026-0968_p2.patch \
            file://CVE-2026-0967.patch \
+           file://CVE-2026-0965.patch \
           "
 
 SRC_URI:append:toolchain-clang = " file://0001-CompilerChecks.cmake-drop-Wunused-variable-flag.patch"
-- 
2.35.6



^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [oe][meta-oe][whinlatter][PATCH 3/3] libssh: Fix CVE-2026-0965
  2026-04-06 11:55 [oe][meta-oe][whinlatter][PATCH 3/3] libssh: Fix CVE-2026-0965 Deepak Rathore -X (deeratho - E INFOCHIPS PRIVATE LIMITED at Cisco)
@ 2026-04-08  5:19 ` Ankur Tyagi
  2026-04-09  4:25   ` [meta-oe][whinlatter][PATCH " Deepak Rathore
  0 siblings, 1 reply; 5+ messages in thread
From: Ankur Tyagi @ 2026-04-08  5:19 UTC (permalink / raw)
  To: deeratho; +Cc: openembedded-devel

I think we can upgrade to v0.11.4

https://git.libssh.org/projects/libssh.git/tree/CHANGELOG?h=stable-0.11

version 0.11.4 (released 2026-02-10)
 * Security:
   * CVE-2025-14821: libssh loads configuration files from the C:\etc directory
     on Windows
   * CVE-2026-0964: SCP Protocol Path Traversal in ssh_scp_pull_request()
   * CVE-2026-0965: Possible Denial of Service when parsing unexpected
     configuration files
   * CVE-2026-0966: Buffer underflow in ssh_get_hexa() on invalid input
   * CVE-2026-0967: Specially crafted patterns could cause DoS
   * CVE-2026-0968: OOB Read in sftp_parse_longname()
   * libssh-2026-sftp-extensions: Read buffer overrun when handling SFTP
     extensions
 * Stability and compatibility improvements of ProxyJum



On Mon, Apr 6, 2026 at 11:56 PM Deepak Rathore via
lists.openembedded.org <deeratho=cisco.com@lists.openembedded.org>
wrote:
>
> From: Deepak Rathore <deeratho@cisco.com>
>
> Pick the patch [1] as mentioned in [2]
>
> [1] https://git.libssh.org/projects/libssh.git/commit/?id=bf390a042623e02abc8f421c4c5fadc0429a8a76
> [2] https://security-tracker.debian.org/tracker/CVE-2026-0965
>
> Signed-off-by: Deepak Rathore <deeratho@cisco.com>
> ---
>  .../libssh/libssh/CVE-2026-0965.patch         | 286 ++++++++++++++++++
>  .../recipes-support/libssh/libssh_0.11.3.bb   |   1 +
>  2 files changed, 287 insertions(+)
>  create mode 100644 meta-oe/recipes-support/libssh/libssh/CVE-2026-0965.patch
>
> diff --git a/meta-oe/recipes-support/libssh/libssh/CVE-2026-0965.patch b/meta-oe/recipes-support/libssh/libssh/CVE-2026-0965.patch
> new file mode 100644
> index 0000000000..57cb9d6170
> --- /dev/null
> +++ b/meta-oe/recipes-support/libssh/libssh/CVE-2026-0965.patch
> @@ -0,0 +1,286 @@
> +From 5858a988942d2e25985b34b8c40ce2792cbbe853 Mon Sep 17 00:00:00 2001
> +From: Jakub Jelen <jjelen@redhat.com>
> +Date: Thu, 11 Dec 2025 17:33:19 +0100
> +Subject: [PATCH 4/4] CVE-2026-0965 config: Do not attempt to read non-regular
> + and too large configuration files
> +
> +Changes also the reading of known_hosts to use the new helper function
> +
> +CVE: CVE-2026-0965
> +Upstream-Status: Backport [https://git.libssh.org/projects/libssh.git/commit/?id=bf390a042623e02abc8f421c4c5fadc0429a8a76]
> +
> +Signed-off-by: Jakub Jelen <jjelen@redhat.com>
> +Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
> +(cherry picked from commit a5eb30dbfd8f3526b2d04bd9f0a3803b665f5798)
> +(cherry picked from commit bf390a042623e02abc8f421c4c5fadc0429a8a76)
> +Signed-off-by: Deepak Rathore <deeratho@cisco.com>
> +---
> + include/libssh/misc.h            |  3 ++
> + include/libssh/priv.h            |  3 ++
> + src/bind_config.c                |  4 +-
> + src/config.c                     |  8 ++--
> + src/dh-gex.c                     |  4 +-
> + src/known_hosts.c                |  2 +-
> + src/knownhosts.c                 |  2 +-
> + src/misc.c                       | 74 ++++++++++++++++++++++++++++++++
> + tests/unittests/torture_config.c | 20 +++++++++
> + 9 files changed, 110 insertions(+), 10 deletions(-)
> +
> +diff --git a/include/libssh/misc.h b/include/libssh/misc.h
> +index ab726a0e..8eab94ee 100644
> +--- a/include/libssh/misc.h
> ++++ b/include/libssh/misc.h
> +@@ -36,6 +36,7 @@
> + #include <sys/types.h>
> + #include <stdbool.h>
> + #endif /* _WIN32 */
> ++#include <stdio.h>
> +
> + #ifdef __cplusplus
> + extern "C" {
> +@@ -136,6 +137,8 @@ int ssh_check_username_syntax(const char *username);
> + void ssh_proxyjumps_free(struct ssh_list *proxy_jump_list);
> + bool ssh_libssh_proxy_jumps(void);
> +
> ++FILE *ssh_strict_fopen(const char *filename, size_t max_file_size);
> ++
> + #ifdef __cplusplus
> + }
> + #endif
> +diff --git a/include/libssh/priv.h b/include/libssh/priv.h
> +index 35fd8506..62069970 100644
> +--- a/include/libssh/priv.h
> ++++ b/include/libssh/priv.h
> +@@ -473,6 +473,9 @@ char *ssh_strerror(int err_num, char *buf, size_t buflen);
> + #define SSH_TTY_MODES_MAX_BUFSIZE   (55 * 5 + 1)
> + int encode_current_tty_opts(unsigned char *buf, size_t buflen);
> +
> ++/** The default maximum file size for a configuration file */
> ++#define SSH_MAX_CONFIG_FILE_SIZE 16 * 1024 * 1024
> ++
> + #ifdef __cplusplus
> + }
> + #endif
> +diff --git a/src/bind_config.c b/src/bind_config.c
> +index 9e4a7fd4..c12f1003 100644
> +--- a/src/bind_config.c
> ++++ b/src/bind_config.c
> +@@ -212,7 +212,7 @@ local_parse_file(ssh_bind bind,
> +         return;
> +     }
> +
> +-    f = fopen(filename, "r");
> ++    f = ssh_strict_fopen(filename, SSH_MAX_CONFIG_FILE_SIZE);
> +     if (f == NULL) {
> +         SSH_LOG(SSH_LOG_RARE, "Cannot find file %s to load",
> +                 filename);
> +@@ -636,7 +636,7 @@ int ssh_bind_config_parse_file(ssh_bind bind, const char *filename)
> +      * option to be redefined later by another file. */
> +     uint8_t seen[BIND_CFG_MAX] = {0};
> +
> +-    f = fopen(filename, "r");
> ++    f = ssh_strict_fopen(filename, SSH_MAX_CONFIG_FILE_SIZE);
> +     if (f == NULL) {
> +         return 0;
> +     }
> +diff --git a/src/config.c b/src/config.c
> +index b4171efd..1ffad537 100644
> +--- a/src/config.c
> ++++ b/src/config.c
> +@@ -223,10 +223,9 @@ local_parse_file(ssh_session session,
> +         return;
> +     }
> +
> +-    f = fopen(filename, "r");
> ++    f = ssh_strict_fopen(filename, SSH_MAX_CONFIG_FILE_SIZE);
> +     if (f == NULL) {
> +-        SSH_LOG(SSH_LOG_RARE, "Cannot find file %s to load",
> +-                filename);
> ++        /* The underlying function logs the reasons */
> +         return;
> +     }
> +
> +@@ -1466,8 +1465,9 @@ int ssh_config_parse_file(ssh_session session, const char *filename)
> +     int parsing, rv;
> +     bool global = 0;
> +
> +-    f = fopen(filename, "r");
> ++    f = ssh_strict_fopen(filename, SSH_MAX_CONFIG_FILE_SIZE);
> +     if (f == NULL) {
> ++        /* The underlying function logs the reasons */
> +         return 0;
> +     }
> +
> +diff --git a/src/dh-gex.c b/src/dh-gex.c
> +index 46ba934e..428a5655 100644
> +--- a/src/dh-gex.c
> ++++ b/src/dh-gex.c
> +@@ -519,9 +519,9 @@ static int ssh_retrieve_dhgroup(char *moduli_file,
> +     }
> +
> +     if (moduli_file != NULL)
> +-        moduli = fopen(moduli_file, "r");
> ++        moduli = ssh_strict_fopen(moduli_file, SSH_MAX_CONFIG_FILE_SIZE);
> +     else
> +-        moduli = fopen(MODULI_FILE, "r");
> ++        moduli = ssh_strict_fopen(MODULI_FILE, SSH_MAX_CONFIG_FILE_SIZE);
> +
> +     if (moduli == NULL) {
> +         char err_msg[SSH_ERRNO_MSG_MAX] = {0};
> +diff --git a/src/known_hosts.c b/src/known_hosts.c
> +index 3ef83e21..701576ce 100644
> +--- a/src/known_hosts.c
> ++++ b/src/known_hosts.c
> +@@ -83,7 +83,7 @@ static struct ssh_tokens_st *ssh_get_knownhost_line(FILE **file,
> +     struct ssh_tokens_st *tokens = NULL;
> +
> +     if (*file == NULL) {
> +-        *file = fopen(filename,"r");
> ++        *file = ssh_strict_fopen(filename, SSH_MAX_CONFIG_FILE_SIZE);
> +         if (*file == NULL) {
> +             return NULL;
> +         }
> +diff --git a/src/knownhosts.c b/src/knownhosts.c
> +index a2d08a75..3ab468de 100644
> +--- a/src/knownhosts.c
> ++++ b/src/knownhosts.c
> +@@ -232,7 +232,7 @@ static int ssh_known_hosts_read_entries(const char *match,
> +     FILE *fp = NULL;
> +     int rc;
> +
> +-    fp = fopen(filename, "r");
> ++    fp = ssh_strict_fopen(filename, SSH_MAX_CONFIG_FILE_SIZE);
> +     if (fp == NULL) {
> +         char err_msg[SSH_ERRNO_MSG_MAX] = {0};
> +         SSH_LOG(SSH_LOG_TRACE, "Failed to open the known_hosts file '%s': %s",
> +diff --git a/src/misc.c b/src/misc.c
> +index 774211fb..3968e6bc 100644
> +--- a/src/misc.c
> ++++ b/src/misc.c
> +@@ -37,6 +37,7 @@
> + #endif /* _WIN32 */
> +
> + #include <errno.h>
> ++#include <fcntl.h>
> + #include <limits.h>
> + #include <stdio.h>
> + #include <string.h>
> +@@ -2244,4 +2245,77 @@ ssh_libssh_proxy_jumps(void)
> +     return !(t != NULL && t[0] == '1');
> + }
> +
> ++/**
> ++ * @internal
> ++ *
> ++ * @brief Safely open a file containing some configuration.
> ++ *
> ++ * Runs checks if the file can be used as some configuration file (is regular
> ++ * file and is not too large). If so, returns the opened file (for reading).
> ++ * Otherwise logs error and returns `NULL`.
> ++ *
> ++ * @param filename      The path to the file to open.
> ++ * @param max_file_size Maximum file size that is accepted.
> ++ *
> ++ * @returns the opened file or `NULL` on error.
> ++ */
> ++FILE *ssh_strict_fopen(const char *filename, size_t max_file_size)
> ++{
> ++    FILE *f = NULL;
> ++    struct stat sb;
> ++    char err_msg[SSH_ERRNO_MSG_MAX] = {0};
> ++    int r, fd;
> ++
> ++    /* open first to avoid TOCTOU */
> ++    fd = open(filename, O_RDONLY);
> ++    if (fd == -1) {
> ++        SSH_LOG(SSH_LOG_RARE,
> ++                "Failed to open a file %s for reading: %s",
> ++                filename,
> ++                ssh_strerror(errno, err_msg, SSH_ERRNO_MSG_MAX));
> ++        return NULL;
> ++    }
> ++
> ++    /* Check the file is sensible for a configuration file */
> ++    r = fstat(fd, &sb);
> ++    if (r != 0) {
> ++        SSH_LOG(SSH_LOG_RARE,
> ++                "Failed to stat %s: %s",
> ++                filename,
> ++                ssh_strerror(errno, err_msg, SSH_ERRNO_MSG_MAX));
> ++        close(fd);
> ++        return NULL;
> ++    }
> ++    if ((sb.st_mode & S_IFMT) != S_IFREG) {
> ++        SSH_LOG(SSH_LOG_RARE,
> ++                "The file %s is not a regular file: skipping",
> ++                filename);
> ++        close(fd);
> ++        return NULL;
> ++    }
> ++
> ++    if ((size_t)sb.st_size > max_file_size) {
> ++        SSH_LOG(SSH_LOG_RARE,
> ++                "The file %s is too large (%jd MB > %zu MB): skipping",
> ++                filename,
> ++                (intmax_t)sb.st_size / 1024 / 1024,
> ++                max_file_size / 1024 / 1024);
> ++        close(fd);
> ++        return NULL;
> ++    }
> ++
> ++    f = fdopen(fd, "r");
> ++    if (f == NULL) {
> ++        SSH_LOG(SSH_LOG_RARE,
> ++                "Failed to open a file %s for reading: %s",
> ++                filename,
> ++                ssh_strerror(r, err_msg, SSH_ERRNO_MSG_MAX));
> ++        close(fd);
> ++        return NULL;
> ++    }
> ++
> ++    /* the flcose() will close also the underlying fd */
> ++    return f;
> ++}
> ++
> + /** @} */
> +diff --git a/tests/unittests/torture_config.c b/tests/unittests/torture_config.c
> +index fcfe8fbc..0cb31a76 100644
> +--- a/tests/unittests/torture_config.c
> ++++ b/tests/unittests/torture_config.c
> +@@ -2675,6 +2675,23 @@ static void torture_config_match_complex(void **state)
> +     ssh_string_free_char(v);
> + }
> +
> ++/* Invalid configuration files
> ++ */
> ++static void torture_config_invalid(void **state)
> ++{
> ++    ssh_session session = *state;
> ++
> ++    ssh_options_set(session, SSH_OPTIONS_HOST, "Bar");
> ++
> ++    /* non-regular file -- ignored (or missing on non-unix) so OK */
> ++    _parse_config(session, "/dev/random", NULL, SSH_OK);
> ++
> ++#ifndef _WIN32
> ++    /* huge file -- ignored (or missing on non-unix) so OK */
> ++    _parse_config(session, "/proc/kcore", NULL, SSH_OK);
> ++#endif
> ++}
> ++
> + int torture_run_tests(void)
> + {
> +     int rc;
> +@@ -2771,6 +2788,9 @@ int torture_run_tests(void)
> +                                         setup, teardown),
> +         cmocka_unit_test_setup_teardown(torture_config_match_complex,
> +                                         setup, teardown),
> ++        cmocka_unit_test_setup_teardown(torture_config_invalid,
> ++                                        setup,
> ++                                        teardown),
> +     };
> +
> +
> +--
> +2.51.0
> +
> diff --git a/meta-oe/recipes-support/libssh/libssh_0.11.3.bb b/meta-oe/recipes-support/libssh/libssh_0.11.3.bb
> index 193ff3512d..c552692bde 100644
> --- a/meta-oe/recipes-support/libssh/libssh_0.11.3.bb
> +++ b/meta-oe/recipes-support/libssh/libssh_0.11.3.bb
> @@ -14,6 +14,7 @@ SRC_URI = "git://git.libssh.org/projects/libssh.git;protocol=https;branch=stable
>             file://CVE-2026-0968_p1.patch \
>             file://CVE-2026-0968_p2.patch \
>             file://CVE-2026-0967.patch \
> +           file://CVE-2026-0965.patch \
>            "
>
>  SRC_URI:append:toolchain-clang = " file://0001-CompilerChecks.cmake-drop-Wunused-variable-flag.patch"
> --
> 2.35.6
>
>
> -=-=-=-=-=-=-=-=-=-=-=-
> Links: You receive all messages sent to this group.
> View/Reply Online (#126037): https://lists.openembedded.org/g/openembedded-devel/message/126037
> Mute This Topic: https://lists.openembedded.org/mt/118688803/3619737
> Group Owner: openembedded-devel+owner@lists.openembedded.org
> Unsubscribe: https://lists.openembedded.org/g/openembedded-devel/unsub [ankur.tyagi85@gmail.com]
> -=-=-=-=-=-=-=-=-=-=-=-
>


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [meta-oe][whinlatter][PATCH 3/3] libssh: Fix CVE-2026-0965
  2026-04-08  5:19 ` Ankur Tyagi
@ 2026-04-09  4:25   ` Deepak Rathore
  2026-04-09  8:26     ` [oe] " Yoann Congal
  2026-04-09  8:30     ` Gyorgy Sarvari
  0 siblings, 2 replies; 5+ messages in thread
From: Deepak Rathore @ 2026-04-09  4:25 UTC (permalink / raw)
  To: openembedded-devel

[-- Attachment #1: Type: text/plain, Size: 24776 bytes --]

Hi Ankur,

Thank you for your review and response.

As previously indicated by the maintainer in this thread ( openembedded-core@lists.openembedded.org | Inquiry Regarding Package Upgrade Approach vs. Manual CVE Fixes in LTS Releases ( https://lists.openembedded.org/g/openembedded-core/topic/118275693 ) ), package upgrades are not considered for stable and LTS branches for stability. Only bug fixes and security fixes are accepted. Accordingly, I have submitted CVE fix patches instead of performing a package upgrade.

Regards,
Deepak

On Wed, Apr 8, 2026 at 10:49 AM, Ankur Tyagi wrote:

> 
> I think we can upgrade to v0.11.4
> 
> https://git.libssh.org/projects/libssh.git/tree/CHANGELOG?h=stable-0.11
> 
> version 0.11.4 (released 2026-02-10)
> * Security:
> * CVE-2025-14821: libssh loads configuration files from the C:\etc
> directory
> on Windows
> * CVE-2026-0964: SCP Protocol Path Traversal in ssh_scp_pull_request()
> * CVE-2026-0965: Possible Denial of Service when parsing unexpected
> configuration files
> * CVE-2026-0966: Buffer underflow in ssh_get_hexa() on invalid input
> * CVE-2026-0967: Specially crafted patterns could cause DoS
> * CVE-2026-0968: OOB Read in sftp_parse_longname()
> * libssh-2026-sftp-extensions: Read buffer overrun when handling SFTP
> extensions
> * Stability and compatibility improvements of ProxyJum
> 
> 
> 
> On Mon, Apr 6, 2026 at 11:56 PM Deepak Rathore via
> lists.openembedded.org <deeratho=cisco.com@lists.openembedded.org>
> wrote:
> 
>> 
>> From: Deepak Rathore <deeratho@cisco.com>
>> 
>> Pick the patch [1] as mentioned in [2]
>> 
>> [1] https://git.libssh.org/projects/libssh.git/commit/?id=bf390a042623e02abc8f421c4c5fadc0429a8a76
>> 
>> [2] https://security-tracker.debian.org/tracker/CVE-2026-0965
>> 
>> Signed-off-by: Deepak Rathore <deeratho@cisco.com>
>> ---
>> .../libssh/libssh/CVE-2026-0965.patch | 286 ++++++++++++++++++
>> .../recipes-support/libssh/libssh_0.11.3.bb | 1 +
>> 2 files changed, 287 insertions(+)
>> create mode 100644
>> meta-oe/recipes-support/libssh/libssh/CVE-2026-0965.patch
>> 
>> diff --git a/meta-oe/recipes-support/libssh/libssh/CVE-2026-0965.patch
>> b/meta-oe/recipes-support/libssh/libssh/CVE-2026-0965.patch
>> new file mode 100644
>> index 0000000000..57cb9d6170
>> --- /dev/null
>> +++ b/meta-oe/recipes-support/libssh/libssh/CVE-2026-0965.patch
>> @@ -0,0 +1,286 @@
>> +From 5858a988942d2e25985b34b8c40ce2792cbbe853 Mon Sep 17 00:00:00 2001
>> +From: Jakub Jelen <jjelen@redhat.com>
>> +Date: Thu, 11 Dec 2025 17:33:19 +0100
>> +Subject: [PATCH 4/4] CVE-2026-0965 config: Do not attempt to read
>> non-regular
>> + and too large configuration files
>> +
>> +Changes also the reading of known_hosts to use the new helper function
>> +
>> +CVE: CVE-2026-0965
>> +Upstream-Status: Backport [ https://git.libssh.org/projects/libssh.git/commit/?id=bf390a042623e02abc8f421c4c5fadc0429a8a76
>> ]
>> +
>> +Signed-off-by: Jakub Jelen <jjelen@redhat.com>
>> +Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
>> +(cherry picked from commit a5eb30dbfd8f3526b2d04bd9f0a3803b665f5798)
>> +(cherry picked from commit bf390a042623e02abc8f421c4c5fadc0429a8a76)
>> +Signed-off-by: Deepak Rathore <deeratho@cisco.com>
>> +---
>> + include/libssh/misc.h | 3 ++
>> + include/libssh/priv.h | 3 ++
>> + src/bind_config.c | 4 +-
>> + src/config.c | 8 ++--
>> + src/dh-gex.c | 4 +-
>> + src/known_hosts.c | 2 +-
>> + src/knownhosts.c | 2 +-
>> + src/misc.c | 74 ++++++++++++++++++++++++++++++++
>> + tests/unittests/torture_config.c | 20 +++++++++
>> + 9 files changed, 110 insertions(+), 10 deletions(-)
>> +
>> +diff --git a/include/libssh/misc.h b/include/libssh/misc.h
>> +index ab726a0e..8eab94ee 100644
>> +--- a/include/libssh/misc.h
>> ++++ b/include/libssh/misc.h
>> +@@ -36,6 +36,7 @@
>> + #include <sys/types.h>
>> + #include <stdbool.h>
>> + #endif /* _WIN32 */
>> ++#include <stdio.h>
>> +
>> + #ifdef __cplusplus
>> + extern "C" {
>> +@@ -136,6 +137,8 @@ int ssh_check_username_syntax(const char *username);
>> + void ssh_proxyjumps_free(struct ssh_list *proxy_jump_list);
>> + bool ssh_libssh_proxy_jumps(void);
>> +
>> ++FILE *ssh_strict_fopen(const char *filename, size_t max_file_size);
>> ++
>> + #ifdef __cplusplus
>> + }
>> + #endif
>> +diff --git a/include/libssh/priv.h b/include/libssh/priv.h
>> +index 35fd8506..62069970 100644
>> +--- a/include/libssh/priv.h
>> ++++ b/include/libssh/priv.h
>> +@@ -473,6 +473,9 @@ char *ssh_strerror(int err_num, char *buf, size_t
>> buflen);
>> + #define SSH_TTY_MODES_MAX_BUFSIZE (55 * 5 + 1)
>> + int encode_current_tty_opts(unsigned char *buf, size_t buflen);
>> +
>> ++/** The default maximum file size for a configuration file */
>> ++#define SSH_MAX_CONFIG_FILE_SIZE 16 * 1024 * 1024
>> ++
>> + #ifdef __cplusplus
>> + }
>> + #endif
>> +diff --git a/src/bind_config.c b/src/bind_config.c
>> +index 9e4a7fd4..c12f1003 100644
>> +--- a/src/bind_config.c
>> ++++ b/src/bind_config.c
>> +@@ -212,7 +212,7 @@ local_parse_file(ssh_bind bind,
>> + return;
>> + }
>> +
>> +- f = fopen(filename, "r");
>> ++ f = ssh_strict_fopen(filename, SSH_MAX_CONFIG_FILE_SIZE);
>> + if (f == NULL) {
>> + SSH_LOG(SSH_LOG_RARE, "Cannot find file %s to load",
>> + filename);
>> +@@ -636,7 +636,7 @@ int ssh_bind_config_parse_file(ssh_bind bind, const
>> char *filename)
>> + * option to be redefined later by another file. */
>> + uint8_t seen[BIND_CFG_MAX] = {0};
>> +
>> +- f = fopen(filename, "r");
>> ++ f = ssh_strict_fopen(filename, SSH_MAX_CONFIG_FILE_SIZE);
>> + if (f == NULL) {
>> + return 0;
>> + }
>> +diff --git a/src/config.c b/src/config.c
>> +index b4171efd..1ffad537 100644
>> +--- a/src/config.c
>> ++++ b/src/config.c
>> +@@ -223,10 +223,9 @@ local_parse_file(ssh_session session,
>> + return;
>> + }
>> +
>> +- f = fopen(filename, "r");
>> ++ f = ssh_strict_fopen(filename, SSH_MAX_CONFIG_FILE_SIZE);
>> + if (f == NULL) {
>> +- SSH_LOG(SSH_LOG_RARE, "Cannot find file %s to load",
>> +- filename);
>> ++ /* The underlying function logs the reasons */
>> + return;
>> + }
>> +
>> +@@ -1466,8 +1465,9 @@ int ssh_config_parse_file(ssh_session session,
>> const char *filename)
>> + int parsing, rv;
>> + bool global = 0;
>> +
>> +- f = fopen(filename, "r");
>> ++ f = ssh_strict_fopen(filename, SSH_MAX_CONFIG_FILE_SIZE);
>> + if (f == NULL) {
>> ++ /* The underlying function logs the reasons */
>> + return 0;
>> + }
>> +
>> +diff --git a/src/dh-gex.c b/src/dh-gex.c
>> +index 46ba934e..428a5655 100644
>> +--- a/src/dh-gex.c
>> ++++ b/src/dh-gex.c
>> +@@ -519,9 +519,9 @@ static int ssh_retrieve_dhgroup(char *moduli_file,
>> + }
>> +
>> + if (moduli_file != NULL)
>> +- moduli = fopen(moduli_file, "r");
>> ++ moduli = ssh_strict_fopen(moduli_file, SSH_MAX_CONFIG_FILE_SIZE);
>> + else
>> +- moduli = fopen(MODULI_FILE, "r");
>> ++ moduli = ssh_strict_fopen(MODULI_FILE, SSH_MAX_CONFIG_FILE_SIZE);
>> +
>> + if (moduli == NULL) {
>> + char err_msg[SSH_ERRNO_MSG_MAX] = {0};
>> +diff --git a/src/known_hosts.c b/src/known_hosts.c
>> +index 3ef83e21..701576ce 100644
>> +--- a/src/known_hosts.c
>> ++++ b/src/known_hosts.c
>> +@@ -83,7 +83,7 @@ static struct ssh_tokens_st
>> *ssh_get_knownhost_line(FILE **file,
>> + struct ssh_tokens_st *tokens = NULL;
>> +
>> + if (*file == NULL) {
>> +- *file = fopen(filename,"r");
>> ++ *file = ssh_strict_fopen(filename, SSH_MAX_CONFIG_FILE_SIZE);
>> + if (*file == NULL) {
>> + return NULL;
>> + }
>> +diff --git a/src/knownhosts.c b/src/knownhosts.c
>> +index a2d08a75..3ab468de 100644
>> +--- a/src/knownhosts.c
>> ++++ b/src/knownhosts.c
>> +@@ -232,7 +232,7 @@ static int ssh_known_hosts_read_entries(const char
>> *match,
>> + FILE *fp = NULL;
>> + int rc;
>> +
>> +- fp = fopen(filename, "r");
>> ++ fp = ssh_strict_fopen(filename, SSH_MAX_CONFIG_FILE_SIZE);
>> + if (fp == NULL) {
>> + char err_msg[SSH_ERRNO_MSG_MAX] = {0};
>> + SSH_LOG(SSH_LOG_TRACE, "Failed to open the known_hosts file '%s': %s",
>> +diff --git a/src/misc.c b/src/misc.c
>> +index 774211fb..3968e6bc 100644
>> +--- a/src/misc.c
>> ++++ b/src/misc.c
>> +@@ -37,6 +37,7 @@
>> + #endif /* _WIN32 */
>> +
>> + #include <errno.h>
>> ++#include <fcntl.h>
>> + #include <limits.h>
>> + #include <stdio.h>
>> + #include <string.h>
>> +@@ -2244,4 +2245,77 @@ ssh_libssh_proxy_jumps(void)
>> + return !(t != NULL && t[0] == '1');
>> + }
>> +
>> ++/**
>> ++ * @internal
>> ++ *
>> ++ * @brief Safely open a file containing some configuration.
>> ++ *
>> ++ * Runs checks if the file can be used as some configuration file (is
>> regular
>> ++ * file and is not too large). If so, returns the opened file (for
>> reading).
>> ++ * Otherwise logs error and returns `NULL`.
>> ++ *
>> ++ * @param filename The path to the file to open.
>> ++ * @param max_file_size Maximum file size that is accepted.
>> ++ *
>> ++ * @returns the opened file or `NULL` on error.
>> ++ */
>> ++FILE *ssh_strict_fopen(const char *filename, size_t max_file_size)
>> ++{
>> ++ FILE *f = NULL;
>> ++ struct stat sb;
>> ++ char err_msg[SSH_ERRNO_MSG_MAX] = {0};
>> ++ int r, fd;
>> ++
>> ++ /* open first to avoid TOCTOU */
>> ++ fd = open(filename, O_RDONLY);
>> ++ if (fd == -1) {
>> ++ SSH_LOG(SSH_LOG_RARE,
>> ++ "Failed to open a file %s for reading: %s",
>> ++ filename,
>> ++ ssh_strerror(errno, err_msg, SSH_ERRNO_MSG_MAX));
>> ++ return NULL;
>> ++ }
>> ++
>> ++ /* Check the file is sensible for a configuration file */
>> ++ r = fstat(fd, &sb);
>> ++ if (r != 0) {
>> ++ SSH_LOG(SSH_LOG_RARE,
>> ++ "Failed to stat %s: %s",
>> ++ filename,
>> ++ ssh_strerror(errno, err_msg, SSH_ERRNO_MSG_MAX));
>> ++ close(fd);
>> ++ return NULL;
>> ++ }
>> ++ if ((sb.st_mode & S_IFMT) != S_IFREG) {
>> ++ SSH_LOG(SSH_LOG_RARE,
>> ++ "The file %s is not a regular file: skipping",
>> ++ filename);
>> ++ close(fd);
>> ++ return NULL;
>> ++ }
>> ++
>> ++ if ((size_t)sb.st_size > max_file_size) {
>> ++ SSH_LOG(SSH_LOG_RARE,
>> ++ "The file %s is too large (%jd MB > %zu MB): skipping",
>> ++ filename,
>> ++ (intmax_t)sb.st_size / 1024 / 1024,
>> ++ max_file_size / 1024 / 1024);
>> ++ close(fd);
>> ++ return NULL;
>> ++ }
>> ++
>> ++ f = fdopen(fd, "r");
>> ++ if (f == NULL) {
>> ++ SSH_LOG(SSH_LOG_RARE,
>> ++ "Failed to open a file %s for reading: %s",
>> ++ filename,
>> ++ ssh_strerror(r, err_msg, SSH_ERRNO_MSG_MAX));
>> ++ close(fd);
>> ++ return NULL;
>> ++ }
>> ++
>> ++ /* the flcose() will close also the underlying fd */
>> ++ return f;
>> ++}
>> ++
>> + /** @} */
>> +diff --git a/tests/unittests/torture_config.c
>> b/tests/unittests/torture_config.c
>> +index fcfe8fbc..0cb31a76 100644
>> +--- a/tests/unittests/torture_config.c
>> ++++ b/tests/unittests/torture_config.c
>> +@@ -2675,6 +2675,23 @@ static void torture_config_match_complex(void
>> **state)
>> + ssh_string_free_char(v);
>> + }
>> +
>> ++/* Invalid configuration files
>> ++ */
>> ++static void torture_config_invalid(void **state)
>> ++{
>> ++ ssh_session session = *state;
>> ++
>> ++ ssh_options_set(session, SSH_OPTIONS_HOST, "Bar");
>> ++
>> ++ /* non-regular file -- ignored (or missing on non-unix) so OK */
>> ++ _parse_config(session, "/dev/random", NULL, SSH_OK);
>> ++
>> ++#ifndef _WIN32
>> ++ /* huge file -- ignored (or missing on non-unix) so OK */
>> ++ _parse_config(session, "/proc/kcore", NULL, SSH_OK);
>> ++#endif
>> ++}
>> ++
>> + int torture_run_tests(void)
>> + {
>> + int rc;
>> +@@ -2771,6 +2788,9 @@ int torture_run_tests(void)
>> + setup, teardown),
>> + cmocka_unit_test_setup_teardown(torture_config_match_complex,
>> + setup, teardown),
>> ++ cmocka_unit_test_setup_teardown(torture_config_invalid,
>> ++ setup,
>> ++ teardown),
>> + };
>> +
>> +
>> +--
>> +2.51.0
>> +
>> diff --git a/meta-oe/recipes-support/libssh/libssh_0.11.3.bb
>> b/meta-oe/recipes-support/libssh/libssh_0.11.3.bb
>> index 193ff3512d..c552692bde 100644
>> --- a/meta-oe/recipes-support/libssh/libssh_0.11.3.bb
>> +++ b/meta-oe/recipes-support/libssh/libssh_0.11.3.bb
>> @@ -14,6 +14,7 @@ SRC_URI =
>> "git://git.libssh.org/projects/libssh.git;protocol=https;branch=stable
>> file://CVE-2026-0968_p1.patch \
>> file://CVE-2026-0968_p2.patch \
>> file://CVE-2026-0967.patch \
>> + file://CVE-2026-0965.patch \
>> "
>> 
>> SRC_URI:append:toolchain-clang = "
>> file://0001-CompilerChecks.cmake-drop-Wunused-variable-flag.patch"
>> --
>> 2.35.6
>> 
>> 
>> 
>> 
> 
> 

On Wed, Apr 8, 2026 at 10:49 AM, Ankur Tyagi wrote:

> 
> I think we can upgrade to v0.11.4
> 
> https://git.libssh.org/projects/libssh.git/tree/CHANGELOG?h=stable-0.11
> 
> version 0.11.4 (released 2026-02-10)
> * Security:
> * CVE-2025-14821: libssh loads configuration files from the C:\etc
> directory
> on Windows
> * CVE-2026-0964: SCP Protocol Path Traversal in ssh_scp_pull_request()
> * CVE-2026-0965: Possible Denial of Service when parsing unexpected
> configuration files
> * CVE-2026-0966: Buffer underflow in ssh_get_hexa() on invalid input
> * CVE-2026-0967: Specially crafted patterns could cause DoS
> * CVE-2026-0968: OOB Read in sftp_parse_longname()
> * libssh-2026-sftp-extensions: Read buffer overrun when handling SFTP
> extensions
> * Stability and compatibility improvements of ProxyJum
> 
> 
> 
> On Mon, Apr 6, 2026 at 11:56 PM Deepak Rathore via
> lists.openembedded.org <deeratho=cisco.com@lists.openembedded.org>
> wrote:
> 
>> 
>> From: Deepak Rathore <deeratho@cisco.com>
>> 
>> Pick the patch [1] as mentioned in [2]
>> 
>> [1] https://git.libssh.org/projects/libssh.git/commit/?id=bf390a042623e02abc8f421c4c5fadc0429a8a76
>> 
>> [2] https://security-tracker.debian.org/tracker/CVE-2026-0965
>> 
>> Signed-off-by: Deepak Rathore <deeratho@cisco.com>
>> ---
>> .../libssh/libssh/CVE-2026-0965.patch | 286 ++++++++++++++++++
>> .../recipes-support/libssh/libssh_0.11.3.bb | 1 +
>> 2 files changed, 287 insertions(+)
>> create mode 100644
>> meta-oe/recipes-support/libssh/libssh/CVE-2026-0965.patch
>> 
>> diff --git a/meta-oe/recipes-support/libssh/libssh/CVE-2026-0965.patch
>> b/meta-oe/recipes-support/libssh/libssh/CVE-2026-0965.patch
>> new file mode 100644
>> index 0000000000..57cb9d6170
>> --- /dev/null
>> +++ b/meta-oe/recipes-support/libssh/libssh/CVE-2026-0965.patch
>> @@ -0,0 +1,286 @@
>> +From 5858a988942d2e25985b34b8c40ce2792cbbe853 Mon Sep 17 00:00:00 2001
>> +From: Jakub Jelen <jjelen@redhat.com>
>> +Date: Thu, 11 Dec 2025 17:33:19 +0100
>> +Subject: [PATCH 4/4] CVE-2026-0965 config: Do not attempt to read
>> non-regular
>> + and too large configuration files
>> +
>> +Changes also the reading of known_hosts to use the new helper function
>> +
>> +CVE: CVE-2026-0965
>> +Upstream-Status: Backport [ https://git.libssh.org/projects/libssh.git/commit/?id=bf390a042623e02abc8f421c4c5fadc0429a8a76
>> ]
>> +
>> +Signed-off-by: Jakub Jelen <jjelen@redhat.com>
>> +Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
>> +(cherry picked from commit a5eb30dbfd8f3526b2d04bd9f0a3803b665f5798)
>> +(cherry picked from commit bf390a042623e02abc8f421c4c5fadc0429a8a76)
>> +Signed-off-by: Deepak Rathore <deeratho@cisco.com>
>> +---
>> + include/libssh/misc.h | 3 ++
>> + include/libssh/priv.h | 3 ++
>> + src/bind_config.c | 4 +-
>> + src/config.c | 8 ++--
>> + src/dh-gex.c | 4 +-
>> + src/known_hosts.c | 2 +-
>> + src/knownhosts.c | 2 +-
>> + src/misc.c | 74 ++++++++++++++++++++++++++++++++
>> + tests/unittests/torture_config.c | 20 +++++++++
>> + 9 files changed, 110 insertions(+), 10 deletions(-)
>> +
>> +diff --git a/include/libssh/misc.h b/include/libssh/misc.h
>> +index ab726a0e..8eab94ee 100644
>> +--- a/include/libssh/misc.h
>> ++++ b/include/libssh/misc.h
>> +@@ -36,6 +36,7 @@
>> + #include <sys/types.h>
>> + #include <stdbool.h>
>> + #endif /* _WIN32 */
>> ++#include <stdio.h>
>> +
>> + #ifdef __cplusplus
>> + extern "C" {
>> +@@ -136,6 +137,8 @@ int ssh_check_username_syntax(const char *username);
>> + void ssh_proxyjumps_free(struct ssh_list *proxy_jump_list);
>> + bool ssh_libssh_proxy_jumps(void);
>> +
>> ++FILE *ssh_strict_fopen(const char *filename, size_t max_file_size);
>> ++
>> + #ifdef __cplusplus
>> + }
>> + #endif
>> +diff --git a/include/libssh/priv.h b/include/libssh/priv.h
>> +index 35fd8506..62069970 100644
>> +--- a/include/libssh/priv.h
>> ++++ b/include/libssh/priv.h
>> +@@ -473,6 +473,9 @@ char *ssh_strerror(int err_num, char *buf, size_t
>> buflen);
>> + #define SSH_TTY_MODES_MAX_BUFSIZE (55 * 5 + 1)
>> + int encode_current_tty_opts(unsigned char *buf, size_t buflen);
>> +
>> ++/** The default maximum file size for a configuration file */
>> ++#define SSH_MAX_CONFIG_FILE_SIZE 16 * 1024 * 1024
>> ++
>> + #ifdef __cplusplus
>> + }
>> + #endif
>> +diff --git a/src/bind_config.c b/src/bind_config.c
>> +index 9e4a7fd4..c12f1003 100644
>> +--- a/src/bind_config.c
>> ++++ b/src/bind_config.c
>> +@@ -212,7 +212,7 @@ local_parse_file(ssh_bind bind,
>> + return;
>> + }
>> +
>> +- f = fopen(filename, "r");
>> ++ f = ssh_strict_fopen(filename, SSH_MAX_CONFIG_FILE_SIZE);
>> + if (f == NULL) {
>> + SSH_LOG(SSH_LOG_RARE, "Cannot find file %s to load",
>> + filename);
>> +@@ -636,7 +636,7 @@ int ssh_bind_config_parse_file(ssh_bind bind, const
>> char *filename)
>> + * option to be redefined later by another file. */
>> + uint8_t seen[BIND_CFG_MAX] = {0};
>> +
>> +- f = fopen(filename, "r");
>> ++ f = ssh_strict_fopen(filename, SSH_MAX_CONFIG_FILE_SIZE);
>> + if (f == NULL) {
>> + return 0;
>> + }
>> +diff --git a/src/config.c b/src/config.c
>> +index b4171efd..1ffad537 100644
>> +--- a/src/config.c
>> ++++ b/src/config.c
>> +@@ -223,10 +223,9 @@ local_parse_file(ssh_session session,
>> + return;
>> + }
>> +
>> +- f = fopen(filename, "r");
>> ++ f = ssh_strict_fopen(filename, SSH_MAX_CONFIG_FILE_SIZE);
>> + if (f == NULL) {
>> +- SSH_LOG(SSH_LOG_RARE, "Cannot find file %s to load",
>> +- filename);
>> ++ /* The underlying function logs the reasons */
>> + return;
>> + }
>> +
>> +@@ -1466,8 +1465,9 @@ int ssh_config_parse_file(ssh_session session,
>> const char *filename)
>> + int parsing, rv;
>> + bool global = 0;
>> +
>> +- f = fopen(filename, "r");
>> ++ f = ssh_strict_fopen(filename, SSH_MAX_CONFIG_FILE_SIZE);
>> + if (f == NULL) {
>> ++ /* The underlying function logs the reasons */
>> + return 0;
>> + }
>> +
>> +diff --git a/src/dh-gex.c b/src/dh-gex.c
>> +index 46ba934e..428a5655 100644
>> +--- a/src/dh-gex.c
>> ++++ b/src/dh-gex.c
>> +@@ -519,9 +519,9 @@ static int ssh_retrieve_dhgroup(char *moduli_file,
>> + }
>> +
>> + if (moduli_file != NULL)
>> +- moduli = fopen(moduli_file, "r");
>> ++ moduli = ssh_strict_fopen(moduli_file, SSH_MAX_CONFIG_FILE_SIZE);
>> + else
>> +- moduli = fopen(MODULI_FILE, "r");
>> ++ moduli = ssh_strict_fopen(MODULI_FILE, SSH_MAX_CONFIG_FILE_SIZE);
>> +
>> + if (moduli == NULL) {
>> + char err_msg[SSH_ERRNO_MSG_MAX] = {0};
>> +diff --git a/src/known_hosts.c b/src/known_hosts.c
>> +index 3ef83e21..701576ce 100644
>> +--- a/src/known_hosts.c
>> ++++ b/src/known_hosts.c
>> +@@ -83,7 +83,7 @@ static struct ssh_tokens_st
>> *ssh_get_knownhost_line(FILE **file,
>> + struct ssh_tokens_st *tokens = NULL;
>> +
>> + if (*file == NULL) {
>> +- *file = fopen(filename,"r");
>> ++ *file = ssh_strict_fopen(filename, SSH_MAX_CONFIG_FILE_SIZE);
>> + if (*file == NULL) {
>> + return NULL;
>> + }
>> +diff --git a/src/knownhosts.c b/src/knownhosts.c
>> +index a2d08a75..3ab468de 100644
>> +--- a/src/knownhosts.c
>> ++++ b/src/knownhosts.c
>> +@@ -232,7 +232,7 @@ static int ssh_known_hosts_read_entries(const char
>> *match,
>> + FILE *fp = NULL;
>> + int rc;
>> +
>> +- fp = fopen(filename, "r");
>> ++ fp = ssh_strict_fopen(filename, SSH_MAX_CONFIG_FILE_SIZE);
>> + if (fp == NULL) {
>> + char err_msg[SSH_ERRNO_MSG_MAX] = {0};
>> + SSH_LOG(SSH_LOG_TRACE, "Failed to open the known_hosts file '%s': %s",
>> +diff --git a/src/misc.c b/src/misc.c
>> +index 774211fb..3968e6bc 100644
>> +--- a/src/misc.c
>> ++++ b/src/misc.c
>> +@@ -37,6 +37,7 @@
>> + #endif /* _WIN32 */
>> +
>> + #include <errno.h>
>> ++#include <fcntl.h>
>> + #include <limits.h>
>> + #include <stdio.h>
>> + #include <string.h>
>> +@@ -2244,4 +2245,77 @@ ssh_libssh_proxy_jumps(void)
>> + return !(t != NULL && t[0] == '1');
>> + }
>> +
>> ++/**
>> ++ * @internal
>> ++ *
>> ++ * @brief Safely open a file containing some configuration.
>> ++ *
>> ++ * Runs checks if the file can be used as some configuration file (is
>> regular
>> ++ * file and is not too large). If so, returns the opened file (for
>> reading).
>> ++ * Otherwise logs error and returns `NULL`.
>> ++ *
>> ++ * @param filename The path to the file to open.
>> ++ * @param max_file_size Maximum file size that is accepted.
>> ++ *
>> ++ * @returns the opened file or `NULL` on error.
>> ++ */
>> ++FILE *ssh_strict_fopen(const char *filename, size_t max_file_size)
>> ++{
>> ++ FILE *f = NULL;
>> ++ struct stat sb;
>> ++ char err_msg[SSH_ERRNO_MSG_MAX] = {0};
>> ++ int r, fd;
>> ++
>> ++ /* open first to avoid TOCTOU */
>> ++ fd = open(filename, O_RDONLY);
>> ++ if (fd == -1) {
>> ++ SSH_LOG(SSH_LOG_RARE,
>> ++ "Failed to open a file %s for reading: %s",
>> ++ filename,
>> ++ ssh_strerror(errno, err_msg, SSH_ERRNO_MSG_MAX));
>> ++ return NULL;
>> ++ }
>> ++
>> ++ /* Check the file is sensible for a configuration file */
>> ++ r = fstat(fd, &sb);
>> ++ if (r != 0) {
>> ++ SSH_LOG(SSH_LOG_RARE,
>> ++ "Failed to stat %s: %s",
>> ++ filename,
>> ++ ssh_strerror(errno, err_msg, SSH_ERRNO_MSG_MAX));
>> ++ close(fd);
>> ++ return NULL;
>> ++ }
>> ++ if ((sb.st_mode & S_IFMT) != S_IFREG) {
>> ++ SSH_LOG(SSH_LOG_RARE,
>> ++ "The file %s is not a regular file: skipping",
>> ++ filename);
>> ++ close(fd);
>> ++ return NULL;
>> ++ }
>> ++
>> ++ if ((size_t)sb.st_size > max_file_size) {
>> ++ SSH_LOG(SSH_LOG_RARE,
>> ++ "The file %s is too large (%jd MB > %zu MB): skipping",
>> ++ filename,
>> ++ (intmax_t)sb.st_size / 1024 / 1024,
>> ++ max_file_size / 1024 / 1024);
>> ++ close(fd);
>> ++ return NULL;
>> ++ }
>> ++
>> ++ f = fdopen(fd, "r");
>> ++ if (f == NULL) {
>> ++ SSH_LOG(SSH_LOG_RARE,
>> ++ "Failed to open a file %s for reading: %s",
>> ++ filename,
>> ++ ssh_strerror(r, err_msg, SSH_ERRNO_MSG_MAX));
>> ++ close(fd);
>> ++ return NULL;
>> ++ }
>> ++
>> ++ /* the flcose() will close also the underlying fd */
>> ++ return f;
>> ++}
>> ++
>> + /** @} */
>> +diff --git a/tests/unittests/torture_config.c
>> b/tests/unittests/torture_config.c
>> +index fcfe8fbc..0cb31a76 100644
>> +--- a/tests/unittests/torture_config.c
>> ++++ b/tests/unittests/torture_config.c
>> +@@ -2675,6 +2675,23 @@ static void torture_config_match_complex(void
>> **state)
>> + ssh_string_free_char(v);
>> + }
>> +
>> ++/* Invalid configuration files
>> ++ */
>> ++static void torture_config_invalid(void **state)
>> ++{
>> ++ ssh_session session = *state;
>> ++
>> ++ ssh_options_set(session, SSH_OPTIONS_HOST, "Bar");
>> ++
>> ++ /* non-regular file -- ignored (or missing on non-unix) so OK */
>> ++ _parse_config(session, "/dev/random", NULL, SSH_OK);
>> ++
>> ++#ifndef _WIN32
>> ++ /* huge file -- ignored (or missing on non-unix) so OK */
>> ++ _parse_config(session, "/proc/kcore", NULL, SSH_OK);
>> ++#endif
>> ++}
>> ++
>> + int torture_run_tests(void)
>> + {
>> + int rc;
>> +@@ -2771,6 +2788,9 @@ int torture_run_tests(void)
>> + setup, teardown),
>> + cmocka_unit_test_setup_teardown(torture_config_match_complex,
>> + setup, teardown),
>> ++ cmocka_unit_test_setup_teardown(torture_config_invalid,
>> ++ setup,
>> ++ teardown),
>> + };
>> +
>> +
>> +--
>> +2.51.0
>> +
>> diff --git a/meta-oe/recipes-support/libssh/libssh_0.11.3.bb
>> b/meta-oe/recipes-support/libssh/libssh_0.11.3.bb
>> index 193ff3512d..c552692bde 100644
>> --- a/meta-oe/recipes-support/libssh/libssh_0.11.3.bb
>> +++ b/meta-oe/recipes-support/libssh/libssh_0.11.3.bb
>> @@ -14,6 +14,7 @@ SRC_URI =
>> "git://git.libssh.org/projects/libssh.git;protocol=https;branch=stable
>> file://CVE-2026-0968_p1.patch \
>> file://CVE-2026-0968_p2.patch \
>> file://CVE-2026-0967.patch \
>> + file://CVE-2026-0965.patch \
>> "
>> 
>> SRC_URI:append:toolchain-clang = "
>> file://0001-CompilerChecks.cmake-drop-Wunused-variable-flag.patch"
>> --
>> 2.35.6
>> 
>> 
>> 
>> 
> 
>

[-- Attachment #2: Type: text/html, Size: 26916 bytes --]

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [oe] [meta-oe][whinlatter][PATCH 3/3] libssh: Fix CVE-2026-0965
  2026-04-09  4:25   ` [meta-oe][whinlatter][PATCH " Deepak Rathore
@ 2026-04-09  8:26     ` Yoann Congal
  2026-04-09  8:30     ` Gyorgy Sarvari
  1 sibling, 0 replies; 5+ messages in thread
From: Yoann Congal @ 2026-04-09  8:26 UTC (permalink / raw)
  To: deeratho, openembedded-devel

On Thu Apr 9, 2026 at 6:25 AM CEST, Deepak Rathore via lists.openembedded.org wrote:
> Hi Ankur,
>
> Thank you for your review and response.
>
> As previously indicated by the maintainer in this thread ( openembedded-core@lists.openembedded.org | Inquiry Regarding Package Upgrade Approach vs. Manual CVE Fixes in LTS Releases ( https://lists.openembedded.org/g/openembedded-core/topic/118275693 ) ), package upgrades are not considered for stable and LTS branches for stability. Only bug fixes and security fixes are accepted. Accordingly, I have submitted CVE fix patches instead of performing a package upgrade.

Hello Deepak,

Just to clarify the above mail: upgrades are generally not acceptable as
they often mix feature additions and security fixes but there is an
exception for upstream projects that have a stable upgrade policy
compatible with ours (ie only security/bug fixes on stable).

It looks like libssh does have a stable policy compatible with ours: If
it were a oe-core recipe I would seriously consider the upgrade.

Regards,

>
> Regards,
> Deepak
>
> On Wed, Apr 8, 2026 at 10:49 AM, Ankur Tyagi wrote:
>
>> 
>> I think we can upgrade to v0.11.4
>> 
>> https://git.libssh.org/projects/libssh.git/tree/CHANGELOG?h=stable-0.11
>> 
>> version 0.11.4 (released 2026-02-10)
>> * Security:
>> * CVE-2025-14821: libssh loads configuration files from the C:\etc
>> directory
>> on Windows
>> * CVE-2026-0964: SCP Protocol Path Traversal in ssh_scp_pull_request()
>> * CVE-2026-0965: Possible Denial of Service when parsing unexpected
>> configuration files
>> * CVE-2026-0966: Buffer underflow in ssh_get_hexa() on invalid input
>> * CVE-2026-0967: Specially crafted patterns could cause DoS
>> * CVE-2026-0968: OOB Read in sftp_parse_longname()
>> * libssh-2026-sftp-extensions: Read buffer overrun when handling SFTP
>> extensions
>> * Stability and compatibility improvements of ProxyJum
>> 
>> 
>> 
>> On Mon, Apr 6, 2026 at 11:56 PM Deepak Rathore via
>> lists.openembedded.org <deeratho=cisco.com@lists.openembedded.org>
>> wrote:
>> 
>>> 
>>> From: Deepak Rathore <deeratho@cisco.com>
>>> 
>>> Pick the patch [1] as mentioned in [2]
>>> 
>>> [1] https://git.libssh.org/projects/libssh.git/commit/?id=bf390a042623e02abc8f421c4c5fadc0429a8a76
>>> 
>>> [2] https://security-tracker.debian.org/tracker/CVE-2026-0965
>>> 
>>> Signed-off-by: Deepak Rathore <deeratho@cisco.com>
>>> ---
>>> .../libssh/libssh/CVE-2026-0965.patch | 286 ++++++++++++++++++
>>> .../recipes-support/libssh/libssh_0.11.3.bb | 1 +
>>> 2 files changed, 287 insertions(+)
>>> create mode 100644
>>> meta-oe/recipes-support/libssh/libssh/CVE-2026-0965.patch
>>> 
>>> diff --git a/meta-oe/recipes-support/libssh/libssh/CVE-2026-0965.patch
>>> b/meta-oe/recipes-support/libssh/libssh/CVE-2026-0965.patch
>>> new file mode 100644
>>> index 0000000000..57cb9d6170
>>> --- /dev/null
>>> +++ b/meta-oe/recipes-support/libssh/libssh/CVE-2026-0965.patch
>>> @@ -0,0 +1,286 @@
>>> +From 5858a988942d2e25985b34b8c40ce2792cbbe853 Mon Sep 17 00:00:00 2001
>>> +From: Jakub Jelen <jjelen@redhat.com>
>>> +Date: Thu, 11 Dec 2025 17:33:19 +0100
>>> +Subject: [PATCH 4/4] CVE-2026-0965 config: Do not attempt to read
>>> non-regular
>>> + and too large configuration files
>>> +
>>> +Changes also the reading of known_hosts to use the new helper function
>>> +
>>> +CVE: CVE-2026-0965
>>> +Upstream-Status: Backport [ https://git.libssh.org/projects/libssh.git/commit/?id=bf390a042623e02abc8f421c4c5fadc0429a8a76
>>> ]
>>> +
>>> +Signed-off-by: Jakub Jelen <jjelen@redhat.com>
>>> +Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
>>> +(cherry picked from commit a5eb30dbfd8f3526b2d04bd9f0a3803b665f5798)
>>> +(cherry picked from commit bf390a042623e02abc8f421c4c5fadc0429a8a76)
>>> +Signed-off-by: Deepak Rathore <deeratho@cisco.com>
>>> +---
>>> + include/libssh/misc.h | 3 ++
>>> + include/libssh/priv.h | 3 ++
>>> + src/bind_config.c | 4 +-
>>> + src/config.c | 8 ++--
>>> + src/dh-gex.c | 4 +-
>>> + src/known_hosts.c | 2 +-
>>> + src/knownhosts.c | 2 +-
>>> + src/misc.c | 74 ++++++++++++++++++++++++++++++++
>>> + tests/unittests/torture_config.c | 20 +++++++++
>>> + 9 files changed, 110 insertions(+), 10 deletions(-)
>>> +
>>> +diff --git a/include/libssh/misc.h b/include/libssh/misc.h
>>> +index ab726a0e..8eab94ee 100644
>>> +--- a/include/libssh/misc.h
>>> ++++ b/include/libssh/misc.h
>>> +@@ -36,6 +36,7 @@
>>> + #include <sys/types.h>
>>> + #include <stdbool.h>
>>> + #endif /* _WIN32 */
>>> ++#include <stdio.h>
>>> +
>>> + #ifdef __cplusplus
>>> + extern "C" {
>>> +@@ -136,6 +137,8 @@ int ssh_check_username_syntax(const char *username);
>>> + void ssh_proxyjumps_free(struct ssh_list *proxy_jump_list);
>>> + bool ssh_libssh_proxy_jumps(void);
>>> +
>>> ++FILE *ssh_strict_fopen(const char *filename, size_t max_file_size);
>>> ++
>>> + #ifdef __cplusplus
>>> + }
>>> + #endif
>>> +diff --git a/include/libssh/priv.h b/include/libssh/priv.h
>>> +index 35fd8506..62069970 100644
>>> +--- a/include/libssh/priv.h
>>> ++++ b/include/libssh/priv.h
>>> +@@ -473,6 +473,9 @@ char *ssh_strerror(int err_num, char *buf, size_t
>>> buflen);
>>> + #define SSH_TTY_MODES_MAX_BUFSIZE (55 * 5 + 1)
>>> + int encode_current_tty_opts(unsigned char *buf, size_t buflen);
>>> +
>>> ++/** The default maximum file size for a configuration file */
>>> ++#define SSH_MAX_CONFIG_FILE_SIZE 16 * 1024 * 1024
>>> ++
>>> + #ifdef __cplusplus
>>> + }
>>> + #endif
>>> +diff --git a/src/bind_config.c b/src/bind_config.c
>>> +index 9e4a7fd4..c12f1003 100644
>>> +--- a/src/bind_config.c
>>> ++++ b/src/bind_config.c
>>> +@@ -212,7 +212,7 @@ local_parse_file(ssh_bind bind,
>>> + return;
>>> + }
>>> +
>>> +- f = fopen(filename, "r");
>>> ++ f = ssh_strict_fopen(filename, SSH_MAX_CONFIG_FILE_SIZE);
>>> + if (f == NULL) {
>>> + SSH_LOG(SSH_LOG_RARE, "Cannot find file %s to load",
>>> + filename);
>>> +@@ -636,7 +636,7 @@ int ssh_bind_config_parse_file(ssh_bind bind, const
>>> char *filename)
>>> + * option to be redefined later by another file. */
>>> + uint8_t seen[BIND_CFG_MAX] = {0};
>>> +
>>> +- f = fopen(filename, "r");
>>> ++ f = ssh_strict_fopen(filename, SSH_MAX_CONFIG_FILE_SIZE);
>>> + if (f == NULL) {
>>> + return 0;
>>> + }
>>> +diff --git a/src/config.c b/src/config.c
>>> +index b4171efd..1ffad537 100644
>>> +--- a/src/config.c
>>> ++++ b/src/config.c
>>> +@@ -223,10 +223,9 @@ local_parse_file(ssh_session session,
>>> + return;
>>> + }
>>> +
>>> +- f = fopen(filename, "r");
>>> ++ f = ssh_strict_fopen(filename, SSH_MAX_CONFIG_FILE_SIZE);
>>> + if (f == NULL) {
>>> +- SSH_LOG(SSH_LOG_RARE, "Cannot find file %s to load",
>>> +- filename);
>>> ++ /* The underlying function logs the reasons */
>>> + return;
>>> + }
>>> +
>>> +@@ -1466,8 +1465,9 @@ int ssh_config_parse_file(ssh_session session,
>>> const char *filename)
>>> + int parsing, rv;
>>> + bool global = 0;
>>> +
>>> +- f = fopen(filename, "r");
>>> ++ f = ssh_strict_fopen(filename, SSH_MAX_CONFIG_FILE_SIZE);
>>> + if (f == NULL) {
>>> ++ /* The underlying function logs the reasons */
>>> + return 0;
>>> + }
>>> +
>>> +diff --git a/src/dh-gex.c b/src/dh-gex.c
>>> +index 46ba934e..428a5655 100644
>>> +--- a/src/dh-gex.c
>>> ++++ b/src/dh-gex.c
>>> +@@ -519,9 +519,9 @@ static int ssh_retrieve_dhgroup(char *moduli_file,
>>> + }
>>> +
>>> + if (moduli_file != NULL)
>>> +- moduli = fopen(moduli_file, "r");
>>> ++ moduli = ssh_strict_fopen(moduli_file, SSH_MAX_CONFIG_FILE_SIZE);
>>> + else
>>> +- moduli = fopen(MODULI_FILE, "r");
>>> ++ moduli = ssh_strict_fopen(MODULI_FILE, SSH_MAX_CONFIG_FILE_SIZE);
>>> +
>>> + if (moduli == NULL) {
>>> + char err_msg[SSH_ERRNO_MSG_MAX] = {0};
>>> +diff --git a/src/known_hosts.c b/src/known_hosts.c
>>> +index 3ef83e21..701576ce 100644
>>> +--- a/src/known_hosts.c
>>> ++++ b/src/known_hosts.c
>>> +@@ -83,7 +83,7 @@ static struct ssh_tokens_st
>>> *ssh_get_knownhost_line(FILE **file,
>>> + struct ssh_tokens_st *tokens = NULL;
>>> +
>>> + if (*file == NULL) {
>>> +- *file = fopen(filename,"r");
>>> ++ *file = ssh_strict_fopen(filename, SSH_MAX_CONFIG_FILE_SIZE);
>>> + if (*file == NULL) {
>>> + return NULL;
>>> + }
>>> +diff --git a/src/knownhosts.c b/src/knownhosts.c
>>> +index a2d08a75..3ab468de 100644
>>> +--- a/src/knownhosts.c
>>> ++++ b/src/knownhosts.c
>>> +@@ -232,7 +232,7 @@ static int ssh_known_hosts_read_entries(const char
>>> *match,
>>> + FILE *fp = NULL;
>>> + int rc;
>>> +
>>> +- fp = fopen(filename, "r");
>>> ++ fp = ssh_strict_fopen(filename, SSH_MAX_CONFIG_FILE_SIZE);
>>> + if (fp == NULL) {
>>> + char err_msg[SSH_ERRNO_MSG_MAX] = {0};
>>> + SSH_LOG(SSH_LOG_TRACE, "Failed to open the known_hosts file '%s': %s",
>>> +diff --git a/src/misc.c b/src/misc.c
>>> +index 774211fb..3968e6bc 100644
>>> +--- a/src/misc.c
>>> ++++ b/src/misc.c
>>> +@@ -37,6 +37,7 @@
>>> + #endif /* _WIN32 */
>>> +
>>> + #include <errno.h>
>>> ++#include <fcntl.h>
>>> + #include <limits.h>
>>> + #include <stdio.h>
>>> + #include <string.h>
>>> +@@ -2244,4 +2245,77 @@ ssh_libssh_proxy_jumps(void)
>>> + return !(t != NULL && t[0] == '1');
>>> + }
>>> +
>>> ++/**
>>> ++ * @internal
>>> ++ *
>>> ++ * @brief Safely open a file containing some configuration.
>>> ++ *
>>> ++ * Runs checks if the file can be used as some configuration file (is
>>> regular
>>> ++ * file and is not too large). If so, returns the opened file (for
>>> reading).
>>> ++ * Otherwise logs error and returns `NULL`.
>>> ++ *
>>> ++ * @param filename The path to the file to open.
>>> ++ * @param max_file_size Maximum file size that is accepted.
>>> ++ *
>>> ++ * @returns the opened file or `NULL` on error.
>>> ++ */
>>> ++FILE *ssh_strict_fopen(const char *filename, size_t max_file_size)
>>> ++{
>>> ++ FILE *f = NULL;
>>> ++ struct stat sb;
>>> ++ char err_msg[SSH_ERRNO_MSG_MAX] = {0};
>>> ++ int r, fd;
>>> ++
>>> ++ /* open first to avoid TOCTOU */
>>> ++ fd = open(filename, O_RDONLY);
>>> ++ if (fd == -1) {
>>> ++ SSH_LOG(SSH_LOG_RARE,
>>> ++ "Failed to open a file %s for reading: %s",
>>> ++ filename,
>>> ++ ssh_strerror(errno, err_msg, SSH_ERRNO_MSG_MAX));
>>> ++ return NULL;
>>> ++ }
>>> ++
>>> ++ /* Check the file is sensible for a configuration file */
>>> ++ r = fstat(fd, &sb);
>>> ++ if (r != 0) {
>>> ++ SSH_LOG(SSH_LOG_RARE,
>>> ++ "Failed to stat %s: %s",
>>> ++ filename,
>>> ++ ssh_strerror(errno, err_msg, SSH_ERRNO_MSG_MAX));
>>> ++ close(fd);
>>> ++ return NULL;
>>> ++ }
>>> ++ if ((sb.st_mode & S_IFMT) != S_IFREG) {
>>> ++ SSH_LOG(SSH_LOG_RARE,
>>> ++ "The file %s is not a regular file: skipping",
>>> ++ filename);
>>> ++ close(fd);
>>> ++ return NULL;
>>> ++ }
>>> ++
>>> ++ if ((size_t)sb.st_size > max_file_size) {
>>> ++ SSH_LOG(SSH_LOG_RARE,
>>> ++ "The file %s is too large (%jd MB > %zu MB): skipping",
>>> ++ filename,
>>> ++ (intmax_t)sb.st_size / 1024 / 1024,
>>> ++ max_file_size / 1024 / 1024);
>>> ++ close(fd);
>>> ++ return NULL;
>>> ++ }
>>> ++
>>> ++ f = fdopen(fd, "r");
>>> ++ if (f == NULL) {
>>> ++ SSH_LOG(SSH_LOG_RARE,
>>> ++ "Failed to open a file %s for reading: %s",
>>> ++ filename,
>>> ++ ssh_strerror(r, err_msg, SSH_ERRNO_MSG_MAX));
>>> ++ close(fd);
>>> ++ return NULL;
>>> ++ }
>>> ++
>>> ++ /* the flcose() will close also the underlying fd */
>>> ++ return f;
>>> ++}
>>> ++
>>> + /** @} */
>>> +diff --git a/tests/unittests/torture_config.c
>>> b/tests/unittests/torture_config.c
>>> +index fcfe8fbc..0cb31a76 100644
>>> +--- a/tests/unittests/torture_config.c
>>> ++++ b/tests/unittests/torture_config.c
>>> +@@ -2675,6 +2675,23 @@ static void torture_config_match_complex(void
>>> **state)
>>> + ssh_string_free_char(v);
>>> + }
>>> +
>>> ++/* Invalid configuration files
>>> ++ */
>>> ++static void torture_config_invalid(void **state)
>>> ++{
>>> ++ ssh_session session = *state;
>>> ++
>>> ++ ssh_options_set(session, SSH_OPTIONS_HOST, "Bar");
>>> ++
>>> ++ /* non-regular file -- ignored (or missing on non-unix) so OK */
>>> ++ _parse_config(session, "/dev/random", NULL, SSH_OK);
>>> ++
>>> ++#ifndef _WIN32
>>> ++ /* huge file -- ignored (or missing on non-unix) so OK */
>>> ++ _parse_config(session, "/proc/kcore", NULL, SSH_OK);
>>> ++#endif
>>> ++}
>>> ++
>>> + int torture_run_tests(void)
>>> + {
>>> + int rc;
>>> +@@ -2771,6 +2788,9 @@ int torture_run_tests(void)
>>> + setup, teardown),
>>> + cmocka_unit_test_setup_teardown(torture_config_match_complex,
>>> + setup, teardown),
>>> ++ cmocka_unit_test_setup_teardown(torture_config_invalid,
>>> ++ setup,
>>> ++ teardown),
>>> + };
>>> +
>>> +
>>> +--
>>> +2.51.0
>>> +
>>> diff --git a/meta-oe/recipes-support/libssh/libssh_0.11.3.bb
>>> b/meta-oe/recipes-support/libssh/libssh_0.11.3.bb
>>> index 193ff3512d..c552692bde 100644
>>> --- a/meta-oe/recipes-support/libssh/libssh_0.11.3.bb
>>> +++ b/meta-oe/recipes-support/libssh/libssh_0.11.3.bb
>>> @@ -14,6 +14,7 @@ SRC_URI =
>>> "git://git.libssh.org/projects/libssh.git;protocol=https;branch=stable
>>> file://CVE-2026-0968_p1.patch \
>>> file://CVE-2026-0968_p2.patch \
>>> file://CVE-2026-0967.patch \
>>> + file://CVE-2026-0965.patch \
>>> "
>>> 
>>> SRC_URI:append:toolchain-clang = "
>>> file://0001-CompilerChecks.cmake-drop-Wunused-variable-flag.patch"
>>> --
>>> 2.35.6
>>> 
>>> 
>>> 
>>> 
>> 
>> 
>
> On Wed, Apr 8, 2026 at 10:49 AM, Ankur Tyagi wrote:
>
>> 
>> I think we can upgrade to v0.11.4
>> 
>> https://git.libssh.org/projects/libssh.git/tree/CHANGELOG?h=stable-0.11
>> 
>> version 0.11.4 (released 2026-02-10)
>> * Security:
>> * CVE-2025-14821: libssh loads configuration files from the C:\etc
>> directory
>> on Windows
>> * CVE-2026-0964: SCP Protocol Path Traversal in ssh_scp_pull_request()
>> * CVE-2026-0965: Possible Denial of Service when parsing unexpected
>> configuration files
>> * CVE-2026-0966: Buffer underflow in ssh_get_hexa() on invalid input
>> * CVE-2026-0967: Specially crafted patterns could cause DoS
>> * CVE-2026-0968: OOB Read in sftp_parse_longname()
>> * libssh-2026-sftp-extensions: Read buffer overrun when handling SFTP
>> extensions
>> * Stability and compatibility improvements of ProxyJum
>> 
>> 
>> 
>> On Mon, Apr 6, 2026 at 11:56 PM Deepak Rathore via
>> lists.openembedded.org <deeratho=cisco.com@lists.openembedded.org>
>> wrote:
>> 
>>> 
>>> From: Deepak Rathore <deeratho@cisco.com>
>>> 
>>> Pick the patch [1] as mentioned in [2]
>>> 
>>> [1] https://git.libssh.org/projects/libssh.git/commit/?id=bf390a042623e02abc8f421c4c5fadc0429a8a76
>>> 
>>> [2] https://security-tracker.debian.org/tracker/CVE-2026-0965
>>> 
>>> Signed-off-by: Deepak Rathore <deeratho@cisco.com>
>>> ---
>>> .../libssh/libssh/CVE-2026-0965.patch | 286 ++++++++++++++++++
>>> .../recipes-support/libssh/libssh_0.11.3.bb | 1 +
>>> 2 files changed, 287 insertions(+)
>>> create mode 100644
>>> meta-oe/recipes-support/libssh/libssh/CVE-2026-0965.patch
>>> 
>>> diff --git a/meta-oe/recipes-support/libssh/libssh/CVE-2026-0965.patch
>>> b/meta-oe/recipes-support/libssh/libssh/CVE-2026-0965.patch
>>> new file mode 100644
>>> index 0000000000..57cb9d6170
>>> --- /dev/null
>>> +++ b/meta-oe/recipes-support/libssh/libssh/CVE-2026-0965.patch
>>> @@ -0,0 +1,286 @@
>>> +From 5858a988942d2e25985b34b8c40ce2792cbbe853 Mon Sep 17 00:00:00 2001
>>> +From: Jakub Jelen <jjelen@redhat.com>
>>> +Date: Thu, 11 Dec 2025 17:33:19 +0100
>>> +Subject: [PATCH 4/4] CVE-2026-0965 config: Do not attempt to read
>>> non-regular
>>> + and too large configuration files
>>> +
>>> +Changes also the reading of known_hosts to use the new helper function
>>> +
>>> +CVE: CVE-2026-0965
>>> +Upstream-Status: Backport [ https://git.libssh.org/projects/libssh.git/commit/?id=bf390a042623e02abc8f421c4c5fadc0429a8a76
>>> ]
>>> +
>>> +Signed-off-by: Jakub Jelen <jjelen@redhat.com>
>>> +Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
>>> +(cherry picked from commit a5eb30dbfd8f3526b2d04bd9f0a3803b665f5798)
>>> +(cherry picked from commit bf390a042623e02abc8f421c4c5fadc0429a8a76)
>>> +Signed-off-by: Deepak Rathore <deeratho@cisco.com>
>>> +---
>>> + include/libssh/misc.h | 3 ++
>>> + include/libssh/priv.h | 3 ++
>>> + src/bind_config.c | 4 +-
>>> + src/config.c | 8 ++--
>>> + src/dh-gex.c | 4 +-
>>> + src/known_hosts.c | 2 +-
>>> + src/knownhosts.c | 2 +-
>>> + src/misc.c | 74 ++++++++++++++++++++++++++++++++
>>> + tests/unittests/torture_config.c | 20 +++++++++
>>> + 9 files changed, 110 insertions(+), 10 deletions(-)
>>> +
>>> +diff --git a/include/libssh/misc.h b/include/libssh/misc.h
>>> +index ab726a0e..8eab94ee 100644
>>> +--- a/include/libssh/misc.h
>>> ++++ b/include/libssh/misc.h
>>> +@@ -36,6 +36,7 @@
>>> + #include <sys/types.h>
>>> + #include <stdbool.h>
>>> + #endif /* _WIN32 */
>>> ++#include <stdio.h>
>>> +
>>> + #ifdef __cplusplus
>>> + extern "C" {
>>> +@@ -136,6 +137,8 @@ int ssh_check_username_syntax(const char *username);
>>> + void ssh_proxyjumps_free(struct ssh_list *proxy_jump_list);
>>> + bool ssh_libssh_proxy_jumps(void);
>>> +
>>> ++FILE *ssh_strict_fopen(const char *filename, size_t max_file_size);
>>> ++
>>> + #ifdef __cplusplus
>>> + }
>>> + #endif
>>> +diff --git a/include/libssh/priv.h b/include/libssh/priv.h
>>> +index 35fd8506..62069970 100644
>>> +--- a/include/libssh/priv.h
>>> ++++ b/include/libssh/priv.h
>>> +@@ -473,6 +473,9 @@ char *ssh_strerror(int err_num, char *buf, size_t
>>> buflen);
>>> + #define SSH_TTY_MODES_MAX_BUFSIZE (55 * 5 + 1)
>>> + int encode_current_tty_opts(unsigned char *buf, size_t buflen);
>>> +
>>> ++/** The default maximum file size for a configuration file */
>>> ++#define SSH_MAX_CONFIG_FILE_SIZE 16 * 1024 * 1024
>>> ++
>>> + #ifdef __cplusplus
>>> + }
>>> + #endif
>>> +diff --git a/src/bind_config.c b/src/bind_config.c
>>> +index 9e4a7fd4..c12f1003 100644
>>> +--- a/src/bind_config.c
>>> ++++ b/src/bind_config.c
>>> +@@ -212,7 +212,7 @@ local_parse_file(ssh_bind bind,
>>> + return;
>>> + }
>>> +
>>> +- f = fopen(filename, "r");
>>> ++ f = ssh_strict_fopen(filename, SSH_MAX_CONFIG_FILE_SIZE);
>>> + if (f == NULL) {
>>> + SSH_LOG(SSH_LOG_RARE, "Cannot find file %s to load",
>>> + filename);
>>> +@@ -636,7 +636,7 @@ int ssh_bind_config_parse_file(ssh_bind bind, const
>>> char *filename)
>>> + * option to be redefined later by another file. */
>>> + uint8_t seen[BIND_CFG_MAX] = {0};
>>> +
>>> +- f = fopen(filename, "r");
>>> ++ f = ssh_strict_fopen(filename, SSH_MAX_CONFIG_FILE_SIZE);
>>> + if (f == NULL) {
>>> + return 0;
>>> + }
>>> +diff --git a/src/config.c b/src/config.c
>>> +index b4171efd..1ffad537 100644
>>> +--- a/src/config.c
>>> ++++ b/src/config.c
>>> +@@ -223,10 +223,9 @@ local_parse_file(ssh_session session,
>>> + return;
>>> + }
>>> +
>>> +- f = fopen(filename, "r");
>>> ++ f = ssh_strict_fopen(filename, SSH_MAX_CONFIG_FILE_SIZE);
>>> + if (f == NULL) {
>>> +- SSH_LOG(SSH_LOG_RARE, "Cannot find file %s to load",
>>> +- filename);
>>> ++ /* The underlying function logs the reasons */
>>> + return;
>>> + }
>>> +
>>> +@@ -1466,8 +1465,9 @@ int ssh_config_parse_file(ssh_session session,
>>> const char *filename)
>>> + int parsing, rv;
>>> + bool global = 0;
>>> +
>>> +- f = fopen(filename, "r");
>>> ++ f = ssh_strict_fopen(filename, SSH_MAX_CONFIG_FILE_SIZE);
>>> + if (f == NULL) {
>>> ++ /* The underlying function logs the reasons */
>>> + return 0;
>>> + }
>>> +
>>> +diff --git a/src/dh-gex.c b/src/dh-gex.c
>>> +index 46ba934e..428a5655 100644
>>> +--- a/src/dh-gex.c
>>> ++++ b/src/dh-gex.c
>>> +@@ -519,9 +519,9 @@ static int ssh_retrieve_dhgroup(char *moduli_file,
>>> + }
>>> +
>>> + if (moduli_file != NULL)
>>> +- moduli = fopen(moduli_file, "r");
>>> ++ moduli = ssh_strict_fopen(moduli_file, SSH_MAX_CONFIG_FILE_SIZE);
>>> + else
>>> +- moduli = fopen(MODULI_FILE, "r");
>>> ++ moduli = ssh_strict_fopen(MODULI_FILE, SSH_MAX_CONFIG_FILE_SIZE);
>>> +
>>> + if (moduli == NULL) {
>>> + char err_msg[SSH_ERRNO_MSG_MAX] = {0};
>>> +diff --git a/src/known_hosts.c b/src/known_hosts.c
>>> +index 3ef83e21..701576ce 100644
>>> +--- a/src/known_hosts.c
>>> ++++ b/src/known_hosts.c
>>> +@@ -83,7 +83,7 @@ static struct ssh_tokens_st
>>> *ssh_get_knownhost_line(FILE **file,
>>> + struct ssh_tokens_st *tokens = NULL;
>>> +
>>> + if (*file == NULL) {
>>> +- *file = fopen(filename,"r");
>>> ++ *file = ssh_strict_fopen(filename, SSH_MAX_CONFIG_FILE_SIZE);
>>> + if (*file == NULL) {
>>> + return NULL;
>>> + }
>>> +diff --git a/src/knownhosts.c b/src/knownhosts.c
>>> +index a2d08a75..3ab468de 100644
>>> +--- a/src/knownhosts.c
>>> ++++ b/src/knownhosts.c
>>> +@@ -232,7 +232,7 @@ static int ssh_known_hosts_read_entries(const char
>>> *match,
>>> + FILE *fp = NULL;
>>> + int rc;
>>> +
>>> +- fp = fopen(filename, "r");
>>> ++ fp = ssh_strict_fopen(filename, SSH_MAX_CONFIG_FILE_SIZE);
>>> + if (fp == NULL) {
>>> + char err_msg[SSH_ERRNO_MSG_MAX] = {0};
>>> + SSH_LOG(SSH_LOG_TRACE, "Failed to open the known_hosts file '%s': %s",
>>> +diff --git a/src/misc.c b/src/misc.c
>>> +index 774211fb..3968e6bc 100644
>>> +--- a/src/misc.c
>>> ++++ b/src/misc.c
>>> +@@ -37,6 +37,7 @@
>>> + #endif /* _WIN32 */
>>> +
>>> + #include <errno.h>
>>> ++#include <fcntl.h>
>>> + #include <limits.h>
>>> + #include <stdio.h>
>>> + #include <string.h>
>>> +@@ -2244,4 +2245,77 @@ ssh_libssh_proxy_jumps(void)
>>> + return !(t != NULL && t[0] == '1');
>>> + }
>>> +
>>> ++/**
>>> ++ * @internal
>>> ++ *
>>> ++ * @brief Safely open a file containing some configuration.
>>> ++ *
>>> ++ * Runs checks if the file can be used as some configuration file (is
>>> regular
>>> ++ * file and is not too large). If so, returns the opened file (for
>>> reading).
>>> ++ * Otherwise logs error and returns `NULL`.
>>> ++ *
>>> ++ * @param filename The path to the file to open.
>>> ++ * @param max_file_size Maximum file size that is accepted.
>>> ++ *
>>> ++ * @returns the opened file or `NULL` on error.
>>> ++ */
>>> ++FILE *ssh_strict_fopen(const char *filename, size_t max_file_size)
>>> ++{
>>> ++ FILE *f = NULL;
>>> ++ struct stat sb;
>>> ++ char err_msg[SSH_ERRNO_MSG_MAX] = {0};
>>> ++ int r, fd;
>>> ++
>>> ++ /* open first to avoid TOCTOU */
>>> ++ fd = open(filename, O_RDONLY);
>>> ++ if (fd == -1) {
>>> ++ SSH_LOG(SSH_LOG_RARE,
>>> ++ "Failed to open a file %s for reading: %s",
>>> ++ filename,
>>> ++ ssh_strerror(errno, err_msg, SSH_ERRNO_MSG_MAX));
>>> ++ return NULL;
>>> ++ }
>>> ++
>>> ++ /* Check the file is sensible for a configuration file */
>>> ++ r = fstat(fd, &sb);
>>> ++ if (r != 0) {
>>> ++ SSH_LOG(SSH_LOG_RARE,
>>> ++ "Failed to stat %s: %s",
>>> ++ filename,
>>> ++ ssh_strerror(errno, err_msg, SSH_ERRNO_MSG_MAX));
>>> ++ close(fd);
>>> ++ return NULL;
>>> ++ }
>>> ++ if ((sb.st_mode & S_IFMT) != S_IFREG) {
>>> ++ SSH_LOG(SSH_LOG_RARE,
>>> ++ "The file %s is not a regular file: skipping",
>>> ++ filename);
>>> ++ close(fd);
>>> ++ return NULL;
>>> ++ }
>>> ++
>>> ++ if ((size_t)sb.st_size > max_file_size) {
>>> ++ SSH_LOG(SSH_LOG_RARE,
>>> ++ "The file %s is too large (%jd MB > %zu MB): skipping",
>>> ++ filename,
>>> ++ (intmax_t)sb.st_size / 1024 / 1024,
>>> ++ max_file_size / 1024 / 1024);
>>> ++ close(fd);
>>> ++ return NULL;
>>> ++ }
>>> ++
>>> ++ f = fdopen(fd, "r");
>>> ++ if (f == NULL) {
>>> ++ SSH_LOG(SSH_LOG_RARE,
>>> ++ "Failed to open a file %s for reading: %s",
>>> ++ filename,
>>> ++ ssh_strerror(r, err_msg, SSH_ERRNO_MSG_MAX));
>>> ++ close(fd);
>>> ++ return NULL;
>>> ++ }
>>> ++
>>> ++ /* the flcose() will close also the underlying fd */
>>> ++ return f;
>>> ++}
>>> ++
>>> + /** @} */
>>> +diff --git a/tests/unittests/torture_config.c
>>> b/tests/unittests/torture_config.c
>>> +index fcfe8fbc..0cb31a76 100644
>>> +--- a/tests/unittests/torture_config.c
>>> ++++ b/tests/unittests/torture_config.c
>>> +@@ -2675,6 +2675,23 @@ static void torture_config_match_complex(void
>>> **state)
>>> + ssh_string_free_char(v);
>>> + }
>>> +
>>> ++/* Invalid configuration files
>>> ++ */
>>> ++static void torture_config_invalid(void **state)
>>> ++{
>>> ++ ssh_session session = *state;
>>> ++
>>> ++ ssh_options_set(session, SSH_OPTIONS_HOST, "Bar");
>>> ++
>>> ++ /* non-regular file -- ignored (or missing on non-unix) so OK */
>>> ++ _parse_config(session, "/dev/random", NULL, SSH_OK);
>>> ++
>>> ++#ifndef _WIN32
>>> ++ /* huge file -- ignored (or missing on non-unix) so OK */
>>> ++ _parse_config(session, "/proc/kcore", NULL, SSH_OK);
>>> ++#endif
>>> ++}
>>> ++
>>> + int torture_run_tests(void)
>>> + {
>>> + int rc;
>>> +@@ -2771,6 +2788,9 @@ int torture_run_tests(void)
>>> + setup, teardown),
>>> + cmocka_unit_test_setup_teardown(torture_config_match_complex,
>>> + setup, teardown),
>>> ++ cmocka_unit_test_setup_teardown(torture_config_invalid,
>>> ++ setup,
>>> ++ teardown),
>>> + };
>>> +
>>> +
>>> +--
>>> +2.51.0
>>> +
>>> diff --git a/meta-oe/recipes-support/libssh/libssh_0.11.3.bb
>>> b/meta-oe/recipes-support/libssh/libssh_0.11.3.bb
>>> index 193ff3512d..c552692bde 100644
>>> --- a/meta-oe/recipes-support/libssh/libssh_0.11.3.bb
>>> +++ b/meta-oe/recipes-support/libssh/libssh_0.11.3.bb
>>> @@ -14,6 +14,7 @@ SRC_URI =
>>> "git://git.libssh.org/projects/libssh.git;protocol=https;branch=stable
>>> file://CVE-2026-0968_p1.patch \
>>> file://CVE-2026-0968_p2.patch \
>>> file://CVE-2026-0967.patch \
>>> + file://CVE-2026-0965.patch \
>>> "
>>> 
>>> SRC_URI:append:toolchain-clang = "
>>> file://0001-CompilerChecks.cmake-drop-Wunused-variable-flag.patch"
>>> --
>>> 2.35.6
>>> 
>>> 
>>> 
>>> 
>> 
>>


-- 
Yoann Congal
Smile ECS



^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [oe] [meta-oe][whinlatter][PATCH 3/3] libssh: Fix CVE-2026-0965
  2026-04-09  4:25   ` [meta-oe][whinlatter][PATCH " Deepak Rathore
  2026-04-09  8:26     ` [oe] " Yoann Congal
@ 2026-04-09  8:30     ` Gyorgy Sarvari
  1 sibling, 0 replies; 5+ messages in thread
From: Gyorgy Sarvari @ 2026-04-09  8:30 UTC (permalink / raw)
  To: deeratho, openembedded-devel



On 4/9/26 06:25, Deepak Rathore via lists.openembedded.org wrote:
> Hi Ankur,
> 
> Thank you for your review and response.
> 
> As previously indicated by the maintainer in this thread (openembedded-
> core@lists.openembedded.org | Inquiry Regarding Package Upgrade Approach
> vs. Manual CVE Fixes in LTS Releases <https://lists.openembedded.org/g/
> openembedded-core/topic/118275693>), package upgrades are not considered
> for stable and LTS branches for stability. Only bug fixes and security
> fixes are accepted. Accordingly, I have submitted CVE fix patches
> instead of performing a package upgrade.
> 

That mailchain also mentions: 'As stated, "General version upgrades" are
unacceptable but there is an
exception for "Changes to follow an upstream stable series or LTS that
aligns with the original release (based on compatibility)'

meta-oe stable branches accept updates also in line with this statement.

Which change in this version do you deem to be inappropriate for a
stable branch?

One thing that's worth pointing out is that there are 6 participants in
the linked email exchange, but 0 meta-openembedded maintainers. While
meta-oe and oe-core are closely related, they are separate projects and
if you have a question about meta-oe, I'd recommend to ask it here
instead of using other random mailing lists.


> Regards,
> Deepak
> 
>  
>  
> On Wed, Apr 8, 2026 at 10:49 AM, Ankur Tyagi wrote:
> 
>     I think we can upgrade to v0.11.4
> 
>     https://git.libssh.org/projects/libssh.git/tree/CHANGELOG?
>     h=stable-0.11 <https://git.libssh.org/projects/libssh.git/tree/
>     CHANGELOG?h=stable-0.11>
> 
>     version 0.11.4 (released 2026-02-10)
>     * Security:
>     * CVE-2025-14821: libssh loads configuration files from the C:\etc
>     directory
>     on Windows
>     * CVE-2026-0964: SCP Protocol Path Traversal in ssh_scp_pull_request()
>     * CVE-2026-0965: Possible Denial of Service when parsing unexpected
>     configuration files
>     * CVE-2026-0966: Buffer underflow in ssh_get_hexa() on invalid input
>     * CVE-2026-0967: Specially crafted patterns could cause DoS
>     * CVE-2026-0968: OOB Read in sftp_parse_longname()
>     * libssh-2026-sftp-extensions: Read buffer overrun when handling SFTP
>     extensions
>     * Stability and compatibility improvements of ProxyJum
> 
> 
> 
>     On Mon, Apr 6, 2026 at 11:56 PM Deepak Rathore via
>     lists.openembedded.org <deeratho=cisco.com@lists.openembedded.org>
>     wrote:
> 
> 
>         From: Deepak Rathore <deeratho@cisco.com>
> 
>         Pick the patch [1] as mentioned in [2]
> 
>         [1] https://git.libssh.org/projects/libssh.git/commit/?
>         id=bf390a042623e02abc8f421c4c5fadc0429a8a76 <https://
>         git.libssh.org/projects/libssh.git/commit/?
>         id=bf390a042623e02abc8f421c4c5fadc0429a8a76>
>         [2] https://security-tracker.debian.org/tracker/CVE-2026-0965
>         <https://security-tracker.debian.org/tracker/CVE-2026-0965>
> 
>         Signed-off-by: Deepak Rathore <deeratho@cisco.com>
>         ---
>         .../libssh/libssh/CVE-2026-0965.patch | 286 ++++++++++++++++++
>         .../recipes-support/libssh/libssh_0.11.3.bb | 1 +
>         2 files changed, 287 insertions(+)
>         create mode 100644 meta-oe/recipes-support/libssh/libssh/
>         CVE-2026-0965.patch
> 
>         diff --git a/meta-oe/recipes-support/libssh/libssh/
>         CVE-2026-0965.patch b/meta-oe/recipes-support/libssh/libssh/
>         CVE-2026-0965.patch
>         new file mode 100644
>         index 0000000000..57cb9d6170
>         --- /dev/null
>         +++ b/meta-oe/recipes-support/libssh/libssh/CVE-2026-0965.patch
>         @@ -0,0 +1,286 @@
>         +From 5858a988942d2e25985b34b8c40ce2792cbbe853 Mon Sep 17
>         00:00:00 2001
>         +From: Jakub Jelen <jjelen@redhat.com>
>         +Date: Thu, 11 Dec 2025 17:33:19 +0100
>         +Subject: [PATCH 4/4] CVE-2026-0965 config: Do not attempt to
>         read non-regular
>         + and too large configuration files
>         +
>         +Changes also the reading of known_hosts to use the new helper
>         function
>         +
>         +CVE: CVE-2026-0965
>         +Upstream-Status: Backport [https://git.libssh.org/projects/
>         libssh.git/commit/?id=bf390a042623e02abc8f421c4c5fadc0429a8a76
>         <https://git.libssh.org/projects/libssh.git/commit/?
>         id=bf390a042623e02abc8f421c4c5fadc0429a8a76>]
>         +
>         +Signed-off-by: Jakub Jelen <jjelen@redhat.com>
>         +Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
>         +(cherry picked from commit
>         a5eb30dbfd8f3526b2d04bd9f0a3803b665f5798)
>         +(cherry picked from commit
>         bf390a042623e02abc8f421c4c5fadc0429a8a76)
>         +Signed-off-by: Deepak Rathore <deeratho@cisco.com>
>         +---
>         + include/libssh/misc.h | 3 ++
>         + include/libssh/priv.h | 3 ++
>         + src/bind_config.c | 4 +-
>         + src/config.c | 8 ++--
>         + src/dh-gex.c | 4 +-
>         + src/known_hosts.c | 2 +-
>         + src/knownhosts.c | 2 +-
>         + src/misc.c | 74 ++++++++++++++++++++++++++++++++
>         + tests/unittests/torture_config.c | 20 +++++++++
>         + 9 files changed, 110 insertions(+), 10 deletions(-)
>         +
>         +diff --git a/include/libssh/misc.h b/include/libssh/misc.h
>         +index ab726a0e..8eab94ee 100644
>         +--- a/include/libssh/misc.h
>         ++++ b/include/libssh/misc.h
>         +@@ -36,6 +36,7 @@
>         + #include <sys/types.h>
>         + #include <stdbool.h>
>         + #endif /* _WIN32 */
>         ++#include <stdio.h>
>         +
>         + #ifdef __cplusplus
>         + extern "C" {
>         +@@ -136,6 +137,8 @@ int ssh_check_username_syntax(const char
>         *username);
>         + void ssh_proxyjumps_free(struct ssh_list *proxy_jump_list);
>         + bool ssh_libssh_proxy_jumps(void);
>         +
>         ++FILE *ssh_strict_fopen(const char *filename, size_t
>         max_file_size);
>         ++
>         + #ifdef __cplusplus
>         + }
>         + #endif
>         +diff --git a/include/libssh/priv.h b/include/libssh/priv.h
>         +index 35fd8506..62069970 100644
>         +--- a/include/libssh/priv.h
>         ++++ b/include/libssh/priv.h
>         +@@ -473,6 +473,9 @@ char *ssh_strerror(int err_num, char *buf,
>         size_t buflen);
>         + #define SSH_TTY_MODES_MAX_BUFSIZE (55 * 5 + 1)
>         + int encode_current_tty_opts(unsigned char *buf, size_t buflen);
>         +
>         ++/** The default maximum file size for a configuration file */
>         ++#define SSH_MAX_CONFIG_FILE_SIZE 16 * 1024 * 1024
>         ++
>         + #ifdef __cplusplus
>         + }
>         + #endif
>         +diff --git a/src/bind_config.c b/src/bind_config.c
>         +index 9e4a7fd4..c12f1003 100644
>         +--- a/src/bind_config.c
>         ++++ b/src/bind_config.c
>         +@@ -212,7 +212,7 @@ local_parse_file(ssh_bind bind,
>         + return;
>         + }
>         +
>         +- f = fopen(filename, "r");
>         ++ f = ssh_strict_fopen(filename, SSH_MAX_CONFIG_FILE_SIZE);
>         + if (f == NULL) {
>         + SSH_LOG(SSH_LOG_RARE, "Cannot find file %s to load",
>         + filename);
>         +@@ -636,7 +636,7 @@ int ssh_bind_config_parse_file(ssh_bind
>         bind, const char *filename)
>         + * option to be redefined later by another file. */
>         + uint8_t seen[BIND_CFG_MAX] = {0};
>         +
>         +- f = fopen(filename, "r");
>         ++ f = ssh_strict_fopen(filename, SSH_MAX_CONFIG_FILE_SIZE);
>         + if (f == NULL) {
>         + return 0;
>         + }
>         +diff --git a/src/config.c b/src/config.c
>         +index b4171efd..1ffad537 100644
>         +--- a/src/config.c
>         ++++ b/src/config.c
>         +@@ -223,10 +223,9 @@ local_parse_file(ssh_session session,
>         + return;
>         + }
>         +
>         +- f = fopen(filename, "r");
>         ++ f = ssh_strict_fopen(filename, SSH_MAX_CONFIG_FILE_SIZE);
>         + if (f == NULL) {
>         +- SSH_LOG(SSH_LOG_RARE, "Cannot find file %s to load",
>         +- filename);
>         ++ /* The underlying function logs the reasons */
>         + return;
>         + }
>         +
>         +@@ -1466,8 +1465,9 @@ int ssh_config_parse_file(ssh_session
>         session, const char *filename)
>         + int parsing, rv;
>         + bool global = 0;
>         +
>         +- f = fopen(filename, "r");
>         ++ f = ssh_strict_fopen(filename, SSH_MAX_CONFIG_FILE_SIZE);
>         + if (f == NULL) {
>         ++ /* The underlying function logs the reasons */
>         + return 0;
>         + }
>         +
>         +diff --git a/src/dh-gex.c b/src/dh-gex.c
>         +index 46ba934e..428a5655 100644
>         +--- a/src/dh-gex.c
>         ++++ b/src/dh-gex.c
>         +@@ -519,9 +519,9 @@ static int ssh_retrieve_dhgroup(char
>         *moduli_file,
>         + }
>         +
>         + if (moduli_file != NULL)
>         +- moduli = fopen(moduli_file, "r");
>         ++ moduli = ssh_strict_fopen(moduli_file, SSH_MAX_CONFIG_FILE_SIZE);
>         + else
>         +- moduli = fopen(MODULI_FILE, "r");
>         ++ moduli = ssh_strict_fopen(MODULI_FILE, SSH_MAX_CONFIG_FILE_SIZE);
>         +
>         + if (moduli == NULL) {
>         + char err_msg[SSH_ERRNO_MSG_MAX] = {0};
>         +diff --git a/src/known_hosts.c b/src/known_hosts.c
>         +index 3ef83e21..701576ce 100644
>         +--- a/src/known_hosts.c
>         ++++ b/src/known_hosts.c
>         +@@ -83,7 +83,7 @@ static struct ssh_tokens_st
>         *ssh_get_knownhost_line(FILE **file,
>         + struct ssh_tokens_st *tokens = NULL;
>         +
>         + if (*file == NULL) {
>         +- *file = fopen(filename,"r");
>         ++ *file = ssh_strict_fopen(filename, SSH_MAX_CONFIG_FILE_SIZE);
>         + if (*file == NULL) {
>         + return NULL;
>         + }
>         +diff --git a/src/knownhosts.c b/src/knownhosts.c
>         +index a2d08a75..3ab468de 100644
>         +--- a/src/knownhosts.c
>         ++++ b/src/knownhosts.c
>         +@@ -232,7 +232,7 @@ static int
>         ssh_known_hosts_read_entries(const char *match,
>         + FILE *fp = NULL;
>         + int rc;
>         +
>         +- fp = fopen(filename, "r");
>         ++ fp = ssh_strict_fopen(filename, SSH_MAX_CONFIG_FILE_SIZE);
>         + if (fp == NULL) {
>         + char err_msg[SSH_ERRNO_MSG_MAX] = {0};
>         + SSH_LOG(SSH_LOG_TRACE, "Failed to open the known_hosts file
>         '%s': %s",
>         +diff --git a/src/misc.c b/src/misc.c
>         +index 774211fb..3968e6bc 100644
>         +--- a/src/misc.c
>         ++++ b/src/misc.c
>         +@@ -37,6 +37,7 @@
>         + #endif /* _WIN32 */
>         +
>         + #include <errno.h>
>         ++#include <fcntl.h>
>         + #include <limits.h>
>         + #include <stdio.h>
>         + #include <string.h>
>         +@@ -2244,4 +2245,77 @@ ssh_libssh_proxy_jumps(void)
>         + return !(t != NULL && t[0] == '1');
>         + }
>         +
>         ++/**
>         ++ * @internal
>         ++ *
>         ++ * @brief Safely open a file containing some configuration.
>         ++ *
>         ++ * Runs checks if the file can be used as some configuration
>         file (is regular
>         ++ * file and is not too large). If so, returns the opened file
>         (for reading).
>         ++ * Otherwise logs error and returns `NULL`.
>         ++ *
>         ++ * @param filename The path to the file to open.
>         ++ * @param max_file_size Maximum file size that is accepted.
>         ++ *
>         ++ * @returns the opened file or `NULL` on error.
>         ++ */
>         ++FILE *ssh_strict_fopen(const char *filename, size_t max_file_size)
>         ++{
>         ++ FILE *f = NULL;
>         ++ struct stat sb;
>         ++ char err_msg[SSH_ERRNO_MSG_MAX] = {0};
>         ++ int r, fd;
>         ++
>         ++ /* open first to avoid TOCTOU */
>         ++ fd = open(filename, O_RDONLY);
>         ++ if (fd == -1) {
>         ++ SSH_LOG(SSH_LOG_RARE,
>         ++ "Failed to open a file %s for reading: %s",
>         ++ filename,
>         ++ ssh_strerror(errno, err_msg, SSH_ERRNO_MSG_MAX));
>         ++ return NULL;
>         ++ }
>         ++
>         ++ /* Check the file is sensible for a configuration file */
>         ++ r = fstat(fd, &sb);
>         ++ if (r != 0) {
>         ++ SSH_LOG(SSH_LOG_RARE,
>         ++ "Failed to stat %s: %s",
>         ++ filename,
>         ++ ssh_strerror(errno, err_msg, SSH_ERRNO_MSG_MAX));
>         ++ close(fd);
>         ++ return NULL;
>         ++ }
>         ++ if ((sb.st_mode & S_IFMT) != S_IFREG) {
>         ++ SSH_LOG(SSH_LOG_RARE,
>         ++ "The file %s is not a regular file: skipping",
>         ++ filename);
>         ++ close(fd);
>         ++ return NULL;
>         ++ }
>         ++
>         ++ if ((size_t)sb.st_size > max_file_size) {
>         ++ SSH_LOG(SSH_LOG_RARE,
>         ++ "The file %s is too large (%jd MB > %zu MB): skipping",
>         ++ filename,
>         ++ (intmax_t)sb.st_size / 1024 / 1024,
>         ++ max_file_size / 1024 / 1024);
>         ++ close(fd);
>         ++ return NULL;
>         ++ }
>         ++
>         ++ f = fdopen(fd, "r");
>         ++ if (f == NULL) {
>         ++ SSH_LOG(SSH_LOG_RARE,
>         ++ "Failed to open a file %s for reading: %s",
>         ++ filename,
>         ++ ssh_strerror(r, err_msg, SSH_ERRNO_MSG_MAX));
>         ++ close(fd);
>         ++ return NULL;
>         ++ }
>         ++
>         ++ /* the flcose() will close also the underlying fd */
>         ++ return f;
>         ++}
>         ++
>         + /** @} */
>         +diff --git a/tests/unittests/torture_config.c b/tests/
>         unittests/torture_config.c
>         +index fcfe8fbc..0cb31a76 100644
>         +--- a/tests/unittests/torture_config.c
>         ++++ b/tests/unittests/torture_config.c
>         +@@ -2675,6 +2675,23 @@ static void
>         torture_config_match_complex(void **state)
>         + ssh_string_free_char(v);
>         + }
>         +
>         ++/* Invalid configuration files
>         ++ */
>         ++static void torture_config_invalid(void **state)
>         ++{
>         ++ ssh_session session = *state;
>         ++
>         ++ ssh_options_set(session, SSH_OPTIONS_HOST, "Bar");
>         ++
>         ++ /* non-regular file -- ignored (or missing on non-unix) so OK */
>         ++ _parse_config(session, "/dev/random", NULL, SSH_OK);
>         ++
>         ++#ifndef _WIN32
>         ++ /* huge file -- ignored (or missing on non-unix) so OK */
>         ++ _parse_config(session, "/proc/kcore", NULL, SSH_OK);
>         ++#endif
>         ++}
>         ++
>         + int torture_run_tests(void)
>         + {
>         + int rc;
>         +@@ -2771,6 +2788,9 @@ int torture_run_tests(void)
>         + setup, teardown),
>         + cmocka_unit_test_setup_teardown(torture_config_match_complex,
>         + setup, teardown),
>         ++ cmocka_unit_test_setup_teardown(torture_config_invalid,
>         ++ setup,
>         ++ teardown),
>         + };
>         +
>         +
>         +--
>         +2.51.0
>         +
>         diff --git a/meta-oe/recipes-support/libssh/libssh_0.11.3.bb b/
>         meta-oe/recipes-support/libssh/libssh_0.11.3.bb
>         index 193ff3512d..c552692bde 100644
>         --- a/meta-oe/recipes-support/libssh/libssh_0.11.3.bb
>         +++ b/meta-oe/recipes-support/libssh/libssh_0.11.3.bb
>         @@ -14,6 +14,7 @@ SRC_URI = "git://git.libssh.org/projects/
>         libssh.git;protocol=https;branch=stable
>         file://CVE-2026-0968_p1.patch \
>         file://CVE-2026-0968_p2.patch \
>         file://CVE-2026-0967.patch \
>         + file://CVE-2026-0965.patch \
>         "
> 
>         SRC_URI:append:toolchain-clang = " file://0001-
>         CompilerChecks.cmake-drop-Wunused-variable-flag.patch"
>         --
>         2.35.6
> 
> 
> 
> On Wed, Apr 8, 2026 at 10:49 AM, Ankur Tyagi wrote:
> 
>     I think we can upgrade to v0.11.4
> 
>     https://git.libssh.org/projects/libssh.git/tree/CHANGELOG?
>     h=stable-0.11 <https://git.libssh.org/projects/libssh.git/tree/
>     CHANGELOG?h=stable-0.11>
> 
>     version 0.11.4 (released 2026-02-10)
>     * Security:
>     * CVE-2025-14821: libssh loads configuration files from the C:\etc
>     directory
>     on Windows
>     * CVE-2026-0964: SCP Protocol Path Traversal in ssh_scp_pull_request()
>     * CVE-2026-0965: Possible Denial of Service when parsing unexpected
>     configuration files
>     * CVE-2026-0966: Buffer underflow in ssh_get_hexa() on invalid input
>     * CVE-2026-0967: Specially crafted patterns could cause DoS
>     * CVE-2026-0968: OOB Read in sftp_parse_longname()
>     * libssh-2026-sftp-extensions: Read buffer overrun when handling SFTP
>     extensions
>     * Stability and compatibility improvements of ProxyJum
> 
> 
> 
>     On Mon, Apr 6, 2026 at 11:56 PM Deepak Rathore via
>     lists.openembedded.org <deeratho=cisco.com@lists.openembedded.org>
>     wrote:
> 
> 
>         From: Deepak Rathore <deeratho@cisco.com>
> 
>         Pick the patch [1] as mentioned in [2]
> 
>         [1] https://git.libssh.org/projects/libssh.git/commit/?
>         id=bf390a042623e02abc8f421c4c5fadc0429a8a76 <https://
>         git.libssh.org/projects/libssh.git/commit/?
>         id=bf390a042623e02abc8f421c4c5fadc0429a8a76>
>         [2] https://security-tracker.debian.org/tracker/CVE-2026-0965
>         <https://security-tracker.debian.org/tracker/CVE-2026-0965>
> 
>         Signed-off-by: Deepak Rathore <deeratho@cisco.com>
>         ---
>         .../libssh/libssh/CVE-2026-0965.patch | 286 ++++++++++++++++++
>         .../recipes-support/libssh/libssh_0.11.3.bb | 1 +
>         2 files changed, 287 insertions(+)
>         create mode 100644 meta-oe/recipes-support/libssh/libssh/
>         CVE-2026-0965.patch
> 
>         diff --git a/meta-oe/recipes-support/libssh/libssh/
>         CVE-2026-0965.patch b/meta-oe/recipes-support/libssh/libssh/
>         CVE-2026-0965.patch
>         new file mode 100644
>         index 0000000000..57cb9d6170
>         --- /dev/null
>         +++ b/meta-oe/recipes-support/libssh/libssh/CVE-2026-0965.patch
>         @@ -0,0 +1,286 @@
>         +From 5858a988942d2e25985b34b8c40ce2792cbbe853 Mon Sep 17
>         00:00:00 2001
>         +From: Jakub Jelen <jjelen@redhat.com>
>         +Date: Thu, 11 Dec 2025 17:33:19 +0100
>         +Subject: [PATCH 4/4] CVE-2026-0965 config: Do not attempt to
>         read non-regular
>         + and too large configuration files
>         +
>         +Changes also the reading of known_hosts to use the new helper
>         function
>         +
>         +CVE: CVE-2026-0965
>         +Upstream-Status: Backport [https://git.libssh.org/projects/
>         libssh.git/commit/?id=bf390a042623e02abc8f421c4c5fadc0429a8a76
>         <https://git.libssh.org/projects/libssh.git/commit/?
>         id=bf390a042623e02abc8f421c4c5fadc0429a8a76>]
>         +
>         +Signed-off-by: Jakub Jelen <jjelen@redhat.com>
>         +Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
>         +(cherry picked from commit
>         a5eb30dbfd8f3526b2d04bd9f0a3803b665f5798)
>         +(cherry picked from commit
>         bf390a042623e02abc8f421c4c5fadc0429a8a76)
>         +Signed-off-by: Deepak Rathore <deeratho@cisco.com>
>         +---
>         + include/libssh/misc.h | 3 ++
>         + include/libssh/priv.h | 3 ++
>         + src/bind_config.c | 4 +-
>         + src/config.c | 8 ++--
>         + src/dh-gex.c | 4 +-
>         + src/known_hosts.c | 2 +-
>         + src/knownhosts.c | 2 +-
>         + src/misc.c | 74 ++++++++++++++++++++++++++++++++
>         + tests/unittests/torture_config.c | 20 +++++++++
>         + 9 files changed, 110 insertions(+), 10 deletions(-)
>         +
>         +diff --git a/include/libssh/misc.h b/include/libssh/misc.h
>         +index ab726a0e..8eab94ee 100644
>         +--- a/include/libssh/misc.h
>         ++++ b/include/libssh/misc.h
>         +@@ -36,6 +36,7 @@
>         + #include <sys/types.h>
>         + #include <stdbool.h>
>         + #endif /* _WIN32 */
>         ++#include <stdio.h>
>         +
>         + #ifdef __cplusplus
>         + extern "C" {
>         +@@ -136,6 +137,8 @@ int ssh_check_username_syntax(const char
>         *username);
>         + void ssh_proxyjumps_free(struct ssh_list *proxy_jump_list);
>         + bool ssh_libssh_proxy_jumps(void);
>         +
>         ++FILE *ssh_strict_fopen(const char *filename, size_t
>         max_file_size);
>         ++
>         + #ifdef __cplusplus
>         + }
>         + #endif
>         +diff --git a/include/libssh/priv.h b/include/libssh/priv.h
>         +index 35fd8506..62069970 100644
>         +--- a/include/libssh/priv.h
>         ++++ b/include/libssh/priv.h
>         +@@ -473,6 +473,9 @@ char *ssh_strerror(int err_num, char *buf,
>         size_t buflen);
>         + #define SSH_TTY_MODES_MAX_BUFSIZE (55 * 5 + 1)
>         + int encode_current_tty_opts(unsigned char *buf, size_t buflen);
>         +
>         ++/** The default maximum file size for a configuration file */
>         ++#define SSH_MAX_CONFIG_FILE_SIZE 16 * 1024 * 1024
>         ++
>         + #ifdef __cplusplus
>         + }
>         + #endif
>         +diff --git a/src/bind_config.c b/src/bind_config.c
>         +index 9e4a7fd4..c12f1003 100644
>         +--- a/src/bind_config.c
>         ++++ b/src/bind_config.c
>         +@@ -212,7 +212,7 @@ local_parse_file(ssh_bind bind,
>         + return;
>         + }
>         +
>         +- f = fopen(filename, "r");
>         ++ f = ssh_strict_fopen(filename, SSH_MAX_CONFIG_FILE_SIZE);
>         + if (f == NULL) {
>         + SSH_LOG(SSH_LOG_RARE, "Cannot find file %s to load",
>         + filename);
>         +@@ -636,7 +636,7 @@ int ssh_bind_config_parse_file(ssh_bind
>         bind, const char *filename)
>         + * option to be redefined later by another file. */
>         + uint8_t seen[BIND_CFG_MAX] = {0};
>         +
>         +- f = fopen(filename, "r");
>         ++ f = ssh_strict_fopen(filename, SSH_MAX_CONFIG_FILE_SIZE);
>         + if (f == NULL) {
>         + return 0;
>         + }
>         +diff --git a/src/config.c b/src/config.c
>         +index b4171efd..1ffad537 100644
>         +--- a/src/config.c
>         ++++ b/src/config.c
>         +@@ -223,10 +223,9 @@ local_parse_file(ssh_session session,
>         + return;
>         + }
>         +
>         +- f = fopen(filename, "r");
>         ++ f = ssh_strict_fopen(filename, SSH_MAX_CONFIG_FILE_SIZE);
>         + if (f == NULL) {
>         +- SSH_LOG(SSH_LOG_RARE, "Cannot find file %s to load",
>         +- filename);
>         ++ /* The underlying function logs the reasons */
>         + return;
>         + }
>         +
>         +@@ -1466,8 +1465,9 @@ int ssh_config_parse_file(ssh_session
>         session, const char *filename)
>         + int parsing, rv;
>         + bool global = 0;
>         +
>         +- f = fopen(filename, "r");
>         ++ f = ssh_strict_fopen(filename, SSH_MAX_CONFIG_FILE_SIZE);
>         + if (f == NULL) {
>         ++ /* The underlying function logs the reasons */
>         + return 0;
>         + }
>         +
>         +diff --git a/src/dh-gex.c b/src/dh-gex.c
>         +index 46ba934e..428a5655 100644
>         +--- a/src/dh-gex.c
>         ++++ b/src/dh-gex.c
>         +@@ -519,9 +519,9 @@ static int ssh_retrieve_dhgroup(char
>         *moduli_file,
>         + }
>         +
>         + if (moduli_file != NULL)
>         +- moduli = fopen(moduli_file, "r");
>         ++ moduli = ssh_strict_fopen(moduli_file, SSH_MAX_CONFIG_FILE_SIZE);
>         + else
>         +- moduli = fopen(MODULI_FILE, "r");
>         ++ moduli = ssh_strict_fopen(MODULI_FILE, SSH_MAX_CONFIG_FILE_SIZE);
>         +
>         + if (moduli == NULL) {
>         + char err_msg[SSH_ERRNO_MSG_MAX] = {0};
>         +diff --git a/src/known_hosts.c b/src/known_hosts.c
>         +index 3ef83e21..701576ce 100644
>         +--- a/src/known_hosts.c
>         ++++ b/src/known_hosts.c
>         +@@ -83,7 +83,7 @@ static struct ssh_tokens_st
>         *ssh_get_knownhost_line(FILE **file,
>         + struct ssh_tokens_st *tokens = NULL;
>         +
>         + if (*file == NULL) {
>         +- *file = fopen(filename,"r");
>         ++ *file = ssh_strict_fopen(filename, SSH_MAX_CONFIG_FILE_SIZE);
>         + if (*file == NULL) {
>         + return NULL;
>         + }
>         +diff --git a/src/knownhosts.c b/src/knownhosts.c
>         +index a2d08a75..3ab468de 100644
>         +--- a/src/knownhosts.c
>         ++++ b/src/knownhosts.c
>         +@@ -232,7 +232,7 @@ static int
>         ssh_known_hosts_read_entries(const char *match,
>         + FILE *fp = NULL;
>         + int rc;
>         +
>         +- fp = fopen(filename, "r");
>         ++ fp = ssh_strict_fopen(filename, SSH_MAX_CONFIG_FILE_SIZE);
>         + if (fp == NULL) {
>         + char err_msg[SSH_ERRNO_MSG_MAX] = {0};
>         + SSH_LOG(SSH_LOG_TRACE, "Failed to open the known_hosts file
>         '%s': %s",
>         +diff --git a/src/misc.c b/src/misc.c
>         +index 774211fb..3968e6bc 100644
>         +--- a/src/misc.c
>         ++++ b/src/misc.c
>         +@@ -37,6 +37,7 @@
>         + #endif /* _WIN32 */
>         +
>         + #include <errno.h>
>         ++#include <fcntl.h>
>         + #include <limits.h>
>         + #include <stdio.h>
>         + #include <string.h>
>         +@@ -2244,4 +2245,77 @@ ssh_libssh_proxy_jumps(void)
>         + return !(t != NULL && t[0] == '1');
>         + }
>         +
>         ++/**
>         ++ * @internal
>         ++ *
>         ++ * @brief Safely open a file containing some configuration.
>         ++ *
>         ++ * Runs checks if the file can be used as some configuration
>         file (is regular
>         ++ * file and is not too large). If so, returns the opened file
>         (for reading).
>         ++ * Otherwise logs error and returns `NULL`.
>         ++ *
>         ++ * @param filename The path to the file to open.
>         ++ * @param max_file_size Maximum file size that is accepted.
>         ++ *
>         ++ * @returns the opened file or `NULL` on error.
>         ++ */
>         ++FILE *ssh_strict_fopen(const char *filename, size_t max_file_size)
>         ++{
>         ++ FILE *f = NULL;
>         ++ struct stat sb;
>         ++ char err_msg[SSH_ERRNO_MSG_MAX] = {0};
>         ++ int r, fd;
>         ++
>         ++ /* open first to avoid TOCTOU */
>         ++ fd = open(filename, O_RDONLY);
>         ++ if (fd == -1) {
>         ++ SSH_LOG(SSH_LOG_RARE,
>         ++ "Failed to open a file %s for reading: %s",
>         ++ filename,
>         ++ ssh_strerror(errno, err_msg, SSH_ERRNO_MSG_MAX));
>         ++ return NULL;
>         ++ }
>         ++
>         ++ /* Check the file is sensible for a configuration file */
>         ++ r = fstat(fd, &sb);
>         ++ if (r != 0) {
>         ++ SSH_LOG(SSH_LOG_RARE,
>         ++ "Failed to stat %s: %s",
>         ++ filename,
>         ++ ssh_strerror(errno, err_msg, SSH_ERRNO_MSG_MAX));
>         ++ close(fd);
>         ++ return NULL;
>         ++ }
>         ++ if ((sb.st_mode & S_IFMT) != S_IFREG) {
>         ++ SSH_LOG(SSH_LOG_RARE,
>         ++ "The file %s is not a regular file: skipping",
>         ++ filename);
>         ++ close(fd);
>         ++ return NULL;
>         ++ }
>         ++
>         ++ if ((size_t)sb.st_size > max_file_size) {
>         ++ SSH_LOG(SSH_LOG_RARE,
>         ++ "The file %s is too large (%jd MB > %zu MB): skipping",
>         ++ filename,
>         ++ (intmax_t)sb.st_size / 1024 / 1024,
>         ++ max_file_size / 1024 / 1024);
>         ++ close(fd);
>         ++ return NULL;
>         ++ }
>         ++
>         ++ f = fdopen(fd, "r");
>         ++ if (f == NULL) {
>         ++ SSH_LOG(SSH_LOG_RARE,
>         ++ "Failed to open a file %s for reading: %s",
>         ++ filename,
>         ++ ssh_strerror(r, err_msg, SSH_ERRNO_MSG_MAX));
>         ++ close(fd);
>         ++ return NULL;
>         ++ }
>         ++
>         ++ /* the flcose() will close also the underlying fd */
>         ++ return f;
>         ++}
>         ++
>         + /** @} */
>         +diff --git a/tests/unittests/torture_config.c b/tests/
>         unittests/torture_config.c
>         +index fcfe8fbc..0cb31a76 100644
>         +--- a/tests/unittests/torture_config.c
>         ++++ b/tests/unittests/torture_config.c
>         +@@ -2675,6 +2675,23 @@ static void
>         torture_config_match_complex(void **state)
>         + ssh_string_free_char(v);
>         + }
>         +
>         ++/* Invalid configuration files
>         ++ */
>         ++static void torture_config_invalid(void **state)
>         ++{
>         ++ ssh_session session = *state;
>         ++
>         ++ ssh_options_set(session, SSH_OPTIONS_HOST, "Bar");
>         ++
>         ++ /* non-regular file -- ignored (or missing on non-unix) so OK */
>         ++ _parse_config(session, "/dev/random", NULL, SSH_OK);
>         ++
>         ++#ifndef _WIN32
>         ++ /* huge file -- ignored (or missing on non-unix) so OK */
>         ++ _parse_config(session, "/proc/kcore", NULL, SSH_OK);
>         ++#endif
>         ++}
>         ++
>         + int torture_run_tests(void)
>         + {
>         + int rc;
>         +@@ -2771,6 +2788,9 @@ int torture_run_tests(void)
>         + setup, teardown),
>         + cmocka_unit_test_setup_teardown(torture_config_match_complex,
>         + setup, teardown),
>         ++ cmocka_unit_test_setup_teardown(torture_config_invalid,
>         ++ setup,
>         ++ teardown),
>         + };
>         +
>         +
>         +--
>         +2.51.0
>         +
>         diff --git a/meta-oe/recipes-support/libssh/libssh_0.11.3.bb b/
>         meta-oe/recipes-support/libssh/libssh_0.11.3.bb
>         index 193ff3512d..c552692bde 100644
>         --- a/meta-oe/recipes-support/libssh/libssh_0.11.3.bb
>         +++ b/meta-oe/recipes-support/libssh/libssh_0.11.3.bb
>         @@ -14,6 +14,7 @@ SRC_URI = "git://git.libssh.org/projects/
>         libssh.git;protocol=https;branch=stable
>         file://CVE-2026-0968_p1.patch \
>         file://CVE-2026-0968_p2.patch \
>         file://CVE-2026-0967.patch \
>         + file://CVE-2026-0965.patch \
>         "
> 
>         SRC_URI:append:toolchain-clang = " file://0001-
>         CompilerChecks.cmake-drop-Wunused-variable-flag.patch"
>         --
>         2.35.6
> 
> 
> 
> 
> 
> -=-=-=-=-=-=-=-=-=-=-=-
> Links: You receive all messages sent to this group.
> View/Reply Online (#126110): https://lists.openembedded.org/g/openembedded-devel/message/126110
> Mute This Topic: https://lists.openembedded.org/mt/118688803/6084445
> Group Owner: openembedded-devel+owner@lists.openembedded.org
> Unsubscribe: https://lists.openembedded.org/g/openembedded-devel/unsub [skandigraun@gmail.com]
> -=-=-=-=-=-=-=-=-=-=-=-
> 



^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2026-04-09  8:30 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-06 11:55 [oe][meta-oe][whinlatter][PATCH 3/3] libssh: Fix CVE-2026-0965 Deepak Rathore -X (deeratho - E INFOCHIPS PRIVATE LIMITED at Cisco)
2026-04-08  5:19 ` Ankur Tyagi
2026-04-09  4:25   ` [meta-oe][whinlatter][PATCH " Deepak Rathore
2026-04-09  8:26     ` [oe] " Yoann Congal
2026-04-09  8:30     ` Gyorgy Sarvari

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox