summaryrefslogtreecommitdiff
path: root/libs/libssh2
diff options
context:
space:
mode:
authorGeorge Hazan <ghazan@miranda.im>2019-03-15 16:04:01 +0300
committerGeorge Hazan <ghazan@miranda.im>2019-03-15 16:04:01 +0300
commit7b425e06f940fbc0a1d962bee7695530fcc70ceb (patch)
treefb232f9f2066ccf19ce46ec8d92fdc2534f4c938 /libs/libssh2
parent2084ac854656d90a030de560d69d6c5080f9bb00 (diff)
libssh updated to 1.8.1
Diffstat (limited to 'libs/libssh2')
-rw-r--r--libs/libssh2/docs/RELEASE-NOTES48
-rw-r--r--libs/libssh2/include/libssh2.h24
-rw-r--r--libs/libssh2/src/channel.c26
-rw-r--r--libs/libssh2/src/comp.c9
-rw-r--r--libs/libssh2/src/kex.c24
-rw-r--r--libs/libssh2/src/packet.c25
-rw-r--r--libs/libssh2/src/session.c5
-rw-r--r--libs/libssh2/src/sftp.c317
-rw-r--r--libs/libssh2/src/transport.c26
-rw-r--r--libs/libssh2/src/userauth.c55
10 files changed, 446 insertions, 113 deletions
diff --git a/libs/libssh2/docs/RELEASE-NOTES b/libs/libssh2/docs/RELEASE-NOTES
index 5b78ede381..6c2d7de324 100644
--- a/libs/libssh2/docs/RELEASE-NOTES
+++ b/libs/libssh2/docs/RELEASE-NOTES
@@ -1,31 +1,29 @@
-libssh2 1.8.0
-
-This release includes the following changes:
-
- o added a basic dockerised test suite
- o crypto: add support for the mbedTLS backend
+libssh2 1.8.1
This release includes the following bugfixes:
-
- o libgcrypt: fixed a NULL pointer dereference on OOM
- o VMS: can't use %zd for off_t format
- o VMS: update vms/libssh2_config.h
- o windows: link with crypt32.lib
- o libssh2_channel_open: speeling error fixed in channel error message
- o msvc: fixed 14 compilation warnings
- o tests: HAVE_NETINET_IN_H was not defined correctly
- o openssl: add OpenSSL 1.1.0 compatibility
- o cmake: Add CLEAR_MEMORY option, analogously to that for autoconf
- o configure: make the --with-* options override the OpenSSL default
- o libssh2_wait_socket: set err_msg on errors
- o libssh2_wait_socket: Fix comparison with api_timeout to use milliseconds
+ o fixed possible integer overflow when reading a specially crafted packet
+ (https://www.libssh2.org/CVE-2019-3855.html)
+ o fixed possible integer overflow in userauth_keyboard_interactive with a
+ number of extremely long prompt strings
+ (https://www.libssh2.org/CVE-2019-3863.html)
+ o fixed possible integer overflow if the server sent an extremely large number
+ of keyboard prompts (https://www.libssh2.org/CVE-2019-3856.html)
+ o fixed possible out of bounds read when processing a specially crafted packet
+ (https://www.libssh2.org/CVE-2019-3861.html)
+ o fixed possible integer overflow when receiving a specially crafted exit
+ signal message channel packet (https://www.libssh2.org/CVE-2019-3857.html)
+ o fixed possible out of bounds read when receiving a specially crafted exit
+ status message channel packet (https://www.libssh2.org/CVE-2019-3862.html)
+ o fixed possible zero byte allocation when reading a specially crafted SFTP
+ packet (https://www.libssh2.org/CVE-2019-3858.html)
+ o fixed possible out of bounds reads when processing specially crafted SFTP
+ packets (https://www.libssh2.org/CVE-2019-3860.html)
+ o fixed possible out of bounds reads in _libssh2_packet_require(v)
+ (https://www.libssh2.org/CVE-2019-3859.html)
+
This release would not have looked like this without help, code, reports and
advice from friends like these:
- Alexander Lamaison, Antenore Gatta, Brad Harder, Charles Collicutt,
- Craig A. Berry, Dan Fandrich, Daniel Stenberg, Kamil Dudka, Keno Fischer,
- Taylor Holberton, Viktor Szakats, Will Cosgrove, Zenju
- (12 contributors)
-
- Thanks! (and sorry if I forgot to mention someone)
+ Chris Coulson, Michael Buckley, Will Cosgrove, Daniel Stenberg
+ (4 contributors)
diff --git a/libs/libssh2/include/libssh2.h b/libs/libssh2/include/libssh2.h
index 34d2842106..f4bae24bc5 100644
--- a/libs/libssh2/include/libssh2.h
+++ b/libs/libssh2/include/libssh2.h
@@ -46,13 +46,13 @@
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.8.0"
+#define LIBSSH2_VERSION "1.7.0_DEV"
/* The numeric version number is also available "in parts" by using these
defines: */
-#define LIBSSH2_VERSION_MAJOR 1
-#define LIBSSH2_VERSION_MINOR 8
-#define LIBSSH2_VERSION_PATCH 0
+#define LIBSSH2_VERSION_MAJOR 1
+#define LIBSSH2_VERSION_MINOR 7
+#define LIBSSH2_VERSION_PATCH 0
/* This is the numeric version of the libssh2 version number, meant for easier
parsing and comparions by programs. The LIBSSH2_VERSION_NUM define will
@@ -69,7 +69,7 @@
and it is always a greater number in a more recent release. It makes
comparisons with greater than and less than work.
*/
-#define LIBSSH2_VERSION_NUM 0x010800
+#define LIBSSH2_VERSION_NUM 0x010700
/*
* This is the date and time when the full source package was created. The
@@ -80,7 +80,7 @@
*
* "Mon Feb 12 11:35:33 UTC 2007"
*/
-#define LIBSSH2_TIMESTAMP "Tue Oct 25 06:44:33 UTC 2016"
+#define LIBSSH2_TIMESTAMP "DEV"
#ifndef RC_INVOKED
@@ -145,6 +145,18 @@ typedef int libssh2_socket_t;
#define LIBSSH2_INVALID_SOCKET -1
#endif /* WIN32 */
+#ifndef SIZE_MAX
+#if _WIN64
+#define SIZE_MAX 0xFFFFFFFFFFFFFFFF
+#else
+#define SIZE_MAX 0xFFFFFFFF
+#endif
+#endif
+
+#ifndef UINT_MAX
+#define UINT_MAX 0xFFFFFFFF
+#endif
+
/*
* Determine whether there is small or large file support on windows.
*/
diff --git a/libs/libssh2/src/channel.c b/libs/libssh2/src/channel.c
index 538a0ab0d9..39ff05bf13 100644
--- a/libs/libssh2/src/channel.c
+++ b/libs/libssh2/src/channel.c
@@ -238,7 +238,20 @@ _libssh2_channel_open(LIBSSH2_SESSION * session, const char *channel_type,
goto channel_error;
}
+ if(session->open_data_len < 1) {
+ _libssh2_error(session, LIBSSH2_ERROR_PROTO,
+ "Unexpected packet size");
+ goto channel_error;
+ }
+
if (session->open_data[0] == SSH_MSG_CHANNEL_OPEN_CONFIRMATION) {
+
+ if(session->open_data_len < 17) {
+ _libssh2_error(session, LIBSSH2_ERROR_PROTO,
+ "Unexpected packet size");
+ goto channel_error;
+ }
+
session->open_channel->remote.id =
_libssh2_ntohu32(session->open_data + 5);
session->open_channel->local.window_size =
@@ -518,7 +531,7 @@ channel_forward_listen(LIBSSH2_SESSION * session, const char *host,
if (rc == LIBSSH2_ERROR_EAGAIN) {
_libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block");
return NULL;
- } else if (rc) {
+ } else if (rc || data_len < 1) {
_libssh2_error(session, LIBSSH2_ERROR_PROTO, "Unknown");
session->fwdLstn_state = libssh2_NB_state_idle;
return NULL;
@@ -855,6 +868,11 @@ static int channel_setenv(LIBSSH2_CHANNEL *channel,
channel->setenv_state = libssh2_NB_state_idle;
return rc;
}
+ else if(data_len < 1) {
+ channel->setenv_state = libssh2_NB_state_idle;
+ return _libssh2_error(session, LIBSSH2_ERROR_PROTO,
+ "Unexpected packet size");
+ }
if (data[0] == SSH_MSG_CHANNEL_SUCCESS) {
LIBSSH2_FREE(session, data);
@@ -971,7 +989,7 @@ static int channel_request_pty(LIBSSH2_CHANNEL *channel,
&channel->reqPTY_packet_requirev_state);
if (rc == LIBSSH2_ERROR_EAGAIN) {
return rc;
- } else if (rc) {
+ } else if (rc || data_len < 1) {
channel->reqPTY_state = libssh2_NB_state_idle;
return _libssh2_error(session, LIBSSH2_ERROR_PROTO,
"Failed to require the PTY package");
@@ -1197,7 +1215,7 @@ channel_x11_req(LIBSSH2_CHANNEL *channel, int single_connection,
&channel->reqX11_packet_requirev_state);
if (rc == LIBSSH2_ERROR_EAGAIN) {
return rc;
- } else if (rc) {
+ } else if (rc || data_len < 1) {
channel->reqX11_state = libssh2_NB_state_idle;
return _libssh2_error(session, rc,
"waiting for x11-req response packet");
@@ -1324,7 +1342,7 @@ _libssh2_channel_process_startup(LIBSSH2_CHANNEL *channel,
&channel->process_packet_requirev_state);
if (rc == LIBSSH2_ERROR_EAGAIN) {
return rc;
- } else if (rc) {
+ } else if (rc || data_len < 1) {
channel->process_state = libssh2_NB_state_end;
return _libssh2_error(session, rc,
"Failed waiting for channel success");
diff --git a/libs/libssh2/src/comp.c b/libs/libssh2/src/comp.c
index 4560188bb7..6293195907 100644
--- a/libs/libssh2/src/comp.c
+++ b/libs/libssh2/src/comp.c
@@ -224,7 +224,12 @@ comp_method_zlib_decomp(LIBSSH2_SESSION * session,
/* A short-term alloc of a full data chunk is better than a series of
reallocs */
char *out;
- int out_maxlen = 4 * src_len;
+ size_t out_maxlen = src_len;
+
+ if (src_len <= SIZE_MAX / 4)
+ out_maxlen = src_len * 4;
+ else
+ out_maxlen = payload_limit;
/* If strm is null, then we have not yet been initialized. */
if (strm == NULL)
@@ -271,7 +276,7 @@ comp_method_zlib_decomp(LIBSSH2_SESSION * session,
"decompression failure");
}
- if (out_maxlen >= (int) payload_limit) {
+ if (out_maxlen > (int) payload_limit || out_maxlen > SIZE_MAX / 2) {
LIBSSH2_FREE(session, out);
return _libssh2_error(session, LIBSSH2_ERROR_ZLIB,
"Excessive growth in decompression phase");
diff --git a/libs/libssh2/src/kex.c b/libs/libssh2/src/kex.c
index 65b722f421..3634cb5a91 100644
--- a/libs/libssh2/src/kex.c
+++ b/libs/libssh2/src/kex.c
@@ -228,11 +228,23 @@ static int diffie_hellman_sha1(LIBSSH2_SESSION *session,
}
/* Parse KEXDH_REPLY */
+ if(exchange_state->s_packet_len < 5) {
+ ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
+ "Unexpected packet length");
+ goto clean_exit;
+ }
+
exchange_state->s = exchange_state->s_packet + 1;
session->server_hostkey_len = _libssh2_ntohu32(exchange_state->s);
exchange_state->s += 4;
+ if(session->server_hostkey_len > exchange_state->s_packet_len - 5) {
+ ret = _libssh2_error(session, LIBSSH2_ERROR_OUT_OF_BOUNDARY,
+ "Host key length out of bounds");
+ goto clean_exit;
+ }
+
if (session->server_hostkey)
LIBSSH2_FREE(session, session->server_hostkey);
@@ -848,11 +860,23 @@ static int diffie_hellman_sha256(LIBSSH2_SESSION *session,
}
/* Parse KEXDH_REPLY */
+ if(exchange_state->s_packet_len < 5) {
+ ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
+ "Unexpected packet length");
+ goto clean_exit;
+ }
+
exchange_state->s = exchange_state->s_packet + 1;
session->server_hostkey_len = _libssh2_ntohu32(exchange_state->s);
exchange_state->s += 4;
+ if(session->server_hostkey_len > exchange_state->s_packet_len - 5) {
+ ret = _libssh2_error(session, LIBSSH2_ERROR_OUT_OF_BOUNDARY,
+ "Host key length out of bounds");
+ goto clean_exit;
+ }
+
if (session->server_hostkey)
LIBSSH2_FREE(session, session->server_hostkey);
diff --git a/libs/libssh2/src/packet.c b/libs/libssh2/src/packet.c
index 5f1feb8c6b..c950b5dcfa 100644
--- a/libs/libssh2/src/packet.c
+++ b/libs/libssh2/src/packet.c
@@ -775,8 +775,8 @@ _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data,
uint32_t len = _libssh2_ntohu32(data + 5);
unsigned char want_reply = 1;
- if(len < (datalen - 10))
- want_reply = data[9 + len];
+ if((len + 9) < datalen)
+ want_reply = data[len + 9];
_libssh2_debug(session,
LIBSSH2_TRACE_CONN,
@@ -784,6 +784,7 @@ _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data,
channel, len, data + 9, want_reply);
if (len == sizeof("exit-status") - 1
+ && (sizeof("exit-status") - 1 + 9) <= datalen
&& !memcmp("exit-status", data + 9,
sizeof("exit-status") - 1)) {
@@ -792,7 +793,7 @@ _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data,
channelp =
_libssh2_channel_locate(session, channel);
- if (channelp) {
+ if (channelp && (sizeof("exit-status") + 13) <= datalen) {
channelp->exit_status =
_libssh2_ntohu32(data + 9 + sizeof("exit-status"));
_libssh2_debug(session, LIBSSH2_TRACE_CONN,
@@ -805,24 +806,32 @@ _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data,
}
else if (len == sizeof("exit-signal") - 1
+ && (sizeof("exit-signal") - 1 + 9) <= datalen
&& !memcmp("exit-signal", data + 9,
sizeof("exit-signal") - 1)) {
/* command terminated due to signal */
if(datalen >= 20)
channelp = _libssh2_channel_locate(session, channel);
- if (channelp) {
+ if (channelp && (sizeof("exit-signal") + 13) <= datalen) {
/* set signal name (without SIG prefix) */
uint32_t namelen =
_libssh2_ntohu32(data + 9 + sizeof("exit-signal"));
- channelp->exit_signal =
- LIBSSH2_ALLOC(session, namelen + 1);
+
+ if(namelen <= UINT_MAX - 1) {
+ channelp->exit_signal =
+ LIBSSH2_ALLOC(session, namelen + 1);
+ }
+ else {
+ channelp->exit_signal = NULL;
+ }
+
if (!channelp->exit_signal)
rc = _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
"memory for signal name");
- else {
+ else if ((sizeof("exit-signal") + 13 + namelen <= datalen)) {
memcpy(channelp->exit_signal,
- data + 13 + sizeof("exit_signal"), namelen);
+ data + 13 + sizeof("exit-signal"), namelen);
channelp->exit_signal[namelen] = '\0';
/* TODO: save error message and language tag */
_libssh2_debug(session, LIBSSH2_TRACE_CONN,
diff --git a/libs/libssh2/src/session.c b/libs/libssh2/src/session.c
index 6352d12ee7..b5a83ddd67 100644
--- a/libs/libssh2/src/session.c
+++ b/libs/libssh2/src/session.c
@@ -765,6 +765,11 @@ session_startup(LIBSSH2_SESSION *session, libssh2_socket_t sock)
if (rc)
return rc;
+ if(session->startup_data_len < 5) {
+ return _libssh2_error(session, LIBSSH2_ERROR_PROTO,
+ "Unexpected packet length");
+ }
+
session->startup_service_length =
_libssh2_ntohu32(session->startup_data + 1);
diff --git a/libs/libssh2/src/sftp.c b/libs/libssh2/src/sftp.c
index 7c44116401..fd94d39029 100644
--- a/libs/libssh2/src/sftp.c
+++ b/libs/libssh2/src/sftp.c
@@ -204,6 +204,10 @@ sftp_packet_add(LIBSSH2_SFTP *sftp, unsigned char *data,
LIBSSH2_SFTP_PACKET *packet;
uint32_t request_id;
+ if (data_len < 5) {
+ return LIBSSH2_ERROR_OUT_OF_BOUNDARY;
+ }
+
_libssh2_debug(session, LIBSSH2_TRACE_SFTP,
"Received packet type %d (len %d)",
(int) data[0], data_len);
@@ -345,6 +349,10 @@ sftp_packet_read(LIBSSH2_SFTP *sftp)
return _libssh2_error(session,
LIBSSH2_ERROR_CHANNEL_PACKET_EXCEEDED,
"SFTP packet too large");
+ if (sftp->partial_len == 0)
+ return _libssh2_error(session,
+ LIBSSH2_ERROR_ALLOC,
+ "Unable to allocate empty SFTP packet");
_libssh2_debug(session, LIBSSH2_TRACE_SFTP,
"Data begin - Packet Length: %lu",
@@ -504,11 +512,15 @@ sftp_packet_ask(LIBSSH2_SFTP *sftp, unsigned char packet_type,
static int
sftp_packet_require(LIBSSH2_SFTP *sftp, unsigned char packet_type,
uint32_t request_id, unsigned char **data,
- size_t *data_len)
+ size_t *data_len, size_t required_size)
{
LIBSSH2_SESSION *session = sftp->channel->session;
int rc;
+ if (data == NULL || data_len == NULL || required_size == 0) {
+ return LIBSSH2_ERROR_BAD_USE;
+ }
+
_libssh2_debug(session, LIBSSH2_TRACE_SFTP, "Requiring packet %d id %ld",
(int) packet_type, request_id);
@@ -516,6 +528,11 @@ sftp_packet_require(LIBSSH2_SFTP *sftp, unsigned char packet_type,
/* The right packet was available in the packet brigade */
_libssh2_debug(session, LIBSSH2_TRACE_SFTP, "Got %d",
(int) packet_type);
+
+ if (*data_len < required_size) {
+ return LIBSSH2_ERROR_OUT_OF_BOUNDARY;
+ }
+
return LIBSSH2_ERROR_NONE;
}
@@ -529,6 +546,11 @@ sftp_packet_require(LIBSSH2_SFTP *sftp, unsigned char packet_type,
/* The right packet was available in the packet brigade */
_libssh2_debug(session, LIBSSH2_TRACE_SFTP, "Got %d",
(int) packet_type);
+
+ if (*data_len < required_size) {
+ return LIBSSH2_ERROR_OUT_OF_BOUNDARY;
+ }
+
return LIBSSH2_ERROR_NONE;
}
}
@@ -544,11 +566,15 @@ static int
sftp_packet_requirev(LIBSSH2_SFTP *sftp, int num_valid_responses,
const unsigned char *valid_responses,
uint32_t request_id, unsigned char **data,
- size_t *data_len)
+ size_t *data_len, size_t required_size)
{
int i;
int rc;
+ if (data == NULL || data_len == NULL || required_size == 0) {
+ return LIBSSH2_ERROR_BAD_USE;
+ }
+
/* If no timeout is active, start a new one */
if (sftp->requirev_start == 0)
sftp->requirev_start = time(NULL);
@@ -562,6 +588,11 @@ sftp_packet_requirev(LIBSSH2_SFTP *sftp, int num_valid_responses,
* the timeout is not active
*/
sftp->requirev_start = 0;
+
+ if (*data_len < required_size) {
+ return LIBSSH2_ERROR_OUT_OF_BOUNDARY;
+ }
+
return LIBSSH2_ERROR_NONE;
}
}
@@ -636,36 +667,65 @@ sftp_attr2bin(unsigned char *p, const LIBSSH2_SFTP_ATTRIBUTES * attrs)
/* sftp_bin2attr
*/
static int
-sftp_bin2attr(LIBSSH2_SFTP_ATTRIBUTES * attrs, const unsigned char *p)
+sftp_bin2attr(LIBSSH2_SFTP_ATTRIBUTES * attrs, const unsigned char *p, size_t data_len)
{
const unsigned char *s = p;
- memset(attrs, 0, sizeof(LIBSSH2_SFTP_ATTRIBUTES));
- attrs->flags = _libssh2_ntohu32(s);
- s += 4;
+ if (data_len >= 4) {
+ memset(attrs, 0, sizeof(LIBSSH2_SFTP_ATTRIBUTES));
+ attrs->flags = _libssh2_ntohu32(s);
+ s += 4;
+ data_len -= 4;
+ }
+ else {
+ return LIBSSH2_ERROR_OUT_OF_BOUNDARY;
+ }
if (attrs->flags & LIBSSH2_SFTP_ATTR_SIZE) {
- attrs->filesize = _libssh2_ntohu64(s);
- s += 8;
+ if (data_len >= 8) {
+ attrs->filesize = _libssh2_ntohu64(s);
+ s += 8;
+ data_len -= 8;
+ }
+ else {
+ return LIBSSH2_ERROR_OUT_OF_BOUNDARY;
+ }
}
if (attrs->flags & LIBSSH2_SFTP_ATTR_UIDGID) {
- attrs->uid = _libssh2_ntohu32(s);
- s += 4;
- attrs->gid = _libssh2_ntohu32(s);
- s += 4;
+ if (data_len >= 8) {
+ attrs->uid = _libssh2_ntohu32(s);
+ s += 4;
+ attrs->gid = _libssh2_ntohu32(s);
+ s += 4;
+ data_len -= 8;
+ }
+ else {
+ return LIBSSH2_ERROR_OUT_OF_BOUNDARY;
+ }
}
if (attrs->flags & LIBSSH2_SFTP_ATTR_PERMISSIONS) {
- attrs->permissions = _libssh2_ntohu32(s);
- s += 4;
+ if (data_len >= 4) {
+ attrs->permissions = _libssh2_ntohu32(s);
+ s += 4;
+ data_len -= 4;
+ }
+ else {
+ return LIBSSH2_ERROR_OUT_OF_BOUNDARY;
+ }
}
if (attrs->flags & LIBSSH2_SFTP_ATTR_ACMODTIME) {
- attrs->atime = _libssh2_ntohu32(s);
- s += 4;
- attrs->mtime = _libssh2_ntohu32(s);
- s += 4;
+ if (data_len >= 8) {
+ attrs->atime = _libssh2_ntohu32(s);
+ s += 4;
+ attrs->mtime = _libssh2_ntohu32(s);
+ s += 4;
+ }
+ else {
+ return LIBSSH2_ERROR_OUT_OF_BOUNDARY;
+ }
}
return (s - p);
@@ -835,18 +895,23 @@ static LIBSSH2_SFTP *sftp_init(LIBSSH2_SESSION *session)
}
rc = sftp_packet_require(sftp_handle, SSH_FXP_VERSION,
- 0, &data, &data_len);
- if (rc == LIBSSH2_ERROR_EAGAIN)
+ 0, &data, &data_len, 5);
+ if (rc == LIBSSH2_ERROR_EAGAIN) {
+ _libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
+ "Would block receiving SSH_FXP_VERSION");
return NULL;
- else if (rc) {
- _libssh2_error(session, rc,
- "Timeout waiting for response from SFTP subsystem");
- goto sftp_init_error;
}
- if (data_len < 5) {
+ else if (rc == LIBSSH2_ERROR_OUT_OF_BOUNDARY) {
+ if (data_len > 0) {
+ LIBSSH2_FREE(session, data);
+ }
_libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
"Invalid SSH_FXP_VERSION response");
- LIBSSH2_FREE(session, data);
+ goto sftp_init_error;
+ }
+ else if (rc) {
+ _libssh2_error(session, rc,
+ "Timeout waiting for response from SFTP subsystem");
goto sftp_init_error;
}
@@ -1112,12 +1177,20 @@ sftp_open(LIBSSH2_SFTP *sftp, const char *filename,
{ SSH_FXP_HANDLE, SSH_FXP_STATUS };
rc = sftp_packet_requirev(sftp, 2, fopen_responses,
sftp->open_request_id, &data,
- &data_len);
+ &data_len, 1);
if (rc == LIBSSH2_ERROR_EAGAIN) {
_libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
"Would block waiting for status message");
return NULL;
}
+ else if (rc == LIBSSH2_ERROR_OUT_OF_BOUNDARY) {
+ if (data_len > 0) {
+ LIBSSH2_FREE(session, data);
+ }
+ _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
+ "Response too small");
+ return NULL;
+ }
sftp->open_state = libssh2_NB_state_idle;
if (rc) {
_libssh2_error(session, rc, "Timeout waiting for status message");
@@ -1148,12 +1221,20 @@ sftp_open(LIBSSH2_SFTP *sftp, const char *filename,
/* silly situation, but check for a HANDLE */
rc = sftp_packet_require(sftp, SSH_FXP_HANDLE,
sftp->open_request_id, &data,
- &data_len);
+ &data_len, 10);
if(rc == LIBSSH2_ERROR_EAGAIN) {
/* go back to sent state and wait for something else */
sftp->open_state = libssh2_NB_state_sent;
return NULL;
}
+ else if (rc == LIBSSH2_ERROR_OUT_OF_BOUNDARY) {
+ if (data_len > 0) {
+ LIBSSH2_FREE(session, data);
+ }
+ _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
+ "Too small FXP_HANDLE");
+ return NULL;
+ }
else if(!rc)
/* we got the handle so this is not a bad situation */
badness = 0;
@@ -1480,15 +1561,21 @@ static ssize_t sftp_read(LIBSSH2_SFTP_HANDLE * handle, char *buffer,
}
rc = sftp_packet_requirev(sftp, 2, read_responses,
- chunk->request_id, &data, &data_len);
-
- if (rc==LIBSSH2_ERROR_EAGAIN && bytes_in_buffer != 0) {
+ chunk->request_id, &data, &data_len, 9);
+ if (rc == LIBSSH2_ERROR_EAGAIN && bytes_in_buffer != 0) {
/* do not return EAGAIN if we have already
* written data into the buffer */
return bytes_in_buffer;
}
- if (rc < 0) {
+ if (rc == LIBSSH2_ERROR_OUT_OF_BOUNDARY) {
+ if (data_len > 0) {
+ LIBSSH2_FREE(session, data);
+ }
+ return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
+ "Response too small");
+ }
+ else if(rc < 0) {
sftp->read_state = libssh2_NB_state_sent2;
return rc;
}
@@ -1698,7 +1785,7 @@ static ssize_t sftp_readdir(LIBSSH2_SFTP_HANDLE *handle, char *buffer,
if (attrs)
memset(attrs, 0, sizeof(LIBSSH2_SFTP_ATTRIBUTES));
- s += sftp_bin2attr(attrs ? attrs : &attrs_dummy, s);
+ s += sftp_bin2attr(attrs ? attrs : &attrs_dummy, s, 32);
handle->u.dir.next_name = (char *) s;
end:
@@ -1753,9 +1840,16 @@ static ssize_t sftp_readdir(LIBSSH2_SFTP_HANDLE *handle, char *buffer,
retcode = sftp_packet_requirev(sftp, 2, read_responses,
sftp->readdir_request_id, &data,
- &data_len);
+ &data_len, 9);
if (retcode == LIBSSH2_ERROR_EAGAIN)
return retcode;
+ else if (retcode == LIBSSH2_ERROR_OUT_OF_BOUNDARY) {
+ if (data_len > 0) {
+ LIBSSH2_FREE(session, data);
+ }
+ return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
+ "Status message too short");
+ }
else if (retcode) {
sftp->readdir_state = libssh2_NB_state_idle;
return _libssh2_error(session, retcode,
@@ -1981,8 +2075,15 @@ static ssize_t sftp_write(LIBSSH2_SFTP_HANDLE *handle, const char *buffer,
/* we check the packets in order */
rc = sftp_packet_require(sftp, SSH_FXP_STATUS,
- chunk->request_id, &data, &data_len);
- if (rc < 0) {
+ chunk->request_id, &data, &data_len, 9);
+ if (rc == LIBSSH2_ERROR_OUT_OF_BOUNDARY) {
+ if (data_len > 0) {
+ LIBSSH2_FREE(session, data);
+ }
+ return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
+ "FXP write packet too short");
+ }
+ else if (rc < 0) {
if (rc == LIBSSH2_ERROR_EAGAIN)
sftp->write_state = libssh2_NB_state_sent;
return rc;
@@ -2124,10 +2225,18 @@ static int sftp_fsync(LIBSSH2_SFTP_HANDLE *handle)
}
rc = sftp_packet_require(sftp, SSH_FXP_STATUS,
- sftp->fsync_request_id, &data, &data_len);
+ sftp->fsync_request_id, &data, &data_len, 9);
if (rc == LIBSSH2_ERROR_EAGAIN) {
return rc;
- } else if (rc) {
+ }
+ else if (rc == LIBSSH2_ERROR_OUT_OF_BOUNDARY) {
+ if (data_len > 0) {
+ LIBSSH2_FREE(session, data);
+ }
+ return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
+ "SFTP fsync packet too short");
+ }
+ else if (rc) {
sftp->fsync_state = libssh2_NB_state_idle;
return _libssh2_error(session, rc,
"Error waiting for FXP EXTENDED REPLY");
@@ -2227,9 +2336,16 @@ static int sftp_fstat(LIBSSH2_SFTP_HANDLE *handle,
rc = sftp_packet_requirev(sftp, 2, fstat_responses,
sftp->fstat_request_id, &data,
- &data_len);
+ &data_len, 9);
if (rc == LIBSSH2_ERROR_EAGAIN)
return rc;
+ else if (rc == LIBSSH2_ERROR_OUT_OF_BOUNDARY) {
+ if (data_len > 0) {
+ LIBSSH2_FREE(session, data);
+ }
+ return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
+ "SFTP fstat packet too short");
+ }
else if (rc) {
sftp->fstat_state = libssh2_NB_state_idle;
return _libssh2_error(session, rc,
@@ -2252,7 +2368,12 @@ static int sftp_fstat(LIBSSH2_SFTP_HANDLE *handle,
}
}
- sftp_bin2attr(attrs, data + 5);
+ if (sftp_bin2attr(attrs, data + 5, data_len - 5) < 0) {
+ LIBSSH2_FREE(session, data);
+ return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
+ "Attributes too short in SFTP fstat");
+ }
+
LIBSSH2_FREE(session, data);
return 0;
@@ -2429,11 +2550,19 @@ sftp_close_handle(LIBSSH2_SFTP_HANDLE *handle)
if (handle->close_state == libssh2_NB_state_sent) {
rc = sftp_packet_require(sftp, SSH_FXP_STATUS,
handle->close_request_id, &data,
- &data_len);
+ &data_len, 9);
if (rc == LIBSSH2_ERROR_EAGAIN) {
return rc;
-
- } else if (rc) {
+ }
+ else if (rc == LIBSSH2_ERROR_OUT_OF_BOUNDARY) {
+ if (data_len > 0) {
+ LIBSSH2_FREE(session, data);
+ }
+ data = NULL;
+ _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
+ "Packet too short in FXP_CLOSE command");
+ }
+ else if (rc) {
_libssh2_error(session, rc,
"Error waiting for status message");
}
@@ -2547,10 +2676,17 @@ static int sftp_unlink(LIBSSH2_SFTP *sftp, const char *filename,
rc = sftp_packet_require(sftp, SSH_FXP_STATUS,
sftp->unlink_request_id, &data,
- &data_len);
+ &data_len, 9);
if (rc == LIBSSH2_ERROR_EAGAIN) {
return rc;
}
+ else if (rc == LIBSSH2_ERROR_OUT_OF_BOUNDARY) {
+ if (data_len > 0) {
+ LIBSSH2_FREE(session, data);
+ }
+ return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
+ "SFTP unlink packet too short");
+ }
else if (rc) {
sftp->unlink_state = libssh2_NB_state_idle;
return _libssh2_error(session, rc,
@@ -2658,10 +2794,18 @@ static int sftp_rename(LIBSSH2_SFTP *sftp, const char *source_filename,
rc = sftp_packet_require(sftp, SSH_FXP_STATUS,
sftp->rename_request_id, &data,
- &data_len);
+ &data_len, 9);
if (rc == LIBSSH2_ERROR_EAGAIN) {
return rc;
- } else if (rc) {
+ }
+ else if (rc == LIBSSH2_ERROR_OUT_OF_BOUNDARY) {
+ if (data_len > 0) {
+ LIBSSH2_FREE(session, data);
+ }
+ return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
+ "SFTP rename packet too short");
+ }
+ else if (rc) {
sftp->rename_state = libssh2_NB_state_idle;
return _libssh2_error(session, rc,
"Error waiting for FXP STATUS");
@@ -2783,11 +2927,19 @@ static int sftp_fstatvfs(LIBSSH2_SFTP_HANDLE *handle, LIBSSH2_SFTP_STATVFS *st)
}
rc = sftp_packet_requirev(sftp, 2, responses, sftp->fstatvfs_request_id,
- &data, &data_len);
+ &data, &data_len, 9);
if (rc == LIBSSH2_ERROR_EAGAIN) {
return rc;
- } else if (rc) {
+ }
+ else if (rc == LIBSSH2_ERROR_OUT_OF_BOUNDARY) {
+ if (data_len > 0) {
+ LIBSSH2_FREE(session, data);
+ }
+ return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
+ "SFTP rename packet too short");
+ }
+ else if (rc) {
sftp->fstatvfs_state = libssh2_NB_state_idle;
return _libssh2_error(session, rc,
"Error waiting for FXP EXTENDED REPLY");
@@ -2910,10 +3062,18 @@ static int sftp_statvfs(LIBSSH2_SFTP *sftp, const char *path,
}
rc = sftp_packet_requirev(sftp, 2, responses, sftp->statvfs_request_id,
- &data, &data_len);
+ &data, &data_len, 9);
if (rc == LIBSSH2_ERROR_EAGAIN) {
return rc;
- } else if (rc) {
+ }
+ else if (rc == LIBSSH2_ERROR_OUT_OF_BOUNDARY) {
+ if (data_len > 0) {
+ LIBSSH2_FREE(session, data);
+ }
+ return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
+ "SFTP fstat packet too short");
+ }
+ else if (rc) {
sftp->statvfs_state = libssh2_NB_state_idle;
return _libssh2_error(session, rc,
"Error waiting for FXP EXTENDED REPLY");
@@ -3040,10 +3200,18 @@ static int sftp_mkdir(LIBSSH2_SFTP *sftp, const char *path,
}
rc = sftp_packet_require(sftp, SSH_FXP_STATUS, sftp->mkdir_request_id,
- &data, &data_len);
+ &data, &data_len, 9);
if (rc == LIBSSH2_ERROR_EAGAIN) {
return rc;
- } else if (rc) {
+ }
+ else if (rc == LIBSSH2_ERROR_OUT_OF_BOUNDARY) {
+ if (data_len > 0) {
+ LIBSSH2_FREE(session, data);
+ }
+ return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
+ "SFTP mkdir packet too short");
+ }
+ else if (rc) {
sftp->mkdir_state = libssh2_NB_state_idle;
return _libssh2_error(session, rc,
"Error waiting for FXP STATUS");
@@ -3134,10 +3302,18 @@ static int sftp_rmdir(LIBSSH2_SFTP *sftp, const char *path,
}
rc = sftp_packet_require(sftp, SSH_FXP_STATUS,
- sftp->rmdir_request_id, &data, &data_len);
+ sftp->rmdir_request_id, &data, &data_len, 9);
if (rc == LIBSSH2_ERROR_EAGAIN) {
return rc;
- } else if (rc) {
+ }
+ else if (rc == LIBSSH2_ERROR_OUT_OF_BOUNDARY) {
+ if (data_len > 0) {
+ LIBSSH2_FREE(session, data);
+ }
+ return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
+ "SFTP rmdir packet too short");
+ }
+ else if (rc) {
sftp->rmdir_state = libssh2_NB_state_idle;
return _libssh2_error(session, rc,
"Error waiting for FXP STATUS");
@@ -3247,9 +3423,16 @@ static int sftp_stat(LIBSSH2_SFTP *sftp, const char *path,
}
rc = sftp_packet_requirev(sftp, 2, stat_responses,
- sftp->stat_request_id, &data, &data_len);
+ sftp->stat_request_id, &data, &data_len, 9);
if (rc == LIBSSH2_ERROR_EAGAIN)
return rc;
+ else if (rc == LIBSSH2_ERROR_OUT_OF_BOUNDARY) {
+ if (data_len > 0) {
+ LIBSSH2_FREE(session, data);
+ }
+ return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
+ "SFTP stat packet too short");
+ }
else if (rc) {
sftp->stat_state = libssh2_NB_state_idle;
return _libssh2_error(session, rc,
@@ -3273,7 +3456,12 @@ static int sftp_stat(LIBSSH2_SFTP *sftp, const char *path,
}
memset(attrs, 0, sizeof(LIBSSH2_SFTP_ATTRIBUTES));
- sftp_bin2attr(attrs, data + 5);
+ if (sftp_bin2attr(attrs, data + 5, data_len - 5) < 0) {
+ LIBSSH2_FREE(session, data);
+ return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
+ "Attributes too short in SFTP fstat");
+ }
+
LIBSSH2_FREE(session, data);
return 0;
@@ -3378,9 +3566,16 @@ static int sftp_symlink(LIBSSH2_SFTP *sftp, const char *path,
retcode = sftp_packet_requirev(sftp, 2, link_responses,
sftp->symlink_request_id, &data,
- &data_len);
+ &data_len, 9);
if (retcode == LIBSSH2_ERROR_EAGAIN)
return retcode;
+ else if (retcode == LIBSSH2_ERROR_OUT_OF_BOUNDARY) {
+ if (data_len > 0) {
+ LIBSSH2_FREE(session, data);
+ }
+ return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
+ "SFTP symlink packet too short");
+ }
else if (retcode) {
sftp->symlink_state = libssh2_NB_state_idle;
return _libssh2_error(session, retcode,
@@ -3410,6 +3605,14 @@ static int sftp_symlink(LIBSSH2_SFTP *sftp, const char *path,
"no name entries");
}
+ if (data_len < 13) {
+ if (data_len > 0) {
+ LIBSSH2_FREE(session, data);
+ }
+ return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
+ "SFTP stat packet too short");
+ }
+
/* this reads a u32 and stores it into a signed 32bit value */
link_len = _libssh2_ntohu32(data + 9);
if (link_len < target_len) {
diff --git a/libs/libssh2/src/transport.c b/libs/libssh2/src/transport.c
index 8725da0950..7317579f36 100644
--- a/libs/libssh2/src/transport.c
+++ b/libs/libssh2/src/transport.c
@@ -438,6 +438,16 @@ int _libssh2_transport_read(LIBSSH2_SESSION * session)
return LIBSSH2_ERROR_DECRYPT;
p->padding_length = block[4];
+ if(p->packet_length < 1) {
+ return LIBSSH2_ERROR_DECRYPT;
+ }
+ else if(p->packet_length > LIBSSH2_PACKET_MAXPAYLOAD) {
+ return LIBSSH2_ERROR_OUT_OF_BOUNDARY;
+ }
+ else if ( p->padding_length > p->packet_length - 1 ) {
+ return LIBSSH2_ERROR_DECRYPT;
+ }
+
/* total_num is the number of bytes following the initial
(5 bytes) packet length and padding length fields */
@@ -471,8 +481,12 @@ int _libssh2_transport_read(LIBSSH2_SESSION * session)
/* copy the data from index 5 to the end of
the blocksize from the temporary buffer to
the start of the decrypted buffer */
- memcpy(p->wptr, &block[5], blocksize - 5);
- p->wptr += blocksize - 5; /* advance write pointer */
+ if (blocksize - 5 <= total_num) {
+ memcpy(p->wptr, &block[5], blocksize - 5);
+ p->wptr += blocksize - 5; /* advance write pointer */
+ } else {
+ return LIBSSH2_ERROR_OUT_OF_BOUNDARY;
+ }
}
/* init the data_num field to the number of bytes of
@@ -546,7 +560,13 @@ int _libssh2_transport_read(LIBSSH2_SESSION * session)
/* if there are bytes to copy that aren't decrypted, simply
copy them as-is to the target buffer */
if (numbytes > 0) {
- memcpy(p->wptr, &p->buf[p->readidx], numbytes);
+
+ if (numbytes <= total_num - (p->wptr - p->payload)) {
+ memcpy(p->wptr, &p->buf[p->readidx], numbytes);
+ }
+ else {
+ return LIBSSH2_ERROR_OUT_OF_BOUNDARY;
+ }
/* advance the read pointer */
p->readidx += numbytes;
diff --git a/libs/libssh2/src/userauth.c b/libs/libssh2/src/userauth.c
index cdfa25e663..ed804629d2 100644
--- a/libs/libssh2/src/userauth.c
+++ b/libs/libssh2/src/userauth.c
@@ -107,7 +107,7 @@ static char *userauth_list(LIBSSH2_SESSION *session, const char *username,
LIBSSH2_FREE(session, session->userauth_list_data);
session->userauth_list_data = NULL;
- if (rc) {
+ if (rc || (session->userauth_list_data_len < 1)) {
_libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
"Unable to send userauth-none request");
session->userauth_list_state = libssh2_NB_state_idle;
@@ -143,8 +143,20 @@ static char *userauth_list(LIBSSH2_SESSION *session, const char *username,
return NULL;
}
- methods_len = _libssh2_ntohu32(session->userauth_list_data + 1);
+ if(session->userauth_list_data_len < 5) {
+ LIBSSH2_FREE(session, session->userauth_list_data);
+ session->userauth_list_data = NULL;
+ _libssh2_error(session, LIBSSH2_ERROR_PROTO,
+ "Unexpected packet size");
+ return NULL;
+ }
+ methods_len = _libssh2_ntohu32(session->userauth_list_data + 1);
+ if(methods_len >= session->userauth_list_data_len - 5) {
+ _libssh2_error(session, LIBSSH2_ERROR_OUT_OF_BOUNDARY,
+ "Unexpected userauth list size");
+ return NULL;
+ }
/* Do note that the memory areas overlap! */
memmove(session->userauth_list_data, session->userauth_list_data + 5,
methods_len);
@@ -285,6 +297,11 @@ userauth_password(LIBSSH2_SESSION *session,
return _libssh2_error(session, rc,
"Waiting for password response");
}
+ else if(session->userauth_pswd_data_len < 1) {
+ session->userauth_pswd_state = libssh2_NB_state_idle;
+ return _libssh2_error(session, LIBSSH2_ERROR_PROTO,
+ "Unexpected packet size");
+ }
if (session->userauth_pswd_data[0] == SSH_MSG_USERAUTH_SUCCESS) {
_libssh2_debug(session, LIBSSH2_TRACE_AUTH,
@@ -312,6 +329,12 @@ userauth_password(LIBSSH2_SESSION *session,
session->userauth_pswd_state = libssh2_NB_state_sent1;
}
+ if(session->userauth_pswd_data_len < 1) {
+ session->userauth_pswd_state = libssh2_NB_state_idle;
+ return _libssh2_error(session, LIBSSH2_ERROR_PROTO,
+ "Unexpected packet size");
+ }
+
if ((session->userauth_pswd_data[0] ==
SSH_MSG_USERAUTH_PASSWD_CHANGEREQ)
|| (session->userauth_pswd_data0 ==
@@ -976,7 +999,7 @@ userauth_hostbased_fromfile(LIBSSH2_SESSION *session,
}
session->userauth_host_state = libssh2_NB_state_idle;
- if (rc) {
+ if (rc || data_len < 1) {
return _libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED,
"Auth failed");
}
@@ -1149,7 +1172,7 @@ _libssh2_userauth_publickey(LIBSSH2_SESSION *session,
NULL, 0);
if (rc == LIBSSH2_ERROR_EAGAIN)
return _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block");
- else if (rc) {
+ else if (rc || (session->userauth_pblc_data_len < 1)) {
LIBSSH2_FREE(session, session->userauth_pblc_packet);
session->userauth_pblc_packet = NULL;
LIBSSH2_FREE(session, session->userauth_pblc_method);
@@ -1332,7 +1355,7 @@ _libssh2_userauth_publickey(LIBSSH2_SESSION *session,
if (rc == LIBSSH2_ERROR_EAGAIN) {
return _libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
"Would block requesting userauth list");
- } else if (rc) {
+ } else if (rc || session->userauth_pblc_data_len < 1) {
session->userauth_pblc_state = libssh2_NB_state_idle;
return _libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED,
"Waiting for publickey USERAUTH response");
@@ -1654,7 +1677,7 @@ userauth_keyboard_interactive(LIBSSH2_SESSION * session,
if (rc == LIBSSH2_ERROR_EAGAIN) {
return _libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
"Would block");
- } else if (rc) {
+ } else if (rc || session->userauth_kybd_data_len < 1) {
session->userauth_kybd_state = libssh2_NB_state_idle;
return _libssh2_error(session,
LIBSSH2_ERROR_AUTHENTICATION_FAILED,
@@ -1734,6 +1757,13 @@ userauth_keyboard_interactive(LIBSSH2_SESSION * session,
/* int num-prompts */
session->userauth_kybd_num_prompts = _libssh2_ntohu32(s);
s += 4;
+ if(session->userauth_kybd_num_prompts &&
+ session->userauth_kybd_num_prompts > 100) {
+ _libssh2_error(session, LIBSSH2_ERROR_OUT_OF_BOUNDARY,
+ "Too many replies for "
+ "keyboard-interactive prompts");
+ goto cleanup;
+ }
if(session->userauth_kybd_num_prompts) {
session->userauth_kybd_prompts =
@@ -1801,8 +1831,17 @@ userauth_keyboard_interactive(LIBSSH2_SESSION * session,
for(i = 0; i < session->userauth_kybd_num_prompts; i++) {
/* string response[1] (ISO-10646 UTF-8) */
- session->userauth_kybd_packet_len +=
- 4 + session->userauth_kybd_responses[i].length;
+ if(session->userauth_kybd_responses[i].length <=
+ (SIZE_MAX - 4 - session->userauth_kybd_packet_len) ) {
+ session->userauth_kybd_packet_len +=
+ 4 + session->userauth_kybd_responses[i].length;
+ }
+ else {
+ _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
+ "Unable to allocate memory for keyboard-"
+ "interactive response packet");
+ goto cleanup;
+ }
}
/* A new userauth_kybd_data area is to be allocated, free the