]> git.ipfire.org Git - thirdparty/libarchive.git/commitdiff
Reject an 'ar' filename table larger than 1GB or a filename larger than 1MB.
authorTim Kientzle <kientzle@acm.org>
Sat, 3 Dec 2016 07:41:52 +0000 (23:41 -0800)
committerTim Kientzle <kientzle@acm.org>
Sat, 3 Dec 2016 07:41:52 +0000 (23:41 -0800)
Suggested by issue 220 from OSS-Fuzz project.

libarchive/archive_read_support_format_ar.c

index 4b5b66bd50a6a4da805e9d9f9b5a542b450aeafc..c766cbaba7a8a3a613df305bbdb6e50e98b2f15b 100644 (file)
@@ -260,7 +260,7 @@ _ar_read_header(struct archive_read *a, struct archive_entry *entry,
                archive_entry_set_filetype(entry, AE_IFREG);
                /* Get the size of the filename table. */
                number = ar_atol10(h + AR_size_offset, AR_size_size);
-               if (number > SIZE_MAX) {
+               if (number > SIZE_MAX || number > 1024 * 1024 * 1024) {
                        archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
                            "Filename table too large");
                        return (ARCHIVE_FATAL);
@@ -342,16 +342,19 @@ _ar_read_header(struct archive_read *a, struct archive_entry *entry,
 
                /* Parse the size of the name, adjust the file size. */
                number = ar_atol10(h + AR_name_offset + 3, AR_name_size - 3);
-               bsd_name_length = (size_t)number;
-               /* Guard against the filename + trailing NUL
-                * overflowing a size_t and against the filename size
-                * being larger than the entire entry. */
-               if (number > (uint64_t)(bsd_name_length + 1)
-                   || (int64_t)bsd_name_length > ar->entry_bytes_remaining) {
+               /* Sanity check the filename length:
+                *   = Must be <= SIZE_MAX - 1
+                *   = Must be <= 1MB
+                *   = Cannot be bigger than the entire entry
+                */
+               if (number > SIZE_MAX - 1
+                   || number > 1024 * 1024
+                   || (int64_t)number > ar->entry_bytes_remaining) {
                        archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
                            "Bad input file size");
                        return (ARCHIVE_FATAL);
                }
+               bsd_name_length = (size_t)number;
                ar->entry_bytes_remaining -= bsd_name_length;
                /* Adjust file size reported to client. */
                archive_entry_set_size(entry, ar->entry_bytes_remaining);