Skip to content

Commit d0331e8

Browse files
committed
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.
1 parent 1185535 commit d0331e8

File tree

1 file changed

+13
-0
lines changed

1 file changed

+13
-0
lines changed

Diff for: libarchive/archive_read_support_format_zip.c

+13
Original file line numberDiff line numberDiff line change
@@ -2778,6 +2778,11 @@ zip_read_mac_metadata(struct archive_read *a, struct archive_entry *entry,
27782778

27792779
switch(rsrc->compression) {
27802780
case 0: /* No compression. */
2781+
if (rsrc->uncompressed_size != rsrc->compressed_size) {
2782+
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
2783+
"Malformed OS X metadata entry: inconsistent size");
2784+
return (ARCHIVE_FATAL);
2785+
}
27812786
#ifdef HAVE_ZLIB_H
27822787
case 8: /* Deflate compression. */
27832788
#endif
@@ -2798,6 +2803,12 @@ zip_read_mac_metadata(struct archive_read *a, struct archive_entry *entry,
27982803
(intmax_t)rsrc->uncompressed_size);
27992804
return (ARCHIVE_WARN);
28002805
}
2806+
if (rsrc->compressed_size > (4 * 1024 * 1024)) {
2807+
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
2808+
"Mac metadata is too large: %jd > 4M bytes",
2809+
(intmax_t)rsrc->compressed_size);
2810+
return (ARCHIVE_WARN);
2811+
}
28012812

28022813
metadata = malloc((size_t)rsrc->uncompressed_size);
28032814
if (metadata == NULL) {
@@ -2836,6 +2847,8 @@ zip_read_mac_metadata(struct archive_read *a, struct archive_entry *entry,
28362847
bytes_avail = remaining_bytes;
28372848
switch(rsrc->compression) {
28382849
case 0: /* No compression. */
2850+
if ((size_t)bytes_avail > metadata_bytes)
2851+
bytes_avail = metadata_bytes;
28392852
memcpy(mp, p, bytes_avail);
28402853
bytes_used = (size_t)bytes_avail;
28412854
metadata_bytes -= bytes_used;

0 commit comments

Comments
 (0)