From cd2eeef5f7093c144015f3a43427924eb258e24d Mon Sep 17 00:00:00 2001 From: Kalle Olavi Niemitalo Date: Sat, 15 Aug 2009 13:44:03 +0300 Subject: [PATCH] bug 1083: Fix infinite loop in decompress_data decompress_data() supposed that read_encoded() would return a positive number if it decompressed something, 0 if no data is available yet but may be later, or -1 if no more data will be available. However, several backends actually returned 0 if they had seen an EOF marker or an error in the stream, causing decompress_data() to keep calling them. Make them return -1 in this situation. --- NEWS | 2 ++ src/encoding/bzip2.c | 2 +- src/encoding/deflate.c | 2 +- src/encoding/encoding.c | 23 +++++++++++++++++++---- src/encoding/lzma.c | 2 +- 5 files changed, 24 insertions(+), 7 deletions(-) diff --git a/NEWS b/NEWS index a3eb8815..1b27fcda 100644 --- a/NEWS +++ b/NEWS @@ -18,6 +18,8 @@ Bugs that should be removed from NEWS before the 0.12.0 release: ELinks could crash; as a precaution, don't allow other actions either. ELinks 0.12pre1 was the first release that supported ``elinks.action''. +* critical bug 1083: Avoid an infinite loop when trying to decompress + malformed data. Caused by the bug 1068 fix in ELinks 0.12pre3. ELinks 0.12pre5: ---------------- diff --git a/src/encoding/bzip2.c b/src/encoding/bzip2.c index 8e7139a6..22196fb8 100644 --- a/src/encoding/bzip2.c +++ b/src/encoding/bzip2.c @@ -88,7 +88,7 @@ bzip2_read(struct stream_encoded *stream, unsigned char *buf, int len) assert(len > 0); - if (data->last_read) return 0; + if (data->last_read) return -1; data->fbz_stream.avail_out = len; data->fbz_stream.next_out = buf; diff --git a/src/encoding/deflate.c b/src/encoding/deflate.c index 2ed742a1..9031409b 100644 --- a/src/encoding/deflate.c +++ b/src/encoding/deflate.c @@ -99,7 +99,7 @@ deflate_read(struct stream_encoded *stream, unsigned char *buf, int len) assert(len > 0); - if (data->last_read) return 0; + if (data->last_read) return -1; data->deflate_stream.avail_out = len; data->deflate_stream.next_out = buf; diff --git a/src/encoding/encoding.c b/src/encoding/encoding.c index d019dab3..2c6e7da6 100644 --- a/src/encoding/encoding.c +++ b/src/encoding/encoding.c @@ -48,7 +48,15 @@ dummy_open(struct stream_encoded *stream, int fd) static int dummy_read(struct stream_encoded *stream, unsigned char *data, int len) { - return safe_read(((struct dummy_enc_data *) stream->data)->fd, data, len); + struct dummy_enc_data *const enc = stream->data; + int got = safe_read(enc->fd, data, len); + + if (got > 0) + return got; + else if (got == -1 && errno == EAGAIN) + return 0; + else + return -1; } static unsigned char * @@ -118,9 +126,16 @@ open_encoded(int fd, enum stream_encoding encoding) return NULL; } -/* Read available data from stream and decode them. Note that when data change - * their size during decoding, 'len' indicates desired size of _returned_ data, - * not desired size of data read from stream. */ +/** Read available data from stream and decode them. Note that when + * data change their size during decoding, @a len indicates desired + * size of _returned_ data, not desired size of data read from + * stream. + * + * @return the number of bytes written to the @a data array if + * something was decoded; 0 if no data is available yet but some may + * become available later; or -1 if there will be no further data, + * either because an error occurred or because an end-of-stream mark + * was reached. */ int read_encoded(struct stream_encoded *stream, unsigned char *data, int len) { diff --git a/src/encoding/lzma.c b/src/encoding/lzma.c index 0cbbaf32..70259626 100644 --- a/src/encoding/lzma.c +++ b/src/encoding/lzma.c @@ -65,7 +65,7 @@ lzma_read(struct stream_encoded *stream, unsigned char *buf, int len) assert(len > 0); - if (data->last_read) return 0; + if (data->last_read) return -1; data->flzma_stream.avail_out = len; data->flzma_stream.next_out = buf;