From 399336eba4fb87eef6358c130c79c756959c3145 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Thu, 17 May 2018 15:21:40 +1000 Subject: [PATCH] Check for invalid last_head entries, avoiding infinite loops. --- lrzip.c | 6 +++++- stream.c | 6 ++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/lrzip.c b/lrzip.c index 7b35b24..0d623ed 100644 --- a/lrzip.c +++ b/lrzip.c @@ -941,7 +941,7 @@ static double percentage(i64 num, i64 den) bool get_fileinfo(rzip_control *control) { - i64 u_len, c_len, last_head, utotal = 0, ctotal = 0, ofs = 25, stream_head[2]; + i64 u_len, c_len, second_last, last_head, utotal = 0, ctotal = 0, ofs = 25, stream_head[2]; i64 expected_size, infile_size, chunk_size = 0, chunk_total = 0; int header_length, stream = 0, chunk = 0; char *tmp, *infilecopy = NULL; @@ -1039,6 +1039,7 @@ next_chunk: while (stream < NUM_STREAMS) { int block = 1; + second_last = 0; if (unlikely(lseek(fd_in, stream_head[stream] + ofs, SEEK_SET) == -1)) fatal_goto(("Failed to seek to header data in get_fileinfo\n"), error); if (unlikely(!get_header_info(control, fd_in, &ctype, &c_len, &u_len, &last_head, chunk_byte))) @@ -1050,6 +1051,9 @@ next_chunk: do { i64 head_off; + if (unlikely(last_head && last_head < second_last)) + failure_goto(("Invalid earlier last_head position, corrupt archive.\n"), error); + second_last = last_head; if (unlikely(last_head + ofs > infile_size)) failure_goto(("Offset greater than archive size, likely corrupted/truncated archive.\n"), error); if (unlikely(head_off = lseek(fd_in, last_head + ofs, SEEK_SET) == -1)) diff --git a/stream.c b/stream.c index f94ea82..816114a 100644 --- a/stream.c +++ b/stream.c @@ -1571,9 +1571,9 @@ static int fill_buffer(rzip_control *control, struct stream_info *sinfo, int str stream_thread_struct *st; uchar c_type, *s_buf; + dealloc(s->buf); if (s->eos) goto out; - dealloc(s->buf); fill_another: if (unlikely(ucthread[s->uthread_no].busy)) failure_return(("Trying to start a busy thread, this shouldn't happen!\n"), -1); @@ -1632,7 +1632,9 @@ fill_another: c_len = le64toh(c_len); u_len = le64toh(u_len); last_head = le64toh(last_head); - if (unlikely(c_len < 1 || u_len < 1 || last_head < 0)) { + /* Check for invalid data and that the last_head is actually moving + * forward correctly. */ + if (unlikely(c_len < 1 || u_len < 1 || last_head < 0 || (last_head && last_head <= s->last_head))) { fatal_return(("Invalid data compressed len %lld uncompressed %lld last_head %lld\n", c_len, u_len, last_head), -1); }