Commit | Line | Data |
---|---|---|
e7806e6c LF |
1 | Fix CVE-2016-1541 (buffer overflow zip_read_mac_metadata) |
2 | ||
3 | Taken from upstream source repository: | |
4 | https://github.com/libarchive/libarchive/commit/d0331e8e5b05b475f20b1f3101fe1ad772d7e7e7 | |
5 | ||
6 | When reading OS X metadata entries in Zip archives that were stored | |
7 | without compression, libarchive would use the uncompressed entry size | |
8 | to allocate a buffer but would use the compressed entry size to limit | |
9 | the amount of data copied into that buffer. Since the compressed | |
10 | and uncompressed sizes are provided by data in the archive itself, | |
11 | an attacker could manipulate these values to write data beyond | |
12 | the end of the allocated buffer. | |
13 | ||
14 | This fix provides three new checks to guard against such | |
15 | manipulation and to make libarchive generally more robust when | |
16 | handling this type of entry: | |
17 | 1. If an OS X metadata entry is stored without compression, | |
18 | abort the entire archive if the compressed and uncompressed | |
19 | data sizes do not match. | |
20 | 2. When sanity-checking the size of an OS X metadata entry, | |
21 | abort this entry if either the compressed or uncompressed | |
22 | size is larger than 4MB. | |
23 | 3. When copying data into the allocated buffer, check the copy | |
24 | size against both the compressed entry size and uncompressed | |
25 | entry size. | |
26 | --- | |
27 | libarchive/archive_read_support_format_zip.c | 13 +++++++++++++ | |
28 | 1 file changed, 13 insertions(+) | |
29 | ||
30 | diff --git a/libarchive/archive_read_support_format_zip.c b/libarchive/archive_read_support_format_zip.c | |
31 | index 0f8262c..0a0be96 100644 | |
32 | --- a/libarchive/archive_read_support_format_zip.c | |
33 | +++ b/libarchive/archive_read_support_format_zip.c | |
34 | @@ -2778,6 +2778,11 @@ zip_read_mac_metadata(struct archive_read *a, struct archive_entry *entry, | |
35 | ||
36 | switch(rsrc->compression) { | |
37 | case 0: /* No compression. */ | |
38 | + if (rsrc->uncompressed_size != rsrc->compressed_size) { | |
39 | + archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, | |
40 | + "Malformed OS X metadata entry: inconsistent size"); | |
41 | + return (ARCHIVE_FATAL); | |
42 | + } | |
43 | #ifdef HAVE_ZLIB_H | |
44 | case 8: /* Deflate compression. */ | |
45 | #endif | |
46 | @@ -2798,6 +2803,12 @@ zip_read_mac_metadata(struct archive_read *a, struct archive_entry *entry, | |
47 | (intmax_t)rsrc->uncompressed_size); | |
48 | return (ARCHIVE_WARN); | |
49 | } | |
50 | + if (rsrc->compressed_size > (4 * 1024 * 1024)) { | |
51 | + archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, | |
52 | + "Mac metadata is too large: %jd > 4M bytes", | |
53 | + (intmax_t)rsrc->compressed_size); | |
54 | + return (ARCHIVE_WARN); | |
55 | + } | |
56 | ||
57 | metadata = malloc((size_t)rsrc->uncompressed_size); | |
58 | if (metadata == NULL) { | |
59 | @@ -2836,6 +2847,8 @@ zip_read_mac_metadata(struct archive_read *a, struct archive_entry *entry, | |
60 | bytes_avail = remaining_bytes; | |
61 | switch(rsrc->compression) { | |
62 | case 0: /* No compression. */ | |
63 | + if ((size_t)bytes_avail > metadata_bytes) | |
64 | + bytes_avail = metadata_bytes; | |
65 | memcpy(mp, p, bytes_avail); | |
66 | bytes_used = (size_t)bytes_avail; | |
67 | metadata_bytes -= bytes_used; |