Blame SOURCES/libarchive-3.3.2-CVE-2018-1000878.patch

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