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

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