mirror of
https://github.com/clearml/dropbear
synced 2025-01-31 02:46:58 +00:00
Fix decompression size check
Dropbear's decompression could erroneously exit with "bad packet, oversized decompressed" for a valid 32768 byte decompressed payload (an off-by-one error). It could be triggered particularly with larger SSH window sizes. This change also simplifies the function by allocating a single 32kB buffer rather than incrementally increasing the size.
This commit is contained in:
parent
86efbae708
commit
f7d306e963
42
packet.c
42
packet.c
@ -430,44 +430,32 @@ static buffer* buf_decompress(const buffer* buf, unsigned int len) {
|
|||||||
z_streamp zstream;
|
z_streamp zstream;
|
||||||
|
|
||||||
zstream = ses.keys->recv.zstream;
|
zstream = ses.keys->recv.zstream;
|
||||||
ret = buf_new(len);
|
/* We use RECV_MAX_PAYLOAD_LEN+1 here to ensure that
|
||||||
|
we can detect an oversized payload after inflate() */
|
||||||
|
ret = buf_new(RECV_MAX_PAYLOAD_LEN+1);
|
||||||
|
|
||||||
zstream->avail_in = len;
|
zstream->avail_in = len;
|
||||||
zstream->next_in = buf_getptr(buf, len);
|
zstream->next_in = buf_getptr(buf, len);
|
||||||
|
zstream->avail_out = ret->size;
|
||||||
/* decompress the payload, incrementally resizing the output buffer */
|
zstream->next_out = ret->data;
|
||||||
while (1) {
|
|
||||||
|
|
||||||
zstream->avail_out = ret->size - ret->pos;
|
|
||||||
zstream->next_out = buf_getwriteptr(ret, zstream->avail_out);
|
|
||||||
|
|
||||||
result = inflate(zstream, Z_SYNC_FLUSH);
|
result = inflate(zstream, Z_SYNC_FLUSH);
|
||||||
|
if (result != Z_OK) {
|
||||||
buf_setlen(ret, ret->size - zstream->avail_out);
|
|
||||||
buf_setpos(ret, ret->len);
|
|
||||||
|
|
||||||
if (result != Z_BUF_ERROR && result != Z_OK) {
|
|
||||||
dropbear_exit("zlib error");
|
dropbear_exit("zlib error");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (zstream->avail_in == 0 &&
|
buf_setlen(ret, ret->size - zstream->avail_out);
|
||||||
(zstream->avail_out != 0 || result == Z_BUF_ERROR)) {
|
|
||||||
/* we can only exit if avail_out hasn't all been used,
|
|
||||||
* and there's no remaining input */
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (zstream->avail_out == 0) {
|
if (zstream->avail_in > 0 || ret->len > RECV_MAX_PAYLOAD_LEN) {
|
||||||
int new_size = 0;
|
/* The remote side sent larger than a payload size
|
||||||
if (ret->size >= RECV_MAX_PAYLOAD_LEN) {
|
* of uncompressed data.
|
||||||
/* Already been increased as large as it can go,
|
*/
|
||||||
* yet didn't finish up the decompression */
|
|
||||||
dropbear_exit("bad packet, oversized decompressed");
|
dropbear_exit("bad packet, oversized decompressed");
|
||||||
}
|
}
|
||||||
new_size = MIN(RECV_MAX_PAYLOAD_LEN, ret->size + ZLIB_DECOMPRESS_INCR);
|
|
||||||
ret = buf_resize(ret, new_size);
|
/* Success. All input was consumed and avail_out > 0 */
|
||||||
}
|
return ret;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user