Check for invalid last_head entries, avoiding infinite loops.

This commit is contained in:
Con Kolivas 2018-05-17 15:21:40 +10:00
parent 257186a865
commit 399336eba4
2 changed files with 9 additions and 3 deletions

View file

@ -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))

View file

@ -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);
}