1dcf5b9
From 7f17c791dcfd8c0416e2cd2485b19410e47ef126 Mon Sep 17 00:00:00 2001
1dcf5b9
From: Tim Kientzle <kientzle@acm.org>
1dcf5b9
Date: Sun, 18 Sep 2016 18:14:58 -0700
1dcf5b9
Subject: [PATCH] Issue 761:  Heap overflow reading corrupted 7Zip files
1dcf5b9
1dcf5b9
The sample file that demonstrated this had multiple 'EmptyStream'
1dcf5b9
attributes.  The first one ended up being used to calculate
1dcf5b9
certain statistics, then was overwritten by the second which
1dcf5b9
was incompatible with those statistics.
1dcf5b9
1dcf5b9
The fix here is to reject any header with multiple EmptyStream
1dcf5b9
attributes.  While here, also reject headers with multiple
1dcf5b9
EmptyFile, AntiFile, Name, or Attributes markers.
1dcf5b9
---
1dcf5b9
 libarchive/archive_read_support_format_7zip.c | 10 ++++++++++
1dcf5b9
 1 file changed, 10 insertions(+)
1dcf5b9
1dcf5b9
diff --git a/libarchive/archive_read_support_format_7zip.c b/libarchive/archive_read_support_format_7zip.c
1dcf5b9
index 1dfe52b..c0a536c 100644
1dcf5b9
--- a/libarchive/archive_read_support_format_7zip.c
1dcf5b9
+++ b/libarchive/archive_read_support_format_7zip.c
1dcf5b9
@@ -2431,6 +2431,8 @@ read_Header(struct archive_read *a, struct _7z_header_info *h,
1dcf5b9
 
1dcf5b9
 		switch (type) {
1dcf5b9
 		case kEmptyStream:
1dcf5b9
+			if (h->emptyStreamBools != NULL)
1dcf5b9
+				return (-1);
1dcf5b9
 			h->emptyStreamBools = calloc((size_t)zip->numFiles,
1dcf5b9
 			    sizeof(*h->emptyStreamBools));
1dcf5b9
 			if (h->emptyStreamBools == NULL)
1dcf5b9
@@ -2451,6 +2453,8 @@ read_Header(struct archive_read *a, struct _7z_header_info *h,
1dcf5b9
 					return (-1);
1dcf5b9
 				break;
1dcf5b9
 			}
1dcf5b9
+			if (h->emptyFileBools != NULL)
1dcf5b9
+				return (-1);
1dcf5b9
 			h->emptyFileBools = calloc(empty_streams,
1dcf5b9
 			    sizeof(*h->emptyFileBools));
1dcf5b9
 			if (h->emptyFileBools == NULL)
1dcf5b9
@@ -2465,6 +2469,8 @@ read_Header(struct archive_read *a, struct _7z_header_info *h,
1dcf5b9
 					return (-1);
1dcf5b9
 				break;
1dcf5b9
 			}
1dcf5b9
+			if (h->antiBools != NULL)
1dcf5b9
+				return (-1);
1dcf5b9
 			h->antiBools = calloc(empty_streams,
1dcf5b9
 			    sizeof(*h->antiBools));
1dcf5b9
 			if (h->antiBools == NULL)
1dcf5b9
@@ -2491,6 +2497,8 @@ read_Header(struct archive_read *a, struct _7z_header_info *h,
1dcf5b9
 			if ((ll & 1) || ll < zip->numFiles * 4)
1dcf5b9
 				return (-1);
1dcf5b9
 
1dcf5b9
+			if (zip->entry_names != NULL)
1dcf5b9
+				return (-1);
1dcf5b9
 			zip->entry_names = malloc(ll);
1dcf5b9
 			if (zip->entry_names == NULL)
1dcf5b9
 				return (-1);
1dcf5b9
@@ -2543,6 +2551,8 @@ read_Header(struct archive_read *a, struct _7z_header_info *h,
1dcf5b9
 			if ((p = header_bytes(a, 2)) == NULL)
1dcf5b9
 				return (-1);
1dcf5b9
 			allAreDefined = *p;
1dcf5b9
+			if (h->attrBools != NULL)
1dcf5b9
+				return (-1);
1dcf5b9
 			h->attrBools = calloc((size_t)zip->numFiles,
1dcf5b9
 			    sizeof(*h->attrBools));
1dcf5b9
 			if (h->attrBools == NULL)