From 192055e960aac4c8c11834f7c66e1a725f06c780 Mon Sep 17 00:00:00 2001 From: zhaoyonghao Date: Tue, 2 Dec 2025 16:40:01 +0800 Subject: [PATCH] backport some patches from upstream (cherry picked from commit 692ada769033787432991161f023a6bb4f3c76a4) --- ...dd-input-bounds-checking-to-SFTP-API.patch | 358 ++++++++++++++++++ ...eak-in-base64_encode-with-empty-data.patch | 34 ++ ...rmed-comments-in-known_hosts-parsing.patch | 34 ++ ...ng-and-harden-_libssh2_base64_encode.patch | 93 +++++ ...-DH-GEX-sha256-bignum-initialization.patch | 42 ++ ...garbage-value-reported-by-clang-tidy.patch | 48 +++ ...agent_open-fix-failure-packet-length.patch | 33 ++ ...dereference-in-path-arg-of-send-recv.patch | 95 +++++ libssh2.spec | 16 +- 9 files changed, 752 insertions(+), 1 deletion(-) create mode 100644 backport-Add-input-bounds-checking-to-SFTP-API.patch create mode 100644 backport-Fix-small-leak-in-base64_encode-with-empty-data.patch create mode 100644 backport-Handle-malformed-comments-in-known_hosts-parsing.patch create mode 100644 backport-Improve-known_hosts-parsing-and-harden-_libssh2_base64_encode.patch create mode 100644 backport-kex-fix-DH-GEX-sha256-bignum-initialization.patch create mode 100644 backport-mbedtls-fix-using-garbage-value-reported-by-clang-tidy.patch create mode 100644 backport-packet-authagent_open-fix-failure-packet-length.patch create mode 100644 backport-scp-fix-NULL-dereference-in-path-arg-of-send-recv.patch diff --git a/backport-Add-input-bounds-checking-to-SFTP-API.patch b/backport-Add-input-bounds-checking-to-SFTP-API.patch new file mode 100644 index 0000000..46d877d --- /dev/null +++ b/backport-Add-input-bounds-checking-to-SFTP-API.patch @@ -0,0 +1,358 @@ +From ff50682c238875ebef8601c0d6bc2105600422e8 Mon Sep 17 00:00:00 2001 +From: Will Cosgrove +Date: Fri, 26 Sep 2025 08:03:28 -0700 +Subject: [PATCH] Add input bounds checking to SFTP API (#1679) + +Add bounds checking to public SFTP API input to avoid possible heap corruption when passing in invalid values. + +Credit: +Oblivionsage + +Conflict:no sftp_posix_rename in sftp.c +Reference:https://github.com/libssh2/libssh2/commit/ff50682c238875ebef8601c0d6bc2105600422e8 +--- + src/sftp.c | 169 +++++++++++++++++++++++++++++++++++++++++------------ + 1 file changed, 131 insertions(+), 38 deletions(-) + +diff --git a/src/sftp.c b/src/sftp.c +index 46164ea..035a6ee 100644 +--- a/src/sftp.c ++++ b/src/sftp.c +@@ -1149,8 +1149,23 @@ sftp_open(LIBSSH2_SFTP *sftp, const char *filename, + }; + unsigned char *s; + ssize_t rc; ++ uint32_t packet_len; + int open_file = (open_type == LIBSSH2_SFTP_OPENFILE) ? 1 : 0; + ++ /* packet_len(4) + packet_type(1) + request_id(4) + filename_len(4) + ++ flags(4) */ ++ packet_len = (13 + ++ (open_file ? (4 + sftp_attrsize(attrs.flags)) : 0)); ++ ++ if(packet_len + filename_len < packet_len) { ++ _libssh2_error(session, LIBSSH2_ERROR_OUT_OF_BOUNDARY, ++ "Input too large " ++ "sftp_open"); ++ return NULL; ++ } ++ ++ packet_len += (uint32_t)filename_len; ++ + if(sftp->open_state == libssh2_NB_state_idle) { + sftp->last_errno = LIBSSH2_FX_OK; + +@@ -1158,10 +1173,7 @@ sftp_open(LIBSSH2_SFTP *sftp, const char *filename, + memcpy(&attrs, attrs_in, sizeof(LIBSSH2_SFTP_ATTRIBUTES)); + } + +- /* packet_len(4) + packet_type(1) + request_id(4) + filename_len(4) + +- flags(4) */ +- sftp->open_packet_len = (uint32_t)(filename_len + 13 + +- (open_file? (4 + sftp_attrsize(attrs.flags)) : 0)); ++ sftp->open_packet_len = packet_len; + + /* surprise! this starts out with nothing sent */ + sftp->open_packet_sent = 0; +@@ -2776,11 +2788,20 @@ static int sftp_unlink(LIBSSH2_SFTP *sftp, const char *filename, + LIBSSH2_SESSION *session = channel->session; + size_t data_len = 0; + uint32_t retcode; +- /* 13 = packet_len(4) + packet_type(1) + request_id(4) + filename_len(4) */ +- uint32_t packet_len = (uint32_t)(filename_len + 13); ++ uint32_t packet_len; + unsigned char *s, *data = NULL; + int rc; + ++ /* 13 = packet_len(4) + packet_type(1) + request_id(4) + filename_len(4) */ ++ packet_len = 13; ++ ++ if(packet_len + filename_len < packet_len) { ++ return _libssh2_error(session, LIBSSH2_ERROR_OUT_OF_BOUNDARY, ++ "Input too large " ++ "sftp_unlink"); ++ } ++ packet_len += (uint32_t)filename_len; ++ + if(sftp->unlink_state == libssh2_NB_state_idle) { + sftp->last_errno = LIBSSH2_FX_OK; + +@@ -2882,14 +2903,28 @@ static int sftp_rename(LIBSSH2_SFTP *sftp, const char *source_filename, + LIBSSH2_SESSION *session = channel->session; + size_t data_len = 0; + int retcode; +- uint32_t packet_len = +- source_filename_len + dest_filename_len + 17 + +- (sftp->version >= 5 ? 4 : 0); +- /* packet_len(4) + packet_type(1) + request_id(4) + +- source_filename_len(4) + dest_filename_len(4) + flags(4){SFTP5+) */ ++ uint32_t packet_len; + unsigned char *data = NULL; + ssize_t rc; + ++ /* packet_len(4) + packet_type(1) + request_id(4) + ++ source_filename_len(4) + dest_filename_len(4) + flags(4){SFTP5+) */ ++ packet_len = 17 + (sftp->version >= 5 ? 4 : 0); ++ ++ if(packet_len + source_filename_len < packet_len) { ++ return _libssh2_error(session, LIBSSH2_ERROR_OUT_OF_BOUNDARY, ++ "Input too large " ++ "sftp_rename"); ++ } ++ packet_len += (uint32_t)source_filename_len; ++ ++ if(packet_len + dest_filename_len < packet_len) { ++ return _libssh2_error(session, LIBSSH2_ERROR_OUT_OF_BOUNDARY, ++ "Input too large (2) " ++ "sftp_rename"); ++ } ++ packet_len += dest_filename_len; ++ + if(sftp->rename_state == libssh2_NB_state_idle) { + sftp->last_errno = LIBSSH2_FX_OK; + +@@ -3021,16 +3056,25 @@ static int sftp_fstatvfs(LIBSSH2_SFTP_HANDLE *handle, LIBSSH2_SFTP_STATVFS *st) + LIBSSH2_CHANNEL *channel = sftp->channel; + LIBSSH2_SESSION *session = channel->session; + size_t data_len = 0; +- /* 17 = packet_len(4) + packet_type(1) + request_id(4) + ext_len(4) +- + handle_len (4) */ +- /* 20 = strlen ("fstatvfs@openssh.com") */ +- uint32_t packet_len = (uint32_t)(handle->handle_len + 20 + 17); ++ uint32_t packet_len; + unsigned char *packet, *s, *data = NULL; + ssize_t rc; + unsigned int flag; + static const unsigned char responses[2] = + { SSH_FXP_EXTENDED_REPLY, SSH_FXP_STATUS }; + ++ /* 17 = packet_len(4) + packet_type(1) + request_id(4) + ext_len(4) ++ + handle_len (4) */ ++ /* 20 = strlen ("fstatvfs@openssh.com") */ ++ packet_len = 20 + 17; ++ ++ if(packet_len + handle->handle_len < packet_len) { ++ return _libssh2_error(session, LIBSSH2_ERROR_OUT_OF_BOUNDARY, ++ "Input too large " ++ "sftp_fstatvfs"); ++ } ++ packet_len += (uint32_t)handle->handle_len; ++ + if(sftp->fstatvfs_state == libssh2_NB_state_idle) { + sftp->last_errno = LIBSSH2_FX_OK; + +@@ -3157,16 +3201,25 @@ static int sftp_statvfs(LIBSSH2_SFTP *sftp, const char *path, + LIBSSH2_CHANNEL *channel = sftp->channel; + LIBSSH2_SESSION *session = channel->session; + size_t data_len = 0; +- /* 17 = packet_len(4) + packet_type(1) + request_id(4) + ext_len(4) +- + path_len (4) */ +- /* 19 = strlen ("statvfs@openssh.com") */ +- uint32_t packet_len = path_len + 19 + 17; ++ uint32_t packet_len; + unsigned char *packet, *s, *data = NULL; + ssize_t rc; + unsigned int flag; + static const unsigned char responses[2] = + { SSH_FXP_EXTENDED_REPLY, SSH_FXP_STATUS }; + ++ /* 17 = packet_len(4) + packet_type(1) + request_id(4) + ext_len(4) ++ + path_len (4) */ ++ /* 19 = strlen ("statvfs@openssh.com") */ ++ packet_len = 19 + 17; ++ ++ if(packet_len + path_len < packet_len) { ++ return _libssh2_error(session, LIBSSH2_ERROR_OUT_OF_BOUNDARY, ++ "Input too large " ++ "sftp_statvfs"); ++ } ++ packet_len += path_len; ++ + if(sftp->statvfs_state == libssh2_NB_state_idle) { + sftp->last_errno = LIBSSH2_FX_OK; + +@@ -3298,7 +3351,7 @@ static int sftp_mkdir(LIBSSH2_SFTP *sftp, const char *path, + }; + size_t data_len = 0; + uint32_t retcode; +- ssize_t packet_len; ++ uint32_t packet_len; + unsigned char *packet, *s, *data = NULL; + int rc; + +@@ -3309,7 +3362,14 @@ static int sftp_mkdir(LIBSSH2_SFTP *sftp, const char *path, + } + + /* 13 = packet_len(4) + packet_type(1) + request_id(4) + path_len(4) */ +- packet_len = path_len + 13 + sftp_attrsize(attrs.flags); ++ packet_len = 13 + sftp_attrsize(attrs.flags); ++ ++ if(packet_len + path_len < packet_len) { ++ return _libssh2_error(session, LIBSSH2_ERROR_OUT_OF_BOUNDARY, ++ "Input too large " ++ "sftp_mkdir"); ++ } ++ packet_len += path_len; + + if(sftp->mkdir_state == libssh2_NB_state_idle) { + sftp->last_errno = LIBSSH2_FX_OK; +@@ -3323,7 +3383,7 @@ static int sftp_mkdir(LIBSSH2_SFTP *sftp, const char *path, + "packet"); + } + +- _libssh2_store_u32(&s, (uint32_t)(packet_len - 4)); ++ _libssh2_store_u32(&s, packet_len - 4); + *(s++) = SSH_FXP_MKDIR; + sftp->mkdir_request_id = sftp->request_id++; + _libssh2_store_u32(&s, sftp->mkdir_request_id); +@@ -3344,7 +3404,7 @@ static int sftp_mkdir(LIBSSH2_SFTP *sftp, const char *path, + sftp->mkdir_packet = packet; + return (int)nwritten; + } +- if(packet_len != nwritten) { ++ if((ssize_t)packet_len != nwritten) { + LIBSSH2_FREE(session, packet); + sftp->mkdir_state = libssh2_NB_state_idle; + return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, +@@ -3415,10 +3475,17 @@ static int sftp_rmdir(LIBSSH2_SFTP *sftp, const char *path, + size_t data_len = 0; + uint32_t retcode; + /* 13 = packet_len(4) + packet_type(1) + request_id(4) + path_len(4) */ +- ssize_t packet_len = path_len + 13; ++ uint32_t packet_len = 13; + unsigned char *s, *data = NULL; + int rc; + ++ if(packet_len + path_len < packet_len) { ++ return _libssh2_error(session, LIBSSH2_ERROR_OUT_OF_BOUNDARY, ++ "Input too large " ++ "sftp_rmdir"); ++ } ++ packet_len += path_len; ++ + if(sftp->rmdir_state == libssh2_NB_state_idle) { + sftp->last_errno = LIBSSH2_FX_OK; + +@@ -3431,7 +3498,7 @@ static int sftp_rmdir(LIBSSH2_SFTP *sftp, const char *path, + "packet"); + } + +- _libssh2_store_u32(&s, (uint32_t)(packet_len - 4)); ++ _libssh2_store_u32(&s, packet_len - 4); + *(s++) = SSH_FXP_RMDIR; + sftp->rmdir_request_id = sftp->request_id++; + _libssh2_store_u32(&s, sftp->rmdir_request_id); +@@ -3447,7 +3514,7 @@ static int sftp_rmdir(LIBSSH2_SFTP *sftp, const char *path, + if(nwritten == LIBSSH2_ERROR_EAGAIN) { + return (int)nwritten; + } +- else if(packet_len != nwritten) { ++ else if((ssize_t)packet_len != nwritten) { + LIBSSH2_FREE(session, sftp->rmdir_packet); + sftp->rmdir_packet = NULL; + sftp->rmdir_state = libssh2_NB_state_idle; +@@ -3519,15 +3586,21 @@ static int sftp_stat(LIBSSH2_SFTP *sftp, const char *path, + LIBSSH2_SESSION *session = channel->session; + size_t data_len = 0; + /* 13 = packet_len(4) + packet_type(1) + request_id(4) + path_len(4) */ +- ssize_t packet_len = +- path_len + 13 + +- ((stat_type == +- LIBSSH2_SFTP_SETSTAT) ? sftp_attrsize(attrs->flags) : 0); ++ uint32_t packet_len = 13 + ++ ((stat_type == ++ LIBSSH2_SFTP_SETSTAT) ? sftp_attrsize(attrs->flags) : 0); + unsigned char *s, *data = NULL; + static const unsigned char stat_responses[2] = + { SSH_FXP_ATTRS, SSH_FXP_STATUS }; + int rc; + ++ if(packet_len + path_len < packet_len) { ++ return _libssh2_error(session, LIBSSH2_ERROR_OUT_OF_BOUNDARY, ++ "Input too large " ++ "sftp_stat"); ++ } ++ packet_len += path_len; ++ + if(sftp->stat_state == libssh2_NB_state_idle) { + sftp->last_errno = LIBSSH2_FX_OK; + +@@ -3542,7 +3615,7 @@ static int sftp_stat(LIBSSH2_SFTP *sftp, const char *path, + "packet"); + } + +- _libssh2_store_u32(&s, (uint32_t)(packet_len - 4)); ++ _libssh2_store_u32(&s, packet_len - 4); + + switch(stat_type) { + case LIBSSH2_SFTP_SETSTAT: +@@ -3574,7 +3647,7 @@ static int sftp_stat(LIBSSH2_SFTP *sftp, const char *path, + if(nwritten == LIBSSH2_ERROR_EAGAIN) { + return (int)nwritten; + } +- else if(packet_len != nwritten) { ++ else if((ssize_t)packet_len != nwritten) { + LIBSSH2_FREE(session, sftp->stat_packet); + sftp->stat_packet = NULL; + sftp->stat_state = libssh2_NB_state_idle; +@@ -3660,15 +3733,35 @@ static int sftp_symlink(LIBSSH2_SFTP *sftp, const char *path, + LIBSSH2_CHANNEL *channel = sftp->channel; + LIBSSH2_SESSION *session = channel->session; + size_t data_len = 0, link_len; +- /* 13 = packet_len(4) + packet_type(1) + request_id(4) + path_len(4) */ +- ssize_t packet_len = +- path_len + 13 + +- ((link_type == LIBSSH2_SFTP_SYMLINK) ? (4 + target_len) : 0); ++ uint32_t packet_len; + unsigned char *s, *data = NULL; + static const unsigned char link_responses[2] = + { SSH_FXP_NAME, SSH_FXP_STATUS }; + int retcode; + ++ /* 13 = packet_len(4) + packet_type(1) + request_id(4) + path_len(4) */ ++ packet_len = 13; ++ ++ if(packet_len + path_len < packet_len) { ++ return _libssh2_error(session, LIBSSH2_ERROR_OUT_OF_BOUNDARY, ++ "Input too large " ++ "sftp_symlink"); ++ } ++ packet_len += path_len; ++ ++ if(link_type == LIBSSH2_SFTP_SYMLINK) { ++ ++ if((target_len + 4 < target_len) || ++ (packet_len + (4 + target_len) < packet_len)) { ++ return _libssh2_error(session, LIBSSH2_ERROR_OUT_OF_BOUNDARY, ++ "Input too large (2)" ++ "sftp_symlink"); ++ } ++ else { ++ packet_len += (4 + target_len); ++ } ++ } ++ + if(sftp->symlink_state == libssh2_NB_state_idle) { + sftp->last_errno = LIBSSH2_FX_OK; + +@@ -3692,7 +3785,7 @@ static int sftp_symlink(LIBSSH2_SFTP *sftp, const char *path, + LIBSSH2_SFTP_REALPATH) ? "realpath" : "symlink", + path)); + +- _libssh2_store_u32(&s, (uint32_t)(packet_len - 4)); ++ _libssh2_store_u32(&s, packet_len - 4); + + switch(link_type) { + case LIBSSH2_SFTP_REALPATH: +@@ -3722,7 +3815,7 @@ static int sftp_symlink(LIBSSH2_SFTP *sftp, const char *path, + packet_len); + if(rc == LIBSSH2_ERROR_EAGAIN) + return (int)rc; +- else if(packet_len != rc) { ++ else if((ssize_t)packet_len != rc) { + LIBSSH2_FREE(session, sftp->symlink_packet); + sftp->symlink_packet = NULL; + sftp->symlink_state = libssh2_NB_state_idle; +-- +2.43.0 + diff --git a/backport-Fix-small-leak-in-base64_encode-with-empty-data.patch b/backport-Fix-small-leak-in-base64_encode-with-empty-data.patch new file mode 100644 index 0000000..63e182c --- /dev/null +++ b/backport-Fix-small-leak-in-base64_encode-with-empty-data.patch @@ -0,0 +1,34 @@ +From cea8783ed8cc0e3c8feea0e4269ca41641f00f44 Mon Sep 17 00:00:00 2001 +From: Will Cosgrove +Date: Mon, 21 Jul 2025 11:48:25 -0700 +Subject: [PATCH] Fix small leak in base64_encode() with empty data #1627 + (#1630) + +Fix small memory leak when trying to encode base64 data with no data. + +Credit: +Liu Xing Yu + +Conflict:NA +Reference:https://github.com/libssh2/libssh2/commit/cea8783ed8cc0e3c8feea0e4269ca41641f00f44 +--- + src/misc.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/src/misc.c b/src/misc.c +index 6515311..63448ed 100644 +--- a/src/misc.c ++++ b/src/misc.c +@@ -425,6 +425,9 @@ size_t _libssh2_base64_encode(LIBSSH2_SESSION *session, + if(insize == 0) + insize = strlen(indata); + ++ if(insize == 0) ++ return 0; /* nothing to encode */ ++ + base64data = output = LIBSSH2_ALLOC(session, insize * 4 / 3 + 4); + if(!output) + return 0; +-- +2.43.0 + diff --git a/backport-Handle-malformed-comments-in-known_hosts-parsing.patch b/backport-Handle-malformed-comments-in-known_hosts-parsing.patch new file mode 100644 index 0000000..463a2a3 --- /dev/null +++ b/backport-Handle-malformed-comments-in-known_hosts-parsing.patch @@ -0,0 +1,34 @@ +From aa4c7b5b96d3d8ba5a452e5227cf9ed71b5a8d2e Mon Sep 17 00:00:00 2001 +From: Will Cosgrove +Date: Mon, 21 Jul 2025 11:46:58 -0700 +Subject: [PATCH] Handle malformed comments in known_hosts parsing #1628 + (#1629) + +Notes: +Handle malformed comment in known_hosts parsing to avoid buffer overflow. + +Credit: +Liu Xing Yu + +Conflict:NA +Reference:https://github.com/libssh2/libssh2/commit/aa4c7b5b96d3d8ba5a452e5227cf9ed71b5a8d2e +--- + src/knownhost.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/knownhost.c b/src/knownhost.c +index c223118..5e12e34 100644 +--- a/src/knownhost.c ++++ b/src/knownhost.c +@@ -789,7 +789,7 @@ static int hostline(LIBSSH2_KNOWNHOSTS *hosts, + key_type = LIBSSH2_KNOWNHOST_KEY_UNKNOWN; + + /* skip whitespaces */ +- while((*key ==' ') || (*key == '\t')) { ++ while(keylen && ((*key ==' ') || (*key == '\t'))) { + key++; + keylen--; + } +-- +2.43.0 + diff --git a/backport-Improve-known_hosts-parsing-and-harden-_libssh2_base64_encode.patch b/backport-Improve-known_hosts-parsing-and-harden-_libssh2_base64_encode.patch new file mode 100644 index 0000000..1122392 --- /dev/null +++ b/backport-Improve-known_hosts-parsing-and-harden-_libssh2_base64_encode.patch @@ -0,0 +1,93 @@ +From d1c0e14d2a7a82de83b9085299bcb9f715c57416 Mon Sep 17 00:00:00 2001 +From: Will Cosgrove +Date: Mon, 25 Aug 2025 09:36:40 -0700 +Subject: [PATCH] Improve known_hosts parsing and harden + _libssh2_base64_encode() (#1641) + +Notes: +Added additional base64 decoding validation when parsing known_hosts and no longer assume what is going into _libssh2_base64_encode() is a null terminated C string, input now must have a length and buffer. + +Reported by: +Dhiraj Mishra mishra.dhiraj95@gmail.com + +Credit: +Will Cosgrove + +Reviewed by: +Michael Buckley + +Conflict:add salt check in knownhost.c +Reference:https://github.com/libssh2/libssh2/commit/d1c0e14d2a7a82de83b9085299bcb9f715c57416 +--- + src/knownhost.c | 26 ++++++++++++++++++++++++-- + src/misc.c | 3 --- + 2 files changed, 24 insertions(+), 5 deletions(-) + +diff --git a/src/knownhost.c b/src/knownhost.c +index 5e12e34..2ffeba7 100644 +--- a/src/knownhost.c ++++ b/src/knownhost.c +@@ -140,8 +140,8 @@ knownhost_add(LIBSSH2_KNOWNHOSTS *hosts, + struct known_host *entry; + size_t hostlen = strlen(host); + int rc; +- char *ptr; +- size_t ptrlen; ++ char *ptr = NULL; ++ size_t ptrlen = 0; + + /* make sure we have a key type set */ + if(!(typemask & LIBSSH2_KNOWNHOST_KEY_MASK)) +@@ -173,13 +173,35 @@ knownhost_add(LIBSSH2_KNOWNHOSTS *hosts, + host, hostlen); + if(rc) + goto error; ++ ++ if(!ptr || ptrlen == 0) { ++ rc = _libssh2_error(hosts->session, LIBSSH2_ERROR_INVAL, ++ "Base64 decoded value is invalid"); ++ goto error; ++ } ++ ++ if(!salt) { ++ rc = _libssh2_error(hosts->session, LIBSSH2_ERROR_INVAL, ++ "Salt is NULL"); ++ goto error; ++ } ++ + entry->name = ptr; + entry->name_len = ptrlen; + ++ ptr = NULL; ++ ptrlen = 0; + rc = _libssh2_base64_decode(hosts->session, &ptr, &ptrlen, + salt, strlen(salt)); + if(rc) + goto error; ++ ++ if(!ptr || ptrlen == 0) { ++ rc = _libssh2_error(hosts->session, LIBSSH2_ERROR_INVAL, ++ "Base64 decoded value is invalid"); ++ goto error; ++ } ++ + entry->salt = ptr; + entry->salt_len = ptrlen; + break; +diff --git a/src/misc.c b/src/misc.c +index 63448ed..d70719d 100644 +--- a/src/misc.c ++++ b/src/misc.c +@@ -422,9 +422,6 @@ size_t _libssh2_base64_encode(LIBSSH2_SESSION *session, + *outptr = NULL; /* set to NULL in case of failure before we reach the + end */ + +- if(insize == 0) +- insize = strlen(indata); +- + if(insize == 0) + return 0; /* nothing to encode */ + +-- +2.43.0 + diff --git a/backport-kex-fix-DH-GEX-sha256-bignum-initialization.patch b/backport-kex-fix-DH-GEX-sha256-bignum-initialization.patch new file mode 100644 index 0000000..b1ce0bf --- /dev/null +++ b/backport-kex-fix-DH-GEX-sha256-bignum-initialization.patch @@ -0,0 +1,42 @@ +From 30befffe04314dfd8e6168485ae1a82dff331472 Mon Sep 17 00:00:00 2001 +From: Josh Brobst +Date: Sun, 11 May 2025 14:15:58 -0400 +Subject: [PATCH] kex: fix DH-GEX-sha256 bignum initialization + +In `kex_method_diffie_hellman_group_exchange_sha256_key_exchange`, +`p` and `g` are later initialized with `_libssh2_bn_from_bin`, so they +should be initially created using `_libssh2_bn_init_from_bin` rather +than `_libssh2_bn_init`, as is done in +`kex_method_diffie_hellman_group_exchange_sha1_key_exchange`. + +Fixing memory leaks when using the libgcrypt backend. + +Follow-up to 09c5e59933daf67b833f34b8c388766abc038483 +Ref: https://web.archive.org/web/trac.libssh2.org/ticket/168 + +Closes #1599 + +Conflict:NA +Reference:https://github.com/libssh2/libssh2/commit/30befffe04314dfd8e6168485ae1a82dff331472 +--- + src/kex.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/kex.c b/src/kex.c +index 7053316..d211e26 100644 +--- a/src/kex.c ++++ b/src/kex.c +@@ -1465,8 +1465,8 @@ kex_method_diffie_hellman_group_exchange_sha256_key_exchange( + int rc; + + if(key_state->state == libssh2_NB_state_idle) { +- key_state->p = _libssh2_bn_init(); +- key_state->g = _libssh2_bn_init(); ++ key_state->p = _libssh2_bn_init_from_bin(); ++ key_state->g = _libssh2_bn_init_from_bin(); + /* Ask for a P and G pair */ + key_state->request[0] = SSH_MSG_KEX_DH_GEX_REQUEST; + _libssh2_htonu32(key_state->request + 1, LIBSSH2_DH_GEX_MINGROUP); +-- +2.43.0 + diff --git a/backport-mbedtls-fix-using-garbage-value-reported-by-clang-tidy.patch b/backport-mbedtls-fix-using-garbage-value-reported-by-clang-tidy.patch new file mode 100644 index 0000000..408c23e --- /dev/null +++ b/backport-mbedtls-fix-using-garbage-value-reported-by-clang-tidy.patch @@ -0,0 +1,48 @@ +From 16ce0ec89b6f171cf5f094bb41d6de80c17d98da Mon Sep 17 00:00:00 2001 +From: Viktor Szakats +Date: Sat, 18 Oct 2025 22:59:49 +0200 +Subject: [PATCH] mbedtls: fix using garbage value (reported by clang-tidy) + +In `_libssh2_mbedtls_pub_priv_key()` on a NON-error code path, a stack +variable was checked without initializing it first. + +I found it interesting that clang-tidy did not find this when building +against the system mbedtls (2.x) with 2.x compatibility code still in. +Then it did find it when using a manual build of mbedtls 3.1.0 with +2.x compatibility code deleted from libssh2. Being such a trivial error +I wonder why no compiler ever detected it as a regular warning. + +linux (clang-tidy, amd64, mbedTLS-prev [3.1.0], cmake, ON): +``` +src/mbedtls.c:744:8: error: Branch condition evaluates to a garbage value [clang-analyzer-core.uninitialized.Branch,-warnings-as-errors] + 744 | if(ret) { + | ^ +``` +Ref: https://github.com/libssh2/libssh2/actions/runs/18620615649/job/53091295760#step:22:44 + +Follow-up to 186f1a2d75560d960bc9ec0e727c14328f51ca4a #132 +Cherry-picked from #1727 +Closes #1729 + +Conflict:NA +Reference:https://github.com/libssh2/libssh2/commit/16ce0ec89b6f171cf5f094bb41d6de80c17d98da +--- + src/mbedtls.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/src/mbedtls.c b/src/mbedtls.c +index 28c4477..60f6d92 100644 +--- a/src/mbedtls.c ++++ b/src/mbedtls.c +@@ -695,6 +695,8 @@ _libssh2_mbedtls_pub_priv_key(LIBSSH2_SESSION *session, + "Key type not supported"); + } + ++ ret = 0; ++ + /* write method */ + mthlen = 7; + mth = LIBSSH2_ALLOC(session, mthlen); +-- +2.43.0 + diff --git a/backport-packet-authagent_open-fix-failure-packet-length.patch b/backport-packet-authagent_open-fix-failure-packet-length.patch new file mode 100644 index 0000000..c115206 --- /dev/null +++ b/backport-packet-authagent_open-fix-failure-packet-length.patch @@ -0,0 +1,33 @@ +From 31ec5a8b55cc90efb0bd1bb2be621e416f1444ef Mon Sep 17 00:00:00 2001 +From: Joshua Rogers +Date: Fri, 10 Oct 2025 01:18:53 +0800 +Subject: [PATCH] packet: authagent_open: fix failure packet length (#1701) + +Compute packet_len using strlen(AuthAgentUnavail) (not X11FwdUnAvil). +The mismatch could send 1 uninitialized byte on the wire. + +Credit: +Joshua Rogers + +Conflict:integrate Commit 88a960a of packet.c +Reference:https://github.com/libssh2/libssh2/commit/31ec5a8b55cc90efb0bd1bb2be621e416f1444ef +--- + src/packet.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/packet.c b/src/packet.c +index 35d4d39..cc43fb4 100644 +--- a/src/packet.c ++++ b/src/packet.c +@@ -462,7 +462,7 @@ packet_authagent_open(LIBSSH2_SESSION * session, + { + int failure_code = SSH_OPEN_CONNECT_FAILED; + /* 17 = packet_type(1) + channel(4) + reason(4) + descr(4) + lang(4) */ +- size_t packet_len = 17 + (sizeof(X11FwdUnAvil) - 1); ++ size_t packet_len = 17 + strlen(AuthAgentUnavail); + unsigned char *p; + LIBSSH2_CHANNEL *channel = authagent_state->channel; + int rc; +-- +2.43.0 + diff --git a/backport-scp-fix-NULL-dereference-in-path-arg-of-send-recv.patch b/backport-scp-fix-NULL-dereference-in-path-arg-of-send-recv.patch new file mode 100644 index 0000000..5d1e71c --- /dev/null +++ b/backport-scp-fix-NULL-dereference-in-path-arg-of-send-recv.patch @@ -0,0 +1,95 @@ +From 992dafbc7f800f8a86c0855a6ea4157bdeb1201d Mon Sep 17 00:00:00 2001 +From: Ryan Kelley +Date: Mon, 21 Jul 2025 13:02:42 -0400 +Subject: [PATCH] scp: fix NULL dereference in path arg of send/recv (#1625) + +Notes: +* Error handling if path for scp is NULL + +Reported-by: +Liu Xing Yu + +Credit: +Ryan Kelley + +Conflict:NA +Reference:https://github.com/libssh2/libssh2/commit/992dafbc7f800f8a86c0855a6ea4157bdeb1201d +--- + docs/libssh2_scp_recv.3 | 2 ++ + docs/libssh2_scp_recv2.3 | 2 ++ + docs/libssh2_scp_send64.3 | 2 ++ + src/scp.c | 12 ++++++++++++ + 4 files changed, 18 insertions(+) + +diff --git a/docs/libssh2_scp_recv.3 b/docs/libssh2_scp_recv.3 +index 7d194d4..ea93ce4 100644 +--- a/docs/libssh2_scp_recv.3 ++++ b/docs/libssh2_scp_recv.3 +@@ -26,6 +26,8 @@ Pointer to a newly allocated LIBSSH2_CHANNEL instance, or NULL on errors. + .SH ERRORS + \fILIBSSH2_ERROR_ALLOC\fP - An internal memory allocation call failed. + ++\fILIBSSH2_ERROR_INVAL\fP - Invalid argument used in function call. ++ + \fILIBSSH2_ERROR_SCP_PROTOCOL\fP - + + \fILIBSSH2_ERROR_EAGAIN\fP - Marked for non-blocking I/O but the call would +diff --git a/docs/libssh2_scp_recv2.3 b/docs/libssh2_scp_recv2.3 +index 4d763fc..5f795ef 100644 +--- a/docs/libssh2_scp_recv2.3 ++++ b/docs/libssh2_scp_recv2.3 +@@ -23,6 +23,8 @@ Pointer to a newly allocated LIBSSH2_CHANNEL instance, or NULL on errors. + .SH ERRORS + \fILIBSSH2_ERROR_ALLOC\fP - An internal memory allocation call failed. + ++\fILIBSSH2_ERROR_INVAL\fP - Invalid argument used in function call. ++ + \fILIBSSH2_ERROR_SCP_PROTOCOL\fP - + + \fILIBSSH2_ERROR_EAGAIN\fP - Marked for non-blocking I/O but the call would +diff --git a/docs/libssh2_scp_send64.3 b/docs/libssh2_scp_send64.3 +index df63b7e..27122e7 100644 +--- a/docs/libssh2_scp_send64.3 ++++ b/docs/libssh2_scp_send64.3 +@@ -35,6 +35,8 @@ Pointer to a newly allocated LIBSSH2_CHANNEL instance, or NULL on errors. + .SH ERRORS + \fILIBSSH2_ERROR_ALLOC\fP - An internal memory allocation call failed. + ++\fILIBSSH2_ERROR_INVAL\fP - Invalid argument used in function call. ++ + \fILIBSSH2_ERROR_SOCKET_SEND\fP - Unable to send data on socket. + + \fILIBSSH2_ERROR_SCP_PROTOCOL\fP - +diff --git a/src/scp.c b/src/scp.c +index ede0b88..80548c9 100644 +--- a/src/scp.c ++++ b/src/scp.c +@@ -282,6 +282,12 @@ scp_recv(LIBSSH2_SESSION * session, const char *path, libssh2_struct_stat * sb) + int tmp_err_code; + const char *tmp_err_msg; + ++ if(!path) { ++ _libssh2_error(session, LIBSSH2_ERROR_INVAL, ++ "Path argument can not be null"); ++ return NULL; ++ } ++ + if(session->scpRecv_state == libssh2_NB_state_idle) { + session->scpRecv_mode = 0; + session->scpRecv_size = 0; +@@ -858,6 +864,12 @@ scp_send(LIBSSH2_SESSION * session, const char *path, int mode, + int tmp_err_code; + const char *tmp_err_msg; + ++ if(!path) { ++ _libssh2_error(session, LIBSSH2_ERROR_INVAL, ++ "Path argument can not be null"); ++ return NULL; ++ } ++ + if(session->scpSend_state == libssh2_NB_state_idle) { + session->scpSend_command_len = + _libssh2_shell_quotedsize(path) + sizeof("scp -t ") + +-- +2.43.0 + diff --git a/libssh2.spec b/libssh2.spec index fd933df..05fef36 100644 --- a/libssh2.spec +++ b/libssh2.spec @@ -1,6 +1,6 @@ Name: libssh2 Version: 1.11.0 -Release: 4 +Release: 5 Summary: A library implementing the SSH2 protocol License: BSD URL: https://www.libssh2.org/ @@ -18,6 +18,14 @@ Patch8: backport-buildconf-drop.patch Patch9: backport-Prevent-possible-double-free-of-hostkey.patch Patch10: backport-Fix-unstable-connections-over-nonblocking-sockets.patch Patch11: backport-session-support-server-banners-up-to-8192-bytes-was-256.patch +Patch12: backport-scp-fix-NULL-dereference-in-path-arg-of-send-recv.patch +Patch13: backport-Handle-malformed-comments-in-known_hosts-parsing.patch +Patch14: backport-Fix-small-leak-in-base64_encode-with-empty-data.patch +Patch15: backport-kex-fix-DH-GEX-sha256-bignum-initialization.patch +Patch16: backport-Improve-known_hosts-parsing-and-harden-_libssh2_base64_encode.patch +Patch17: backport-Add-input-bounds-checking-to-SFTP-API.patch +Patch18: backport-packet-authagent_open-fix-failure-packet-length.patch +Patch19: backport-mbedtls-fix-using-garbage-value-reported-by-clang-tidy.patch BuildRequires: coreutils findutils /usr/bin/man zlib-devel BuildRequires: gcc make sed openssl-devel > 1:1.0.2 openssh-server @@ -97,6 +105,12 @@ echo "exit 0" > tests/mansyntax.sh %{_mandir}/man3/libssh2_*.3* %changelog +* Tue Dec 02 2025 zhaoyonghao - 1.11.0-5 +- Type:bugfix +- CVE: +- SUG:NA +- DESC:backport some patches from upstream + * Tue Oct 29 2024 bitianyuan - 1.11.0-4 - Type:bugfix - ID:NA -- Gitee