Additional length checks to prevent out-of-bounds reads and writes in _libssh2_packet_add().
@@ -779,8 +779,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,
@@ -788,6 +788,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)) {
@@ -796,7 +797,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,
@@ -809,13 +810,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"));
@@ -831,9 +833,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,
