]> git.ipfire.org Git - thirdparty/libarchive.git/commitdiff
Handle ZIP files with padding in the extra fields 1074/head
authorJoe Damato <ice799@gmail.com>
Fri, 12 Oct 2018 00:40:45 +0000 (17:40 -0700)
committerJoe Damato <ice799@gmail.com>
Fri, 12 Oct 2018 00:54:12 +0000 (17:54 -0700)
Some ZIP files (certain android AAR packages) include ZIP extra fields
that appear to be padded with 0s. This is technically incorrect, however
other ZIP implementations appear to deal with these type of technically
malformed files. It appears that these broken implementations may be
padding the field to end on a word-aligned boundary.

Instead of generating an error if the length of the extra field is less
than the minimum size (4 bytes), consume the 1 - 3 bytes while checking that
each byte is zero. If all bytes are zero, no error is raised.

libarchive/archive_read_support_format_zip.c

index 420004dbabbc3a7c92c411b655aca0a657e2d37b..ddeda426dda6b27bb74f22d1c2920d763e034281 100644 (file)
@@ -428,10 +428,25 @@ process_extra(struct archive_read *a, const char *p, size_t extra_length, struct
        }
 
        if (extra_length < 4) {
-               archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
-                   "Too-small extra data: Need at least 4 bytes, but only found %d bytes", (int)extra_length);
-               return ARCHIVE_FAILED;
+               size_t i = 0;
+               /* Some ZIP files may have trailing 0 bytes. Let's check they
+                * are all 0 and ignore them instead of returning an error.
+                *
+                * This is not techincally correct, but some ZIP files look like
+                * this and other tools support those files - so let's also
+                * support them.
+                */
+               for (; i < extra_length; i++) {
+                       if (p[i] != 0) {
+                               archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+                                               "Too-small extra data: Need at least 4 bytes, but only found %d bytes", (int)extra_length);
+                               return ARCHIVE_FAILED;
+                       }
+               }
+
+               return ARCHIVE_OK;
        }
+
        while (offset <= extra_length - 4) {
                unsigned short headerid = archive_le16dec(p + offset);
                unsigned short datasize = archive_le16dec(p + offset + 2);