]> git.99rst.org Git - openwrt-packages.git/commitdiff
libssh: fix big-endian -R forwarding and crash without entropy source
authorDaniel Golle <redacted>
Fri, 28 Aug 2026 08:19:13 +0000 (09:19 +0100)
committerAlexandru Ardelean <redacted>
Fri, 28 Aug 2026 09:14:51 +0000 (12:14 +0300)
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 <redacted>
libs/libssh/Makefile
libs/libssh/patches/0001-mbedtls-Fail-ssh_crypto_init-when-the-CTR-DRBG-cannot-be-seeded.patch [new file with mode: 0644]
libs/libssh/patches/0002-messages-Parse-the-forwarding-bind-port-as-the-uint32-it-is-on-the-wire.patch [new file with mode: 0644]
libs/libssh/patches/0003-mbedtls-Guard-the-CTR-DRBG-against-use-before-it-is-seeded.patch [new file with mode: 0644]
libs/libssh/patches/0004-init-Do-not-report-a-failed-initialisation-as-initialised.patch [new file with mode: 0644]

index 334d2534483f4f6fccd3ea5b79a75840e2db848a..a04c33f84b479fe62c9f01e91bf2fb3651c730ac 100644 (file)
@@ -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 (file)
index 0000000..30d5003
--- /dev/null
@@ -0,0 +1,30 @@
+From 01141368cbab5bd54f680b12a772948bad0513f6 Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+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 <daniel@makrotopia.org>
+---
+ 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 (file)
index 0000000..078e083
--- /dev/null
@@ -0,0 +1,74 @@
+From d7111e73e0886af1f848912758285d4ac32baf45 Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+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: <apE6-yLX4akEHi6S@makrotopia.org>
+To: libssh@libssh.org
+Cc: John Crispin <john@phrozen.org>
+
+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 <daniel@makrotopia.org>
+---
+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 (file)
index 0000000..d36ed3a
--- /dev/null
@@ -0,0 +1,65 @@
+From ff41950e17c4af14369be82f64197f138977b4ac Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+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: <apE7dljmkHRzSCXq@makrotopia.org>
+To: libssh@libssh.org
+Cc: John Crispin <john@phrozen.org>
+
+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 <daniel@makrotopia.org>
+---
+ 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 (file)
index 0000000..a9bdd7d
--- /dev/null
@@ -0,0 +1,46 @@
+From cf7f79a2f4a4dba8f9b9fa074a7171479ffa6c84 Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Fri, 28 Aug 2026 08:40:52 +0100
+Subject: [PATCH 2/2] init: Do not report a failed initialisation as initialised
+Message-ID: <apE7hG3Qwp8HsTIS@makrotopia.org>
+To: libssh@libssh.org
+Cc: John Crispin <john@phrozen.org>
+
+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 <daniel@makrotopia.org>
+---
+ 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;
git clone https://git.99rst.org/PROJECT