]> git.ipfire.org Git - thirdparty/libarchive.git/commitdiff
RAR5 reader: reject files that declare invalid header flags 1326/head
authorGrzegorz Antoniak <ga@anadoxin.org>
Sun, 2 Feb 2020 07:04:41 +0000 (08:04 +0100)
committerGrzegorz Antoniak <ga@anadoxin.org>
Sun, 2 Feb 2020 07:04:41 +0000 (08:04 +0100)
One of the fields in RAR5's base block structure is the size of the
header. Some invalid files declare a 0 header size setting, which can
confuse the unpacker. Minimum header size for RAR5 base blocks is 7
bytes (4 bytes for CRC, and 3 bytes for the rest), so block size of 0
bytes should be rejected at header parsing stage.

The fix adds an error condition if header size of 0 bytes is detected.
In this case, the unpacker will not attempt to unpack the file, as the
header is corrupted.

The commit also adds OSSFuzz #20459 sample to test further regressions
in this area.

Makefile.am
libarchive/archive_read_support_format_rar5.c
libarchive/test/test_read_format_rar5.c
libarchive/test/test_read_format_rar5_block_size_is_too_small.rar.uu [new file with mode: 0644]

index 06c26442087fb0dbeff14384b3a39e3059b0c495..c65e243712a4bdbfb61c940b96f09988ba8f2057 100644 (file)
@@ -877,6 +877,7 @@ libarchive_test_EXTRA_DIST=\
        libarchive/test/test_read_format_rar5_win32.rar.uu \
        libarchive/test/test_read_format_rar5_arm_filter_on_window_boundary.rar.uu \
        libarchive/test/test_read_format_rar5_different_winsize_on_merge.rar.uu \
+       libarchive/test/test_read_format_rar5_block_size_is_too_small.rar.uu \
        libarchive/test/test_read_format_raw.bufr.uu \
        libarchive/test/test_read_format_raw.data.gz.uu \
        libarchive/test/test_read_format_raw.data.Z.uu \
index ff1d6f812f4706a52e8b8d7c6b1c2d50b9fe7005..f7c163eb03ef4718f1e51e42e0185b1efec980d6 100644 (file)
@@ -2085,6 +2085,8 @@ static int scan_for_signature(struct archive_read* a);
 static int process_base_block(struct archive_read* a,
     struct archive_entry* entry)
 {
+       const size_t SMALLEST_RAR5_BLOCK_SIZE = 3;
+
        struct rar5* rar = get_context(a);
        uint32_t hdr_crc, computed_crc;
        size_t raw_hdr_size = 0, hdr_size_len, hdr_size;
@@ -2114,15 +2116,26 @@ static int process_base_block(struct archive_read* a,
                return ARCHIVE_EOF;
        }
 
+       hdr_size = raw_hdr_size + hdr_size_len;
+
        /* Sanity check, maximum header size for RAR5 is 2MB. */
-       if(raw_hdr_size > (2 * 1024 * 1024)) {
+       if(hdr_size > (2 * 1024 * 1024)) {
                archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
                    "Base block header is too large");
 
                return ARCHIVE_FATAL;
        }
 
-       hdr_size = raw_hdr_size + hdr_size_len;
+       /* Additional sanity checks to weed out invalid files. */
+       if(raw_hdr_size == 0 || hdr_size_len == 0 ||
+               hdr_size < SMALLEST_RAR5_BLOCK_SIZE)
+       {
+               archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+                   "Too small block encountered (%ld bytes)",
+                   raw_hdr_size);
+
+               return ARCHIVE_FATAL;
+       }
 
        /* Read the whole header data into memory, maximum memory use here is
         * 2MB. */
index bb94d4e34e25a123ead7363df84bb11d81941747..f91521e72f820209c432d2df1b84de87f4d96f32 100644 (file)
@@ -1256,3 +1256,18 @@ DEFINE_TEST(test_read_format_rar5_different_winsize_on_merge)
 
        EPILOGUE();
 }
+
+DEFINE_TEST(test_read_format_rar5_block_size_is_too_small)
+{
+       char buf[4096];
+       PROLOGUE("test_read_format_rar5_block_size_is_too_small.rar");
+
+       /* This file is damaged, so those functions should return failure.
+        * Additionally, SIGSEGV shouldn't be raised during execution
+        * of those functions. */
+
+       assertA(archive_read_next_header(a, &ae) != ARCHIVE_OK);
+       assertA(archive_read_data(a, buf, sizeof(buf)) <= 0);
+
+       EPILOGUE();
+}
diff --git a/libarchive/test/test_read_format_rar5_block_size_is_too_small.rar.uu b/libarchive/test/test_read_format_rar5_block_size_is_too_small.rar.uu
new file mode 100644 (file)
index 0000000..5cad219
--- /dev/null
@@ -0,0 +1,8 @@
+begin 644 test_read_format_rar5_block_size_is_too_small.rar
+M4F%R(1H'`0"-[P+2``+'(!P,("`@N`,!`B`@("`@("`@("`@("`@("#_("`@
+M("`@("`@("`@((:Q;2!4-'-^4B`!((WO`M(``O\@$/\@-R`@("`@("`@("`@
+M``X@("`@("`@____("`@("`@(/\@("`@("`@("`@("#_(+6U,2"UM;6UM[CU
+M)B`@*(0G(`!.`#D\3R``(/__(,+_````-0#_($&%*/HE=C+N`"```"```"`D
+J`)$#("#_("#__P`@__\@_R#_("`@("`@("#_("#__R`@(/__("#__R`"
+`
+end