libssh: patch CVE-2026-0968

Backport patches [1] and [2] as mentioned in [3]

[1] https://git.libssh.org/projects/libssh.git/commit/?id=796d85f786dff62bd4bcc4408d9b7bbc855841e9
[2] https://git.libssh.org/projects/libssh.git/commit/?id=212121971fb26e1e00b72bd5402c0454a4d84c03
[3] https://security-tracker.debian.org/tracker/CVE-2026-0968

Certain functions from sftp.c were moved to a new file sftp_common.c
in version 0.11.0 by following commit:
https://git.libssh.org/projects/libssh.git/commit/src/sftp_common.c?id=c3e03ab4651e4f3382e3a51c0273ade894f0c48a

This is the backport of the changes using the original file sftp.c

Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
Signed-off-by: Anuj Mittal <anuj.mittal@oss.qualcomm.com>
This commit is contained in:
Ankur Tyagi
2026-04-28 17:01:06 +12:00
committed by Anuj Mittal
parent 5ce7602ce1
commit 015b974b6b
3 changed files with 202 additions and 0 deletions
@@ -0,0 +1,64 @@
From 9fd388141c973ba6fb7d45966c25d1fad9e1d419 Mon Sep 17 00:00:00 2001
From: Jakub Jelen <jjelen@redhat.com>
Date: Mon, 22 Dec 2025 20:59:11 +0100
Subject: [PATCH] CVE-2026-0968: sftp: Sanitize input handling in
sftp_parse_longname()
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
CVE: CVE-2026-0968
Upstream-Status: Backport [https://git.libssh.org/projects/libssh.git/commit/?id=796d85f786dff62bd4bcc4408d9b7bbc855841e9]
Certain functions from sftp.c were moved to a new file sftp_common.c
in version 0.11.0 by following commit:
https://git.libssh.org/projects/libssh.git/commit/src/sftp_common.c?id=c3e03ab4651e4f3382e3a51c0273ade894f0c48a
This is the backport of the changes which fixes the CVE in the original file
sftp.c
Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
---
src/sftp.c | 16 +++++++++++++---
1 file changed, 13 insertions(+), 3 deletions(-)
diff --git a/src/sftp.c b/src/sftp.c
index 4a77141b..2194a9ef 100644
--- a/src/sftp.c
+++ b/src/sftp.c
@@ -1289,13 +1289,18 @@ static char *sftp_parse_longname(const char *longname,
const char *p, *q;
size_t len, field = 0;
+ if (longname == NULL || longname_field < SFTP_LONGNAME_PERM ||
+ longname_field > SFTP_LONGNAME_NAME) {
+ return NULL;
+ }
+
p = longname;
/* Find the beginning of the field which is specified by sftp_longname_field_e. */
- while(field != longname_field) {
+ while (*p != '\0' && field != longname_field) {
if(isspace(*p)) {
field++;
p++;
- while(*p && isspace(*p)) {
+ while (*p != '\0' && isspace(*p)) {
p++;
}
} else {
@@ -1303,8 +1308,13 @@ static char *sftp_parse_longname(const char *longname,
}
}
+ /* If we reached NULL before we got our field fail */
+ if (field != longname_field) {
+ return NULL;
+ }
+
q = p;
- while (! isspace(*q)) {
+ while (*q != '\0' && !isspace(*q)) {
q++;
}
@@ -0,0 +1,136 @@
From 04cd54c7302195055d208e0ca00d6e519d674bb2 Mon Sep 17 00:00:00 2001
From: Jakub Jelen <jjelen@redhat.com>
Date: Mon, 22 Dec 2025 21:00:03 +0100
Subject: [PATCH] CVE-2026-0968 tests: Reproducer for invalid longname data
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 90a5d8f47399e8db61b56793cd21476ff6a528e0)
(cherry picked from commit 212121971fb26e1e00b72bd5402c0454a4d84c03)
CVE: CVE-2026-0968
Upstream-Status: Backport [https://git.libssh.org/projects/libssh.git/commit/?id=212121971fb26e1e00b72bd5402c0454a4d84c03]
Certain functions from sftp.c were moved to a new file sftp_common.c
in version 0.11.0 by following commit:
https://git.libssh.org/projects/libssh.git/commit/src/sftp_common.c?id=c3e03ab4651e4f3382e3a51c0273ade894f0c48a
Updated unit test to include sftp.c during the backport.
Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
---
tests/unittests/CMakeLists.txt | 7 +++
tests/unittests/torture_unit_sftp.c | 86 +++++++++++++++++++++++++++++
2 files changed, 93 insertions(+)
create mode 100644 tests/unittests/torture_unit_sftp.c
diff --git a/tests/unittests/CMakeLists.txt b/tests/unittests/CMakeLists.txt
index f85da72b..41f25830 100644
--- a/tests/unittests/CMakeLists.txt
+++ b/tests/unittests/CMakeLists.txt
@@ -101,6 +101,13 @@ if (UNIX AND NOT WIN32)
endif (WITH_SERVER)
endif (UNIX AND NOT WIN32)
+if (WITH_SFTP)
+ set(LIBSSH_UNIT_TESTS
+ ${LIBSSH_UNIT_TESTS}
+ torture_unit_sftp
+ )
+endif (WITH_SFTP)
+
foreach(_UNIT_TEST ${LIBSSH_UNIT_TESTS})
add_cmocka_test(${_UNIT_TEST}
SOURCES ${_UNIT_TEST}.c
diff --git a/tests/unittests/torture_unit_sftp.c b/tests/unittests/torture_unit_sftp.c
new file mode 100644
index 00000000..8cdaba8e
--- /dev/null
+++ b/tests/unittests/torture_unit_sftp.c
@@ -0,0 +1,86 @@
+#include "config.h"
+
+#include "sftp.c"
+#include "torture.h"
+
+#define LIBSSH_STATIC
+
+static void test_sftp_parse_longname(void **state)
+{
+ const char *lname = NULL;
+ char *value = NULL;
+
+ /* state not used */
+ (void)state;
+
+ /* Valid example from SFTP draft, page 18:
+ * https://datatracker.ietf.org/doc/draft-spaghetti-sshm-filexfer/
+ */
+ lname = "-rwxr-xr-x 1 mjos staff 348911 Mar 25 14:29 t-filexfer";
+ value = sftp_parse_longname(lname, SFTP_LONGNAME_PERM);
+ assert_string_equal(value, "-rwxr-xr-x");
+ free(value);
+ value = sftp_parse_longname(lname, SFTP_LONGNAME_OWNER);
+ assert_string_equal(value, "mjos");
+ free(value);
+ value = sftp_parse_longname(lname, SFTP_LONGNAME_GROUP);
+ assert_string_equal(value, "staff");
+ free(value);
+ value = sftp_parse_longname(lname, SFTP_LONGNAME_SIZE);
+ assert_string_equal(value, "348911");
+ free(value);
+ /* This function is broken further as the date contains space which breaks
+ * the parsing altogether */
+ value = sftp_parse_longname(lname, SFTP_LONGNAME_DATE);
+ assert_string_equal(value, "Mar");
+ free(value);
+ value = sftp_parse_longname(lname, SFTP_LONGNAME_TIME);
+ assert_string_equal(value, "25");
+ free(value);
+ value = sftp_parse_longname(lname, SFTP_LONGNAME_NAME);
+ assert_string_equal(value, "14:29");
+ free(value);
+}
+
+static void test_sftp_parse_longname_invalid(void **state)
+{
+ const char *lname = NULL;
+ char *value = NULL;
+
+ /* state not used */
+ (void)state;
+
+ /* Invalid inputs should not crash
+ */
+ lname = NULL;
+ value = sftp_parse_longname(lname, SFTP_LONGNAME_PERM);
+ assert_null(value);
+ value = sftp_parse_longname(lname, SFTP_LONGNAME_NAME);
+ assert_null(value);
+
+ lname = "";
+ value = sftp_parse_longname(lname, SFTP_LONGNAME_PERM);
+ assert_string_equal(value, "");
+ free(value);
+ value = sftp_parse_longname(lname, SFTP_LONGNAME_NAME);
+ assert_null(value);
+
+ lname = "-rwxr-xr-x 1";
+ value = sftp_parse_longname(lname, SFTP_LONGNAME_PERM);
+ assert_string_equal(value, "-rwxr-xr-x");
+ free(value);
+ value = sftp_parse_longname(lname, SFTP_LONGNAME_NAME);
+ assert_null(value);
+}
+
+int torture_run_tests(void)
+{
+ int rc;
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test(test_sftp_parse_longname),
+ cmocka_unit_test(test_sftp_parse_longname_invalid),
+ };
+
+ rc = cmocka_run_group_tests(tests, NULL, NULL);
+ return rc;
+}
@@ -28,6 +28,8 @@ SRC_URI = "git://git.libssh.org/projects/libssh.git;protocol=https;branch=stable
file://CVE-2026-0966-1.patch \
file://CVE-2026-0966-2.patch \
file://CVE-2026-0966-3.patch \
file://CVE-2026-0968-1.patch \
file://CVE-2026-0968-2.patch \
"
SRCREV = "10e09e273f69e149389b3e0e5d44b8c221c2e7f6"