CVE-2016-1541: Improper Input Validation (CWE-20)
value: Heap-based buffer overflow in the zip_read_mac_metadata function in archive_read_support_format_zip.c in libarchive before 3.2.0 allows remote attackers to execute arbitrary code via crafted entry-size values in a ZIP archive.
CWE description: The product receives input or data, but it does
        not validate or incorrectly validates that the input has the
        properties that are required to process the data safely and
        correctly.
CVSS v3 base score: 8.8
Published: 2016-05-07T10:59Z
Repository: https://github.com/libarchive/libarchive
Language: C
Files changed: libarchive/archive_read_support_format_zip.c
Commit date: 2016-04-24 17:13:45 -0700
Commit message: Issue #656:  Fix CVE-2016-1541, VU#862384

When reading OS X metadata entries in Zip archives that were stored
without compression, libarchive would use the uncompressed entry size
to allocate a buffer but would use the compressed entry size to limit
the amount of data copied into that buffer.  Since the compressed
and uncompressed sizes are provided by data in the archive itself,
an attacker could manipulate these values to write data beyond
the end of the allocated buffer.

This fix provides three new checks to guard against such
manipulation and to make libarchive generally more robust when
handling this type of entry:
 1. If an OS X metadata entry is stored without compression,
    abort the entire archive if the compressed and uncompressed
    data sizes do not match.
 2. When sanity-checking the size of an OS X metadata entry,
    abort this entry if either the compressed or uncompressed
    size is larger than 4MB.
 3. When copying data into the allocated buffer, check the copy
    size against both the compressed entry size and uncompressed
    entry size.

Diff: diff --git a/libarchive/archive_read_support_format_zip.c b/libarchive/archive_read_support_format_zip.c
index 0f8262c62..0a0be96b5 100644
--- a/libarchive/archive_read_support_format_zip.c
+++ b/libarchive/archive_read_support_format_zip.c
@@ -2776,10 +2776,15 @@ zip_read_mac_metadata(struct archive_read *a, struct archive_entry *entry,
 	ssize_t hsize;
 	int ret = ARCHIVE_OK, eof;
 
 	switch(rsrc->compression) {
 	case 0:  /* No compression. */
+		if (rsrc->uncompressed_size != rsrc->compressed_size) {
+			archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+			    "Malformed OS X metadata entry: inconsistent size");
+			return (ARCHIVE_FATAL);
+		}
 #ifdef HAVE_ZLIB_H
 	case 8: /* Deflate compression. */
 #endif
 		break;
 	default: /* Unsupported compression. */
@@ -2796,10 +2801,16 @@ zip_read_mac_metadata(struct archive_read *a, struct archive_entry *entry,
 		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 		    "Mac metadata is too large: %jd > 4M bytes",
 		    (intmax_t)rsrc->uncompressed_size);
 		return (ARCHIVE_WARN);
 	}
+	if (rsrc->compressed_size > (4 * 1024 * 1024)) {
+		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+		    "Mac metadata is too large: %jd > 4M bytes",
+		    (intmax_t)rsrc->compressed_size);
+		return (ARCHIVE_WARN);
+	}
 
 	metadata = malloc((size_t)rsrc->uncompressed_size);
 	if (metadata == NULL) {
 		archive_set_error(&a->archive, ENOMEM,
 		    "Can't allocate memory for Mac metadata");
@@ -2834,10 +2845,12 @@ zip_read_mac_metadata(struct archive_read *a, struct archive_entry *entry,
 		}
 		if ((size_t)bytes_avail > remaining_bytes)
 			bytes_avail = remaining_bytes;
 		switch(rsrc->compression) {
 		case 0:  /* No compression. */
+			if ((size_t)bytes_avail > metadata_bytes)
+				bytes_avail = metadata_bytes;
 			memcpy(mp, p, bytes_avail);
 			bytes_used = (size_t)bytes_avail;
 			metadata_bytes -= bytes_used;
 			mp += bytes_used;
 			if (metadata_bytes == 0)

Fixed code: 		if (rsrc->uncompressed_size != rsrc->compressed_size) {
			archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
			    "Malformed OS X metadata entry: inconsistent size");
			return (ARCHIVE_FATAL);
		}
	if (rsrc->compressed_size > (4 * 1024 * 1024)) {
		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
		    "Mac metadata is too large: %jd > 4M bytes",
		    (intmax_t)rsrc->compressed_size);
		return (ARCHIVE_WARN);
	}
			if ((size_t)bytes_avail > metadata_bytes)
				bytes_avail = metadata_bytes;