From 693a2606b678b14c3e078ac61375f535373dce29 Mon Sep 17 00:00:00 2001 From: dmiller Date: Mon, 27 Jul 2026 15:55:34 +0000 Subject: [PATCH] Backport patches for libssh2 CVEs. Bump version string. --- libssh2/include/libssh2.h | 4 +-- libssh2/src/libssh2_priv.h | 8 +++++ libssh2/src/packet.c | 6 ++-- libssh2/src/sftp.c | 66 +++++++++++++++++++++++++++----------- libssh2/src/transport.c | 6 +++- libssh2/src/userauth.c | 13 +++++++- 6 files changed, 78 insertions(+), 25 deletions(-) diff --git a/libssh2/include/libssh2.h b/libssh2/include/libssh2.h index f47858aed..03f442155 100644 --- a/libssh2/include/libssh2.h +++ b/libssh2/include/libssh2.h @@ -48,7 +48,7 @@ to make the BANNER define (used by src/session.c) be a valid SSH banner. Release versions have no appended strings and may of course not have dashes either. */ -#define LIBSSH2_VERSION "1.11.1" +#define LIBSSH2_VERSION "1.11.1_NMAP1" /* The numeric version number is also available "in parts" by using these defines: */ @@ -82,7 +82,7 @@ * * "Mon Feb 12 11:35:33 UTC 2007" */ -#define LIBSSH2_TIMESTAMP "Wed Oct 16 08:03:21 UTC 2024" +#define LIBSSH2_TIMESTAMP "Wed Jul 27 15:27:00 UTC 2026" #ifndef RC_INVOKED diff --git a/libssh2/src/libssh2_priv.h b/libssh2/src/libssh2_priv.h index 9b8866dcc..bb1f8ad3f 100644 --- a/libssh2/src/libssh2_priv.h +++ b/libssh2/src/libssh2_priv.h @@ -117,6 +117,14 @@ #define UINT32_MAX 0xffffffffU #endif +#ifdef _WIN64 +#define LIBSSH2_UNCONST(p) ((void *)(libssh2_uint64_t)(const void *)(p)) +#elif defined(_MSC_VER) +#define LIBSSH2_UNCONST(p) ((void *)(unsigned int)(const void *)(p)) +#else +#define LIBSSH2_UNCONST(p) ((void *)(uintptr_t)(const void *)(p)) +#endif + #if (defined(__GNUC__) || defined(__clang__)) && \ defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \ !defined(LIBSSH2_NO_FMT_CHECKS) diff --git a/libssh2/src/packet.c b/libssh2/src/packet.c index 6da14e9fa..ebaddae56 100644 --- a/libssh2/src/packet.c +++ b/libssh2/src/packet.c @@ -868,8 +868,10 @@ _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data, nr_extensions -= 1; - _libssh2_get_string(&buf, &name, &name_len); - _libssh2_get_string(&buf, &value, &value_len); + if(_libssh2_get_string(&buf, &name, &name_len)) + break; + if(_libssh2_get_string(&buf, &value, &value_len)) + break; if(name && value) { _libssh2_debug((session, diff --git a/libssh2/src/sftp.c b/libssh2/src/sftp.c index 6ede31110..43b6ff901 100644 --- a/libssh2/src/sftp.c +++ b/libssh2/src/sftp.c @@ -3795,15 +3795,19 @@ 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; + size_t data_len = 0, lk_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); unsigned char *s, *data = NULL; + struct string_buf buf; static const unsigned char link_responses[2] = { SSH_FXP_NAME, SSH_FXP_STATUS }; int retcode; + unsigned char packet_type; + uint32_t tmp_u32; + unsigned char *lk_target; if(sftp->symlink_state == libssh2_NB_state_idle) { sftp->last_errno = LIBSSH2_FX_OK; @@ -3891,8 +3895,25 @@ static int sftp_symlink(LIBSSH2_SFTP *sftp, const char *path, sftp->symlink_state = libssh2_NB_state_idle; - if(data[0] == SSH_FXP_STATUS) { - retcode = _libssh2_ntohu32(data + 5); + buf.data = (unsigned char *)LIBSSH2_UNCONST(data); + buf.dataptr = buf.data; + buf.len = data_len; + + if(_libssh2_get_byte(&buf, &packet_type)) { + LIBSSH2_FREE(session, data); + return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, + "SFTP Protocol Error (type)"); + } + + if(packet_type == SSH_FXP_STATUS) { + if(_libssh2_get_u32(&buf, &tmp_u32)) { + LIBSSH2_FREE(session, data); + return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, + "SFTP Protocol Error (code)"); + } + + retcode = (int)tmp_u32; + LIBSSH2_FREE(session, data); if(retcode == LIBSSH2_FX_OK) return LIBSSH2_ERROR_NONE; @@ -3903,30 +3924,37 @@ static int sftp_symlink(LIBSSH2_SFTP *sftp, const char *path, } } - if(_libssh2_ntohu32(data + 5) < 1) { + /* advance past id */ + if(_libssh2_get_u32(&buf, &tmp_u32)) { LIBSSH2_FREE(session, data); return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, - "Invalid READLINK/REALPATH response, " - "no name entries"); + "SFTP Protocol Error (id)"); } - if(data_len < 13) { - if(data_len > 0) { - LIBSSH2_FREE(session, data); - } + /* look for at least one link */ + if(_libssh2_get_u32(&buf, &tmp_u32) || tmp_u32 < 1) { + LIBSSH2_FREE(session, data); return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, - "SFTP stat packet too short"); + "Invalid READLINK/REALPATH response, " + "no name entries"); } - /* this reads a u32 and stores it into a signed 32bit value */ - link_len = _libssh2_ntohu32(data + 9); - if(link_len < target_len) { - memcpy(target, data + 13, link_len); - target[link_len] = 0; - retcode = (int)link_len; + if(_libssh2_get_string(&buf, &lk_target, &lk_len) == LIBSSH2_ERROR_NONE) { + if(lk_len < target_len) { + memcpy(target, lk_target, lk_len); + target[lk_len] = '\0'; + retcode = (int)lk_len; + } + else { + retcode = LIBSSH2_ERROR_BUFFER_TOO_SMALL; + } } - else - retcode = LIBSSH2_ERROR_BUFFER_TOO_SMALL; + else { + LIBSSH2_FREE(session, data); + return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, + "SFTP Protocol Error (filename)"); + } + LIBSSH2_FREE(session, data); return retcode; diff --git a/libssh2/src/transport.c b/libssh2/src/transport.c index e1120656c..d147505b7 100644 --- a/libssh2/src/transport.c +++ b/libssh2/src/transport.c @@ -639,8 +639,12 @@ int _libssh2_transport_read(LIBSSH2_SESSION * session) total_num = 4; p->packet_length = _libssh2_ntohu32(block); - if(p->packet_length < 1) + if(p->packet_length < 1) { return LIBSSH2_ERROR_DECRYPT; + } + else if(p->packet_length > LIBSSH2_PACKET_MAXPAYLOAD) { + return LIBSSH2_ERROR_OUT_OF_BOUNDARY; + } /* total_num may include size field, however due to existing * logic it needs to be removed after the entire packet is read diff --git a/libssh2/src/userauth.c b/libssh2/src/userauth.c index 0040c3fa3..588b83f24 100644 --- a/libssh2/src/userauth.c +++ b/libssh2/src/userauth.c @@ -80,6 +80,12 @@ static char *userauth_list(LIBSSH2_SESSION *session, const char *username, memset(&session->userauth_list_packet_requirev_state, 0, sizeof(session->userauth_list_packet_requirev_state)); + if(username_len > UINT32_MAX - 27) { + _libssh2_error(session, LIBSSH2_ERROR_PROTO, + "username_len out of bounds"); + return NULL; + } + session->userauth_list_data_len = username_len + 27; s = session->userauth_list_data = @@ -307,6 +313,11 @@ userauth_password(LIBSSH2_SESSION *session, * 40 = packet_type(1) + username_len(4) + service_len(4) + * service(14)"ssh-connection" + method_len(4) + method(8)"password" + * chgpwdbool(1) + password_len(4) */ + if(username_len > UINT32_MAX - 40) { + return _libssh2_error(session, LIBSSH2_ERROR_PROTO, + "username_len out of bounds"); + } + session->userauth_pswd_data_len = username_len + 40; session->userauth_pswd_data0 = @@ -447,7 +458,7 @@ password_response: } /* basic data_len + newpw_len(4) */ - if(username_len + password_len + 44 <= UINT_MAX) { + if(username_len <= UINT32_MAX - password_len - 44) { session->userauth_pswd_data_len = username_len + password_len + 44; s = session->userauth_pswd_data =