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/
--- /dev/null
+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))
--- /dev/null
+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;
+
--- /dev/null
+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;
--- /dev/null
+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;