Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
openSUSE:Leap:15.1:Rings:1-MinimalX
libssh2_org
libssh2_org-CVE-2019-3860.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File libssh2_org-CVE-2019-3860.patch of Package libssh2_org
commit ed0d9bd45e4d55cb3ca600c70fa26c6b7bf9bf05 Author: Michael Buckley <michael@panic.com> Date: Wed Dec 5 10:35:19 2018 -0800 Add a required_size parameter to sftp_packet_require et. al. to require callers of these functions to handle packets that are too short. diff --git src/sftp.c src/sftp.c index 5316e7c..fd94d39 100644 --- src/sftp.c +++ src/sftp.c @@ -512,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); @@ -524,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; } @@ -537,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; } } @@ -552,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); @@ -570,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; } } @@ -644,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); @@ -843,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; } @@ -1120,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"); @@ -1156,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; @@ -1488,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; } @@ -1706,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: @@ -1761,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, @@ -1989,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; @@ -2132,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"); @@ -2235,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, @@ -2260,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; @@ -2437,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"); } @@ -2555,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, @@ -2666,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"); @@ -2791,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"); @@ -2918,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"); @@ -3048,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"); @@ -3142,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"); @@ -3255,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, @@ -3281,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; @@ -3386,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, @@ -3418,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) {
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor