From 0d5b592897bc7f585f966c6a3d29d0dcf540ddc0 Mon Sep 17 00:00:00 2001 From: tomcruiseqi <10762123+tomcruiseqi@user.noreply.gitee.com> Date: Thu, 3 Sep 2026 17:51:54 +0800 Subject: [PATCH] [CVE][Upstream] Add patch to fix CVE-2026-59843 To #bug40538 commit 44b186fa17aff497dae420c59c003222e438103c upstream commit 7d7c3a04a25b0c86bb402627d3b6918232243445 upstream Project: TC2024080204 Signed-off-by: tomcruiseqi --- 0047-bugfix-for-CVE-2026-59843.patch | 82 +++++++++++++ 0048-bugfix-for-CVE-2026-59843.patch | 171 +++++++++++++++++++++++++++ libssh.spec | 10 +- 3 files changed, 262 insertions(+), 1 deletion(-) create mode 100644 0047-bugfix-for-CVE-2026-59843.patch create mode 100644 0048-bugfix-for-CVE-2026-59843.patch diff --git a/0047-bugfix-for-CVE-2026-59843.patch b/0047-bugfix-for-CVE-2026-59843.patch new file mode 100644 index 0000000..b779959 --- /dev/null +++ b/0047-bugfix-for-CVE-2026-59843.patch @@ -0,0 +1,82 @@ +From 44b186fa17aff497dae420c59c003222e438103c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavol=20=C5=BD=C3=A1=C4=8Dik?= +Date: Fri, 6 Mar 2026 13:58:30 +0100 +Subject: [PATCH] channels: Fail when receiving max packet size 0 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Do this both for SSH2_MSG_CHANNEL_OPEN and for +SSH2_MSG_CHANNEL_OPEN_CONFIRMATION. Using the +max packet size 0 would lead to an infinite loop +in channel_write_common. + +Originally reported by Rinku Das on on 23th February. +Independently reported by Yi Lin on 26th February and +Haruto Kimura on 22nd March. + +We do not consider this as a security issue as connecting +to untrusted servers on the internet brings much worse +security consequences than hanging your clinet. + +Signed-off-by: Pavol Žáčik +Reviewed-by: Jakub Jelen + +Conflict:Adapt context in src/channels.c for 0.10.5 +Reference:https://gitlab.com/libssh/libssh-mirror/-/commit/44b186fa17aff497dae420c59c003222e438103c +--- + src/channels.c | 7 +++++++ + src/messages.c | 19 +++++++++++++++---- + 2 files changed, 22 insertions(+), 4 deletions(-) + +diff --git a/src/channels.c b/src/channels.c +index 459246b..7b66427 100644 +--- a/src/channels.c ++++ b/src/channels.c +@@ -192,6 +192,13 @@ SSH_PACKET_CALLBACK(ssh_packet_channel_open_conf){ + if (rc != SSH_OK) + goto error; + ++ if (channel->remote_maxpacket == 0) { ++ SSH_LOG(SSH_LOG_RARE, ++ "Invalid maximum packet size 0 in " ++ "SSH2_MSG_CHANNEL_OPEN_CONFIRMATION"); ++ goto error; ++ } ++ + SSH_LOG(SSH_LOG_PROTOCOL, + "Received a CHANNEL_OPEN_CONFIRMATION for channel %d:%d", + channel->local_channel, +diff --git a/src/messages.c b/src/messages.c +index 54497fa..5228b3d 100644 +--- a/src/messages.c ++++ b/src/messages.c +@@ -1160,10 +1160,21 @@ SSH_PACKET_CALLBACK(ssh_packet_channel_open){ + SSH_LOG(SSH_LOG_PACKET, + "Clients wants to open a %s channel", type_c); + +- ssh_buffer_unpack(packet,"ddd", +- &msg->channel_request_open.sender, +- &msg->channel_request_open.window, +- &msg->channel_request_open.packet_size); ++ rc = ssh_buffer_unpack(packet, ++ "ddd", ++ &msg->channel_request_open.sender, ++ &msg->channel_request_open.window, ++ &msg->channel_request_open.packet_size); ++ if (rc != SSH_OK){ ++ goto error; ++ } ++ ++ if (msg->channel_request_open.packet_size == 0) { ++ ssh_set_error(session, ++ SSH_FATAL, ++ "Invalid maximum packet size 0 in SSH2_MSG_CHANNEL_OPEN"); ++ goto error; ++ } + + if (session->session_state != SSH_SESSION_STATE_AUTHENTICATED){ + ssh_set_error(session,SSH_FATAL, "Invalid state when receiving channel open request (must be authenticated)"); +-- +2.33.0 + diff --git a/0048-bugfix-for-CVE-2026-59843.patch b/0048-bugfix-for-CVE-2026-59843.patch new file mode 100644 index 0000000..b4158bd --- /dev/null +++ b/0048-bugfix-for-CVE-2026-59843.patch @@ -0,0 +1,171 @@ +From 7d7c3a04a25b0c86bb402627d3b6918232243445 Mon Sep 17 00:00:00 2001 +From: Martin Pitt +Date: Sun, 26 Jul 2026 14:01:27 +0000 +Subject: [PATCH] tests: Verify zero max packet size in channel + open is rejected + +Cover both directions with unit tests: a client receiving +SSH2_MSG_CHANNEL_OPEN_CONFIRMATION with a maximum packet size of 0 must +not transition the channel to the open state, and a server receiving +SSH2_MSG_CHANNEL_OPEN with a maximum packet size of 0 must reject the +request. Both come with a positive control using a valid packet size. + +Signed-off-by: Martin Pitt +Reviewed-by: Jakub Jelen + +Conflict:Adapt context in tests/unittests/torture_channel.c for 0.10.5 +Reference:https://gitlab.com/libssh/libssh-mirror/-/commit/7d7c3a04a25b0c86bb402627d3b6918232243445 +--- + tests/unittests/torture_channel.c | 125 ++++++++++++++++++++++++++++++ + 1 file changed, 125 insertions(+) + +diff --git a/tests/unittests/torture_channel.c b/tests/unittests/torture_channel.c +index c165c57..d854e28 100644 +--- a/tests/unittests/torture_channel.c ++++ b/tests/unittests/torture_channel.c +@@ -12,6 +12,8 @@ + #include "torture.h" + #include "channels.c" + ++#include ++ + static int torture_data_cb_calls; + + static int torture_channel_data_cb(ssh_session session, +@@ -171,10 +173,133 @@ static void torture_channel_select(void **state) + close(fd); + } + ++/* Feed a fabricated SSH2_MSG_CHANNEL_OPEN_CONFIRMATION with the given ++ * maximum packet size to a channel in OPENING state and return its ++ * resulting state. */ ++static enum ssh_channel_state_e ++channel_open_conf_maxpacket(uint32_t maxpacket) ++{ ++ ssh_session session = NULL; ++ ssh_channel channel = NULL; ++ ssh_buffer packet = NULL; ++ enum ssh_channel_state_e result; ++ int rc; ++ ++ session = ssh_new(); ++ assert_non_null(session); ++ session->flags |= SSH_SESSION_FLAG_AUTHENTICATED; ++ ++ channel = ssh_channel_new(session); ++ assert_non_null(channel); ++ channel->local_channel = ssh_channel_new_id(session); ++ channel->state = SSH_CHANNEL_STATE_OPENING; ++ ++ packet = ssh_buffer_new(); ++ assert_non_null(packet); ++ rc = ssh_buffer_pack(packet, ++ "dddd", ++ channel->local_channel, ++ (uint32_t)42, /* sender channel */ ++ (uint32_t)64000, /* initial window size */ ++ maxpacket); ++ assert_int_equal(rc, SSH_OK); ++ ++ rc = ssh_packet_channel_open_conf(session, ++ SSH2_MSG_CHANNEL_OPEN_CONFIRMATION, ++ packet, ++ NULL); ++ assert_int_equal(rc, SSH_PACKET_USED); ++ ++ result = channel->state; ++ ++ SSH_BUFFER_FREE(packet); ++ ssh_free(session); ++ ++ return result; ++} ++ ++static void torture_channel_open_conf(void **state) ++{ ++ (void)state; /* unused */ ++ ++ assert_int_equal(channel_open_conf_maxpacket(32768), ++ SSH_CHANNEL_STATE_OPEN); ++} ++ ++/* CVE-2026-59843: a maximum packet size of 0 in CHANNEL_OPEN_CONFIRMATION ++ * must not open the channel, as it would cause an infinite loop in ++ * channel_write_common(). */ ++static void torture_channel_open_conf_zero_maxpacket(void **state) ++{ ++ (void)state; /* unused */ ++ ++ assert_int_not_equal(channel_open_conf_maxpacket(0), ++ SSH_CHANNEL_STATE_OPEN); ++} ++ ++/* Feed a fabricated SSH2_MSG_CHANNEL_OPEN with the given maximum packet ++ * size to an unauthenticated session and return the resulting session ++ * error string via a static buffer. */ ++static const char * ++channel_open_maxpacket_error(uint32_t maxpacket) ++{ ++ static char error[256]; ++ ssh_session session = NULL; ++ ssh_buffer packet = NULL; ++ int rc; ++ ++ session = ssh_new(); ++ assert_non_null(session); ++ ++ packet = ssh_buffer_new(); ++ assert_non_null(packet); ++ rc = ssh_buffer_pack(packet, ++ "sddd", ++ "session", ++ (uint32_t)42, /* sender channel */ ++ (uint32_t)64000, /* initial window size */ ++ maxpacket); ++ assert_int_equal(rc, SSH_OK); ++ ++ rc = ssh_packet_channel_open(session, ++ SSH2_MSG_CHANNEL_OPEN, ++ packet, ++ NULL); ++ assert_int_equal(rc, SSH_PACKET_USED); ++ ++ snprintf(error, sizeof(error), "%s", ssh_get_error(session)); ++ ++ SSH_BUFFER_FREE(packet); ++ ssh_free(session); ++ ++ return error; ++} ++ ++/* CVE-2026-59843: a maximum packet size of 0 in CHANNEL_OPEN must be ++ * rejected before any further processing. The control case with a valid ++ * size proceeds to the session state check, proving the zero case failed ++ * on the packet size specifically. */ ++static void torture_channel_open_zero_maxpacket(void **state) ++{ ++ (void)state; /* unused */ ++ ++ assert_string_equal( ++ channel_open_maxpacket_error(0), ++ "Invalid maximum packet size 0 in SSH2_MSG_CHANNEL_OPEN"); ++ ++ assert_string_equal( ++ channel_open_maxpacket_error(32768), ++ "Invalid state when receiving channel open request " ++ "(must be authenticated)"); ++} ++ + int torture_run_tests(void) { + int rc; + struct CMUnitTest tests[] = { + cmocka_unit_test(torture_channel_select), ++ cmocka_unit_test(torture_channel_open_conf), ++ cmocka_unit_test(torture_channel_open_conf_zero_maxpacket), ++ cmocka_unit_test(torture_channel_open_zero_maxpacket), + cmocka_unit_test( + torture_channel_rcv_data_after_remote_close), + }; +-- +2.33.0 + diff --git a/libssh.spec b/libssh.spec index 5739b76..825967c 100644 --- a/libssh.spec +++ b/libssh.spec @@ -1,4 +1,4 @@ -%define anolis_release 19 +%define anolis_release 20 ExcludeArch: riscv64 %global _smp_build_ncpus 1 @@ -92,6 +92,11 @@ Patch0045: 0045-bugfix-for-CVE-2026-59848.patch # https://git.libssh.org/projects/libssh.git/patch/?id=2544f22733ffcd59a2e51e2950f80901d063b946 Patch0046: 0046-bugfix-for-CVE-2026-59844.patch +# https://gitlab.com/libssh/libssh-mirror/-/commit/44b186fa17aff497dae420c59c003222e438103c +# https://gitlab.com/libssh/libssh-mirror/-/commit/7d7c3a04a25b0c86bb402627d3b6918232243445 +Patch0047: 0047-bugfix-for-CVE-2026-59843.patch +Patch0048: 0048-bugfix-for-CVE-2026-59843.patch + BuildRequires: cmake gcc-c++ BuildRequires: openssl-devel zlib-devel krb5-devel libcmocka-devel BuildRequires: pam_wrapper socket_wrapper nss_wrapper uid_wrapper @@ -201,6 +206,9 @@ popd %doc AUTHORS CHANGELOG README %changelog +* Thu Sep 03 2026 tomcruiseqi - 0.10.5-20 +- Fix CVE-2026-59843 + * Fri Aug 14 2026 tomcruiseqi - 0.10.5-19 - Fix CVE-2026-59844 -- Gitee