From: Daniel Golle Date: Fri, 28 Aug 2026 08:19:13 +0000 (+0100) Subject: libssh: fix big-endian -R forwarding and crash without entropy source X-Git-Url: http://git.99rst.org/?a=commitdiff_plain;h=bdcd738a1b9d99f311f6af376a820ce139393523;p=openwrt-packages.git libssh: fix big-endian -R forwarding and crash without entropy source On big-endian hosts the server parsed every tcpip-forward bind port as zero and bound an ephemeral port, so -R remote forwarding never carried a connection. With no usable entropy source the library crashed inside mbedtls instead of failing cleanly. Patches 2-4 were sent upstream to the libssh mailing list: https://archive.libssh.org/libssh/2026-08/0000000.html https://archive.libssh.org/libssh/2026-08/0000001.html Patch 1 backports the seed-failure error path they depend on from upstream master commit ac4b723c. Signed-off-by: Daniel Golle --- diff --git a/libs/libssh/Makefile b/libs/libssh/Makefile index 334d25344..a04c33f84 100644 --- a/libs/libssh/Makefile +++ b/libs/libssh/Makefile @@ -9,7 +9,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=libssh PKG_VERSION:=0.12.2 -PKG_RELEASE:=1 +PKG_RELEASE:=2 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz PKG_SOURCE_URL:=https://www.libssh.org/files/0.12/ diff --git a/libs/libssh/patches/0001-mbedtls-Fail-ssh_crypto_init-when-the-CTR-DRBG-cannot-be-seeded.patch b/libs/libssh/patches/0001-mbedtls-Fail-ssh_crypto_init-when-the-CTR-DRBG-cannot-be-seeded.patch new file mode 100644 index 000000000..30d5003f8 --- /dev/null +++ b/libs/libssh/patches/0001-mbedtls-Fail-ssh_crypto_init-when-the-CTR-DRBG-cannot-be-seeded.patch @@ -0,0 +1,30 @@ +From 01141368cbab5bd54f680b12a772948bad0513f6 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Fri, 28 Aug 2026 09:10:24 +0100 +Subject: [PATCH] mbedtls: Fail ssh_crypto_init() when the CTR-DRBG cannot be + seeded + +A failed mbedtls_ctr_drbg_seed() freed the DRBG context but still +reported success and marked the backend initialised, leaving every +later RNG call to operate on a freed context. Free the entropy context +as well and return SSH_ERROR, so the failure reaches the callers. + +Backport of the mbedtls 3.x part of upstream master commit ac4b723c +("mbedtls: Initial migration to PSA-Crypto API (v4)"). + +Signed-off-by: Daniel Golle +--- + src/libmbedcrypto.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/src/libmbedcrypto.c ++++ b/src/libmbedcrypto.c +@@ -1079,6 +1079,8 @@ int ssh_crypto_init(void) + &ssh_mbedtls_entropy, NULL, 0); + if (rc != 0) { + mbedtls_ctr_drbg_free(&ssh_mbedtls_ctr_drbg); ++ mbedtls_entropy_free(&ssh_mbedtls_entropy); ++ return SSH_ERROR; + } + + #if !(defined(MBEDTLS_CHACHA20_C) && defined(MBEDTLS_POLY1305_C)) diff --git a/libs/libssh/patches/0002-messages-Parse-the-forwarding-bind-port-as-the-uint32-it-is-on-the-wire.patch b/libs/libssh/patches/0002-messages-Parse-the-forwarding-bind-port-as-the-uint32-it-is-on-the-wire.patch new file mode 100644 index 000000000..078e0833e --- /dev/null +++ b/libs/libssh/patches/0002-messages-Parse-the-forwarding-bind-port-as-the-uint32-it-is-on-the-wire.patch @@ -0,0 +1,74 @@ +From d7111e73e0886af1f848912758285d4ac32baf45 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Fri, 28 Aug 2026 08:38:35 +0100 +Subject: [PATCH] messages: Parse the forwarding bind port as the uint32 it is + on the wire +Message-ID: +To: libssh@libssh.org +Cc: John Crispin + +ssh_packet_global_request() unpacked the "tcpip-forward" and +"cancel-tcpip-forward" bind port with the "d" format directly into the +uint16_t bind_port field. "d" stores a full uint32_t through the given +pointer, so the two bytes following the field were overwritten and the +field itself received only the most significant half of the value: +zero, on big-endian platforms, for any valid port. + +A server offering -R forwarding on a big-endian host therefore saw +every requested bind port as a wildcard, bound an ephemeral port +instead of the requested one and reported success, while the client +kept waiting on the port it had asked for, since the chosen port is +only reported back to the client for an actual wildcard request. The +forwarding therefore never carried a connection. + +Unpack into a uint32_t local and assign it to the field, as the +direct-tcpip and forwarded-tcpip channel-open parsers already do. + +Signed-off-by: Daniel Golle +--- +Found on OpenWrt (mips_24kc, big-endian, musl), where a client's -R +forwarding request through a libssh server bound the wrong port. +Verified on a big-endian build: before this patch the server binds an +ephemeral port instead of the requested one and the forwarding never +carries a connection, with it the requested port is bound and -R +forwarding works end to end. No changes in testsuite results. + + src/messages.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +--- a/src/messages.c ++++ b/src/messages.c +@@ -1799,6 +1799,7 @@ SSH_PACKET_CALLBACK(ssh_packet_global_re + ssh_message msg = NULL; + char *request = NULL; + uint8_t want_reply; ++ uint32_t bind_port = 0; + int rc = SSH_PACKET_USED; + int r; + +@@ -1829,10 +1830,11 @@ SSH_PACKET_CALLBACK(ssh_packet_global_re + r = ssh_buffer_unpack(packet, + "sd", + &msg->global_request.bind_address, +- &msg->global_request.bind_port); ++ &bind_port); + if (r != SSH_OK){ + goto reply_with_failure; + } ++ msg->global_request.bind_port = (uint16_t)bind_port; + msg->global_request.type = SSH_GLOBAL_REQUEST_TCPIP_FORWARD; + msg->global_request.want_reply = want_reply; + +@@ -1870,10 +1872,11 @@ SSH_PACKET_CALLBACK(ssh_packet_global_re + r = ssh_buffer_unpack(packet, + "sd", + &msg->global_request.bind_address, +- &msg->global_request.bind_port); ++ &bind_port); + if (r != SSH_OK){ + goto reply_with_failure; + } ++ msg->global_request.bind_port = (uint16_t)bind_port; + msg->global_request.type = SSH_GLOBAL_REQUEST_CANCEL_TCPIP_FORWARD; + msg->global_request.want_reply = want_reply; + diff --git a/libs/libssh/patches/0003-mbedtls-Guard-the-CTR-DRBG-against-use-before-it-is-seeded.patch b/libs/libssh/patches/0003-mbedtls-Guard-the-CTR-DRBG-against-use-before-it-is-seeded.patch new file mode 100644 index 000000000..d36ed3ad3 --- /dev/null +++ b/libs/libssh/patches/0003-mbedtls-Guard-the-CTR-DRBG-against-use-before-it-is-seeded.patch @@ -0,0 +1,65 @@ +From ff41950e17c4af14369be82f64197f138977b4ac Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Fri, 28 Aug 2026 08:40:38 +0100 +Subject: [PATCH 1/2] mbedtls: Guard the CTR-DRBG against use before it is seeded +Message-ID: +To: libssh@libssh.org +Cc: John Crispin + +When ssh_crypto_init() cannot seed the CTR-DRBG, typically because no +entropy source is available, it frees the DRBG context and reports +failure. The automatic constructor initialisation has no way to hand +that failure to the application, so the library remains loaded with a +zeroed DRBG context, and the first ssh_get_random() call runs +mbedtls_ctr_drbg_random() on that zeroed context and crashes inside +mbedtls (SIGSEGV or SIGBUS, depending on the platform). The same holds +for any RNG use after ssh_finalize(). + +Make ssh_mbedtls_initialized() available with mbedtls 3.x as well and +check it in ssh_mbedtls_random() before touching the DRBG, returning +failure exactly as the PSA (mbedtls 4.x) implementation already does. +The callers of ssh_get_random() all handle a failure return. + +Signed-off-by: Daniel Golle +--- + include/libssh/libmbedcrypto.h | 1 + + src/getrandom_mbedcrypto.c | 3 +++ + src/libmbedcrypto.c | 5 +++++ + 3 files changed, 9 insertions(+) + +--- a/include/libssh/libmbedcrypto.h ++++ b/include/libssh/libmbedcrypto.h +@@ -135,6 +135,7 @@ int ssh_mbedcry_hex2bn(bignum *dest, cha + + mbedtls_ctr_drbg_context *ssh_get_mbedtls_ctr_drbg_context(void); + ++int ssh_mbedtls_initialized(void); + int ssh_mbedtls_random(void *where, int len, int strong); + + ssh_string make_ecpoint_string(const mbedtls_ecp_group *g, const +--- a/src/getrandom_mbedcrypto.c ++++ b/src/getrandom_mbedcrypto.c +@@ -32,6 +32,9 @@ int + ssh_mbedtls_random(void *where, int len, int strong) + { + int rc = 0; ++ if (!ssh_mbedtls_initialized()) { ++ return 0; ++ } + if (strong) { + mbedtls_ctr_drbg_set_prediction_resistance(&ssh_mbedtls_ctr_drbg, + MBEDTLS_CTR_DRBG_PR_ON); +--- a/src/libmbedcrypto.c ++++ b/src/libmbedcrypto.c +@@ -60,6 +60,11 @@ int ssh_kdf(struct ssh_crypto_struct *cr + key_type, output, requested_len); + } + ++int ssh_mbedtls_initialized(void) ++{ ++ return libmbedcrypto_initialized; ++} ++ + HMACCTX hmac_init(const void *key, size_t len, enum ssh_hmac_e type) + { + HMACCTX ctx = NULL; diff --git a/libs/libssh/patches/0004-init-Do-not-report-a-failed-initialisation-as-initialised.patch b/libs/libssh/patches/0004-init-Do-not-report-a-failed-initialisation-as-initialised.patch new file mode 100644 index 000000000..a9bdd7d07 --- /dev/null +++ b/libs/libssh/patches/0004-init-Do-not-report-a-failed-initialisation-as-initialised.patch @@ -0,0 +1,46 @@ +From cf7f79a2f4a4dba8f9b9fa074a7171479ffa6c84 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Fri, 28 Aug 2026 08:40:52 +0100 +Subject: [PATCH 2/2] init: Do not report a failed initialisation as initialised +Message-ID: +To: libssh@libssh.org +Cc: John Crispin + +is_ssh_initialized() answered only whether _ssh_init() had run, not +whether it had succeeded: the counter is incremented before anything is +attempted and stays raised when initialisation fails (_ssh_finalize() +relies on that to skip tearing down what was never set up). After a +failed constructor initialisation, for example with no usable entropy +source, the guard in ssh_connect() therefore passed and the session ran +into the unusable crypto state instead of failing with the intended +"Library not initialized" error. + +Report the library as initialised only when the recorded initialisation +result is a success. + +Signed-off-by: Daniel Golle +--- + src/init.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +--- a/src/init.c ++++ b/src/init.c +@@ -277,7 +277,8 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, + * @internal + * @brief Return whether the library is initialized + * +- * @returns true if the library is initialized; false otherwise. ++ * @returns true if the library is initialized and initialization ++ * succeeded; false otherwise. + * + * @see ssh_init() + */ +@@ -286,7 +287,7 @@ bool is_ssh_initialized(void) { + bool is_initialized = false; + + ssh_mutex_lock(&ssh_init_mutex); +- is_initialized = _ssh_initialized > 0; ++ is_initialized = _ssh_initialized > 0 && _ssh_init_ret == 0; + ssh_mutex_unlock(&ssh_init_mutex); + + return is_initialized;