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

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