| From dedcbd106f8e52d5586b0205bc7677e4c9868f9c Mon Sep 17 00:00:00 2001 |
| From: Will Cosgrove <will@panic.com> |
| Date: Fri, 30 Aug 2019 09:57:38 -0700 |
| Subject: [PATCH] packet.c: improve message parsing (#402) |
| |
| * packet.c: improve parsing of packets |
| |
| file: packet.c |
| |
| notes: |
| Use _libssh2_get_string API in SSH_MSG_DEBUG/SSH_MSG_DISCONNECT. Additional uint32 bounds check in SSH_MSG_GLOBAL_REQUEST. |
| |
| Upstream-Status: Backport |
| CVE: CVE-2019-17498 |
| Signed-off-by: Li Zhou <li.zhou@windriver.com> |
| --- |
| src/packet.c | 68 ++++++++++++++++++++++------------------------------ |
| 1 file changed, 29 insertions(+), 39 deletions(-) |
| |
| diff --git a/src/packet.c b/src/packet.c |
| index 38ab629..2e01bfc 100644 |
| --- a/src/packet.c |
| +++ b/src/packet.c |
| @@ -419,8 +419,8 @@ _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data, |
| size_t datalen, int macstate) |
| { |
| int rc = 0; |
| - char *message = NULL; |
| - char *language = NULL; |
| + unsigned char *message = NULL; |
| + unsigned char *language = NULL; |
| size_t message_len = 0; |
| size_t language_len = 0; |
| LIBSSH2_CHANNEL *channelp = NULL; |
| @@ -472,33 +472,23 @@ _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data, |
| |
| case SSH_MSG_DISCONNECT: |
| if(datalen >= 5) { |
| - size_t reason = _libssh2_ntohu32(data + 1); |
| + uint32_t reason = 0; |
| + struct string_buf buf; |
| + buf.data = (unsigned char *)data; |
| + buf.dataptr = buf.data; |
| + buf.len = datalen; |
| + buf.dataptr++; /* advance past type */ |
| |
| - if(datalen >= 9) { |
| - message_len = _libssh2_ntohu32(data + 5); |
| + _libssh2_get_u32(&buf, &reason); |
| + _libssh2_get_string(&buf, &message, &message_len); |
| + _libssh2_get_string(&buf, &language, &language_len); |
| |
| - if(message_len < datalen-13) { |
| - /* 9 = packet_type(1) + reason(4) + message_len(4) */ |
| - message = (char *) data + 9; |
| - |
| - language_len = |
| - _libssh2_ntohu32(data + 9 + message_len); |
| - language = (char *) data + 9 + message_len + 4; |
| - |
| - if(language_len > (datalen-13-message_len)) { |
| - /* bad input, clear info */ |
| - language = message = NULL; |
| - language_len = message_len = 0; |
| - } |
| - } |
| - else |
| - /* bad size, clear it */ |
| - message_len = 0; |
| - } |
| if(session->ssh_msg_disconnect) { |
| - LIBSSH2_DISCONNECT(session, reason, message, |
| - message_len, language, language_len); |
| + LIBSSH2_DISCONNECT(session, reason, (const char *)message, |
| + message_len, (const char *)language, |
| + language_len); |
| } |
| + |
| _libssh2_debug(session, LIBSSH2_TRACE_TRANS, |
| "Disconnect(%d): %s(%s)", reason, |
| message, language); |
| @@ -539,24 +529,24 @@ _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data, |
| int always_display = data[1]; |
| |
| if(datalen >= 6) { |
| - message_len = _libssh2_ntohu32(data + 2); |
| - |
| - if(message_len <= (datalen - 10)) { |
| - /* 6 = packet_type(1) + display(1) + message_len(4) */ |
| - message = (char *) data + 6; |
| - language_len = _libssh2_ntohu32(data + 6 + |
| - message_len); |
| - |
| - if(language_len <= (datalen - 10 - message_len)) |
| - language = (char *) data + 10 + message_len; |
| - } |
| + struct string_buf buf; |
| + buf.data = (unsigned char *)data; |
| + buf.dataptr = buf.data; |
| + buf.len = datalen; |
| + buf.dataptr += 2; /* advance past type & always display */ |
| + |
| + _libssh2_get_string(&buf, &message, &message_len); |
| + _libssh2_get_string(&buf, &language, &language_len); |
| } |
| |
| if(session->ssh_msg_debug) { |
| - LIBSSH2_DEBUG(session, always_display, message, |
| - message_len, language, language_len); |
| + LIBSSH2_DEBUG(session, always_display, |
| + (const char *)message, |
| + message_len, (const char *)language, |
| + language_len); |
| } |
| } |
| + |
| /* |
| * _libssh2_debug will actually truncate this for us so |
| * that it's not an inordinate about of data |
| @@ -579,7 +569,7 @@ _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data, |
| uint32_t len = 0; |
| unsigned char want_reply = 0; |
| len = _libssh2_ntohu32(data + 1); |
| - if(datalen >= (6 + len)) { |
| + if((len <= (UINT_MAX - 6)) && (datalen >= (6 + len))) { |
| want_reply = data[5 + len]; |
| _libssh2_debug(session, |
| LIBSSH2_TRACE_CONN, |
| -- |
| 2.17.1 |
| |