ab85643
From 22700942fec895b2d3e5ed6741756deb8666eaae Mon Sep 17 00:00:00 2001
ab85643
From: Daniel Axtens <dja@axtens.net>
ab85643
Date: Tue, 4 Dec 2018 00:55:22 +1100
ab85643
Subject: [PATCH] rar: file split across multi-part archives must match
ab85643
ab85643
Fuzzing uncovered some UAF and memory overrun bugs where a file in a
ab85643
single file archive reported that it was split across multiple
ab85643
volumes. This was caused by ppmd7 operations calling
ab85643
rar_br_fillup. This would invoke rar_read_ahead, which would in some
ab85643
situations invoke archive_read_format_rar_read_header.  That would
ab85643
check the new file name against the old file name, and if they didn't
ab85643
match up it would free the ppmd7 buffer and allocate a new
ab85643
one. However, because the ppmd7 decoder wasn't actually done with the
ab85643
buffer, it would continue to used the freed buffer. Both reads and
ab85643
writes to the freed region can be observed.
ab85643
ab85643
This is quite tricky to solve: once the buffer has been freed it is
ab85643
too late, as the ppmd7 decoder functions almost universally assume
ab85643
success - there's no way for ppmd_read to signal error, nor are there
ab85643
good ways for functions like Range_Normalise to propagate them. So we
ab85643
can't detect after the fact that we're in an invalid state - e.g. by
ab85643
checking rar->cursor, we have to prevent ourselves from ever ending up
ab85643
there. So, when we are in the dangerous part or rar_read_ahead that
ab85643
assumes a valid split, we set a flag force read_header to either go
ab85643
down the path for split files or bail. This means that the ppmd7
ab85643
decoder keeps a valid buffer and just runs out of data.
ab85643
ab85643
Found with a combination of AFL, afl-rb and qsym.
ab85643
---
ab85643
 libarchive/archive_read_support_format_rar.c | 9 +++++++++
ab85643
 1 file changed, 9 insertions(+)
ab85643
ab85643
diff --git a/libarchive/archive_read_support_format_rar.c b/libarchive/archive_read_support_format_rar.c
ab85643
index 6f419c27..a8cc5c94 100644
ab85643
--- a/libarchive/archive_read_support_format_rar.c
ab85643
+++ b/libarchive/archive_read_support_format_rar.c
ab85643
@@ -258,6 +258,7 @@ struct rar
ab85643
   struct data_block_offsets *dbo;
ab85643
   unsigned int cursor;
ab85643
   unsigned int nodes;
ab85643
+  char filename_must_match;
ab85643
 
ab85643
   /* LZSS members */
ab85643
   struct huffman_code maincode;
ab85643
@@ -1560,6 +1561,12 @@ read_header(struct archive_read *a, struct archive_entry *entry,
ab85643
     }
ab85643
     return ret;
ab85643
   }
ab85643
+  else if (rar->filename_must_match)
ab85643
+  {
ab85643
+    archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
ab85643
+      "Mismatch of file parts split across multi-volume archive");
ab85643
+    return (ARCHIVE_FATAL);
ab85643
+  }
ab85643
 
ab85643
   rar->filename_save = (char*)realloc(rar->filename_save,
ab85643
                                       filename_size + 1);
ab85643
@@ -2933,12 +2940,14 @@ rar_read_ahead(struct archive_read *a, size_t min, ssize_t *avail)
ab85643
     else if (*avail == 0 && rar->main_flags & MHD_VOLUME &&
ab85643
       rar->file_flags & FHD_SPLIT_AFTER)
ab85643
     {
ab85643
+      rar->filename_must_match = 1;
ab85643
       ret = archive_read_format_rar_read_header(a, a->entry);
ab85643
       if (ret == (ARCHIVE_EOF))
ab85643
       {
ab85643
         rar->has_endarc_header = 1;
ab85643
         ret = archive_read_format_rar_read_header(a, a->entry);
ab85643
       }
ab85643
+      rar->filename_must_match = 0;
ab85643
       if (ret != (ARCHIVE_OK))
ab85643
         return NULL;
ab85643
       return rar_read_ahead(a, min, avail);
ab85643
-- 
ab85643
2.17.1
ab85643