Skip to content

Commit

Permalink
More 1.8.0 security fixes (libssh2#316)
Browse files Browse the repository at this point in the history
* Defend against possible integer overflows in comp_method_zlib_decomp.

* Defend against writing beyond the end of the payload in _libssh2_transport_read().

* Sanitize padding_length - _libssh2_transport_read(). https://libssh2.org/CVE-2019-3861.html

This prevents an underflow resulting in a potential out-of-bounds read if a server sends a too-large padding_length, possibly with malicious intent.

* Prevent zero-byte allocation in sftp_packet_read() which could lead to an out-of-bounds read. https://libssh2.org/CVE-2019-3858.html

* Check the length of data passed to sftp_packet_add() to prevent out-of-bounds reads.

* Add a required_size parameter to sftp_packet_require et. al. to require callers of these functions to handle packets that are too short. https://libssh2.org/CVE-2019-3860.html

* Additional length checks to prevent out-of-bounds reads and writes in _libssh2_packet_add(). https://libssh2.org/CVE-2019-3862.html
  • Loading branch information
MichaelBuckley authored and willco007 committed Mar 14, 2019
1 parent c286e4d commit f15b1e2
Show file tree
Hide file tree
Showing 4 changed files with 292 additions and 68 deletions.
9 changes: 7 additions & 2 deletions src/comp.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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");
Expand Down
14 changes: 8 additions & 6 deletions src/packet.c
Original file line number Diff line number Diff line change
Expand Up @@ -775,15 +775,16 @@ _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,
"Channel %d received request type %.*s (wr %X)",
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)) {

Expand All @@ -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,
Expand All @@ -805,13 +806,14 @@ _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"));
Expand All @@ -827,9 +829,9 @@ _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data,
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,
Expand Down
Loading

0 comments on commit f15b1e2

Please sign in to comment.