public inbox for openembedded-devel@lists.openembedded.org
 help / color / mirror / Atom feed
From: "Deepak Rathore" <deeratho@cisco.com>
To: openembedded-devel@lists.openembedded.org
Subject: Re: [meta-oe][whinlatter][PATCH 3/3] libssh: Fix CVE-2026-0965
Date: Wed, 08 Apr 2026 21:25:22 -0700	[thread overview]
Message-ID: <829031.1775708722131603063@lists.openembedded.org> (raw)
In-Reply-To: <CADySD0Hw0=QGHcd0Xfendesh8hiTfpxHb5T7boTSbXL5SSwUMw@mail.gmail.com>

[-- 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 --]

  reply	other threads:[~2026-04-09  4:25 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
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   ` Deepak Rathore [this message]
2026-04-09  8:26     ` [oe] [meta-oe][whinlatter][PATCH " Yoann Congal
2026-04-09  8:30     ` Gyorgy Sarvari

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=829031.1775708722131603063@lists.openembedded.org \
    --to=deeratho@cisco.com \
    --cc=openembedded-devel@lists.openembedded.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox