Resolves: RHEL-150661 Resolves: CVE-2025-4877 Resolves: CVE-2025-4878 Resolves: CVE-2025-5351 Resolves: CVE-2025-8114 Resolves: CVE-2025-8277 Resolves: CVE-2026-0964 Resolves: CVE-2026-0965 Resolves: CVE-2026-0966 Resolves: CVE-2026-0967 Resolves: CVE-2026-0968
185 lines
5.4 KiB
Diff
185 lines
5.4 KiB
Diff
From 7d08a51ec529edc5ccf7978d403ec4ef151e82a7 Mon Sep 17 00:00:00 2001
|
|
From: Jakub Jelen <jjelen@redhat.com>
|
|
Date: Mon, 22 Dec 2025 20:59:11 +0100
|
|
Subject: [PATCH 1/2] 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>
|
|
(cherry picked from commit 20856f44c146468c830da61dcbbbaa8ce71e390b)
|
|
---
|
|
src/sftp.c | 16 +++++++++++++---
|
|
1 file changed, 13 insertions(+), 3 deletions(-)
|
|
|
|
diff --git a/src/sftp.c b/src/sftp.c
|
|
index 60e591f0..70f9ed15 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++;
|
|
}
|
|
|
|
--
|
|
2.53.0
|
|
|
|
|
|
From ccedc7907ebe2c1a977b739b85034953de582fb3 Mon Sep 17 00:00:00 2001
|
|
From: Jakub Jelen <jjelen@redhat.com>
|
|
Date: Mon, 22 Dec 2025 21:00:03 +0100
|
|
Subject: [PATCH 2/2] 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)
|
|
---
|
|
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 28458d49..658f14bc 100644
|
|
--- a/tests/unittests/CMakeLists.txt
|
|
+++ b/tests/unittests/CMakeLists.txt
|
|
@@ -95,6 +95,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;
|
|
+}
|
|
--
|
|
2.53.0
|
|
|