From: Grzegorz Antoniak Date: Thu, 28 Feb 2019 06:26:25 +0000 (+0100) Subject: ZIP reader: fixed an unlimited loop in BZIP2 decompressor. X-Git-Tag: v3.4.0~113^2 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=refs%2Fpull%2F1153%2Fhead;p=thirdparty%2Flibarchive.git ZIP reader: fixed an unlimited loop in BZIP2 decompressor. The hang was triggered on invalid zipx files that declare more data than there actually is in the file. This case was found by fuzzing the zipx file. --- diff --git a/libarchive/archive_read_support_format_zip.c b/libarchive/archive_read_support_format_zip.c index 723ea1e04..677c43709 100644 --- a/libarchive/archive_read_support_format_zip.c +++ b/libarchive/archive_read_support_format_zip.c @@ -1984,6 +1984,15 @@ zip_read_data_zipx_bzip2(struct archive_read *a, const void **buff, } in_bytes = zipmin(zip->entry_bytes_remaining, bytes_avail); + if(in_bytes < 1) { + /* libbz2 doesn't complain when caller feeds avail_in == 0. It will + * actually return success in this case, which is undesirable. This is + * why we need to make this check manually. */ + + archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, + "Truncated bzip2 file body"); + return (ARCHIVE_FATAL); + } /* Setup buffer boundaries. */ zip->bzstream.next_in = (char*)(uintptr_t) compressed_buff; diff --git a/libarchive/test/test_read_format_zip.c b/libarchive/test/test_read_format_zip.c index bc04933c3..14c5ada81 100644 --- a/libarchive/test/test_read_format_zip.c +++ b/libarchive/test/test_read_format_zip.c @@ -769,6 +769,28 @@ DEFINE_TEST(test_read_format_zip_ppmd8_crash_1) extract_reference_file(refname); + assert((a = archive_read_new()) != NULL); + assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_zip(a)); + assertEqualIntA(a, ARCHIVE_OK, archive_read_open_filename(a, refname, 100)); + assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); + + /* This file shouldn't be properly decompressed, because it's invalid. + * However, unpacker should return an error during unpacking. Without the + * proper fix, the unpacker was entering an unlimited loop. */ + assertEqualIntA(a, ARCHIVE_FATAL, archive_read_data(a, buf, 1)); + assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a)); + assertEqualIntA(a, ARCHIVE_OK, archive_read_free(a)); +} + +DEFINE_TEST(test_read_format_zip_bz2_hang_on_invalid) +{ + const char *refname = "test_read_format_zip_bz2_hang.zip"; + struct archive *a; + struct archive_entry *ae; + char buf[8]; + + extract_reference_file(refname); + assert((a = archive_read_new()) != NULL); assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_zip(a)); assertEqualIntA(a, ARCHIVE_OK, archive_read_open_filename(a, refname, 37)); diff --git a/libarchive/test/test_read_format_zip_bz2_hang.zip.uu b/libarchive/test/test_read_format_zip_bz2_hang.zip.uu new file mode 100644 index 000000000..5193a77ae --- /dev/null +++ b/libarchive/test/test_read_format_zip_bz2_hang.zip.uu @@ -0,0 +1,5 @@ +begin 644 test_read_format_zip_bz2_hang.zip +M4$L#!)LP,#`,,#`P,#`P,#`P,#`P,#`P,#`$`!P`,#`P,#`P"0`P,#`P,#`P +1,#!U>`L`8(0P,#`P,#`P,#`` +` +end