Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8340962

ZipEntry field validation does not take into account the size of a CEN header

XMLWordPrintable

    • Icon: CSR CSR
    • Resolution: Approved
    • Icon: P4 P4
    • 24
    • core-libs
    • None
    • behavioral
    • low
    • Hide
      The risk is extremely low. We have not encountered any issues with existing Zip/Jar files with the changes made via JDK-8316141. JDK-8336025 added similar validation to zipOutputStream

      The change ensures that we correctly validate for the maximum possible field size value taking into account the CEN Header size.

      The addition of validating the comment field length has minimal risk at best as the entry comment field is seldom used if at all and on a run of our internal corpus of 90,000+ jar files, we did not encounter any which included an entry comment
      Show
      The risk is extremely low. We have not encountered any issues with existing Zip/Jar files with the changes made via JDK-8316141 . JDK-8336025 added similar validation to zipOutputStream The change ensures that we correctly validate for the maximum possible field size value taking into account the CEN Header size. The addition of validating the comment field length has minimal risk at best as the entry comment field is seldom used if at all and on a run of our internal corpus of 90,000+ jar files, we did not encounter any which included an entry comment
    • Java API
    • SE

      Summary

      ZipEntry(String), ZipEntry::setComment, and ZipEntry::setExtra did not take into account the combined length of the CEN Header, ZipEntry name, entry comment, and entry extra data size when validating the input for the constructor and methods.

      Problem

      This is a follow-on to JDK-8316141 and JDK-8336025 which addresses the fact that the validation checking in ZipFile and ZipOutputStream did not verify that the combined length of the CEN Header, which is 46 bytes, the entry name length, entry comment length, and entry extra length exceeds 65,535 bytes per the PKWare APP.NOTE 4.4.10, 4.4.11, & 4.4.12.

      The maximum possible value for the above fields when you take into account the CEN Header length is 65,489. Because of this, we need to change the ZipEntry validation for the above fields to validate that the combined length does not exceed 65,535 bytes.

      Solution

      Update ZipEntry validation for the name, extra and comments fields so that the validation takes into account the combined length of the entry name, entry comment, entry extra data along with the 46 bytes for the CEN Header does not exceed 65,535 bytes.

      Specification

      The following updates will ba made to ZipEntry:

      diff --git a/src/java.base/share/classes/java/util/zip/ZipEntry.java b/src/java.base/share/classes/java/util/zip/ZipEntry.java
      index 026f6e466ea..35eae646ea8 100644
      --- a/src/java.base/share/classes/java/util/zip/ZipEntry.java
      +++ b/src/java.base/share/classes/java/util/zip/ZipEntry.java
      @@ -91,11 +91,10 @@ public class ZipEntry implements ZipConstants, Cloneable {
            */
           private static final long UPPER_DOSTIME_BOUND =
                   128L * 365 * 24 * 60 * 60 * 1000;
      -    // Maximum possible size of name length + comment length + extra length
      -    // for entries in order to not exceed 65,489 bytes minus 46 bytes for the CEN
      -    // header length
      -    private static final int MAX_NAME_COMMENT_EXTRA_SIZE =
      -            0xFFFF - ZipFile.CENHDR;
      +    // CEN header size + name length + comment length + extra length
      +    // should not exceed 65,535 bytes per the PKWare APP.NOTE
      +    // 4.4.10, 4.4.11, & 4.4.12.
      +    private static final int MAX_COMBINED_CEN_HEADER_SIZE = 0xFFFF;
           /**
            * Creates a new ZIP entry with the specified name.
            *
      @@ -103,12 +102,12 @@ public class ZipEntry implements ZipConstants, Cloneable {
            *         The entry name
            *
            * @throws NullPointerException if the entry name is null
      -     * @throws IllegalArgumentException if the entry name is longer than
      -     *         65,489 bytes
      +     * @throws IllegalArgumentException if the combined length of the entry name
      +     * and the {@linkplain #CENHDR CEN Header size} exceeds 65,535 bytes.
            */
           public ZipEntry(String name) {
               Objects.requireNonNull(name, "name");
      -        if (name.length() > MAX_NAME_COMMENT_EXTRA_SIZE) {
      +        if (!isCENHeaderValid(name, null, null)) {
                   throw new IllegalArgumentException("entry name too long");
               }
               this.name = name;
      @@ -523,8 +522,10 @@ public int getMethod() {
            * @param  extra
            *         The extra field data bytes
            *
      -     * @throws IllegalArgumentException if the length of the specified
      -     *         extra field data is greater than 65,489 bytes
      +     * @throws IllegalArgumentException if the combined length of the specified
      +     * extra field data, the {@linkplain #getName() entry name},
      +     * the {@linkplain #getComment() entry comment}, and the
      +     * {@linkplain #CENHDR CEN Header size}, exceeds 65,535 bytes.
            *
            * @see #getExtra()
            */
      @@ -545,7 +546,7 @@ public void setExtra(byte[] extra) {
      */
      void setExtra0(byte[] extra, boolean doZIP64, boolean isLOC) { if (extra != null) { - if (extra.length > MAX_NAME_COMMENT_EXTRA_SIZE) { + if (!isCENHeaderValid(name, extra, comment)) { throw new IllegalArgumentException("invalid extra field length"); } // extra fields are in "HeaderID(2)DataSize(2)Data... format @@ -647,13 +648,15 @@ public byte[] getExtra() { /** * Sets the optional comment string for the entry. * @param comment the comment string - * @throws IllegalArgumentException if the length of the specified - * comment string is greater than 65,489 bytes + * @throws IllegalArgumentException if the combined length + * of the specified entry comment, the {@linkplain #getName() entry name}, + * the {@linkplain #getExtra() extra field data}, and the + * {@linkplain #CENHDR CEN Header size}, exceeds 65,535 bytes. * @see #getComment() */ public void setComment(String comment) { if (comment != null) { - if (comment.length() > MAX_NAME_COMMENT_EXTRA_SIZE) { + if (!isCENHeaderValid(name, extra, comment)) { throw new IllegalArgumentException("entry comment too long"); } } @@ -707,4 +710,20 @@ public Object clone() { throw new InternalError(e); } } + + /** + * Validate that the CEN header size + name length + comment length + extra length + * do not exceed 65,535 bytes per the PKWare APP.NOTE + * 4.4.10, 4.4.11, & 4.4.12. + * @param name Zip entry name + * @param extra Zip extra data + * @param comment Zip entry comment + * @return true if valid CEN Header size; false otherwise + */ + static boolean isCENHeaderValid(String name, byte[] extra, String comment) { + int clen = comment == null ? 0 : comment.length(); + int elen = extra == null ? 0 : extra.length; + long headerSize = (long)CENHDR + name.length() + clen + elen; + return headerSize <= MAX_COMBINED_CEN_HEADER_SIZE; + } }

            lancea Lance Andersen
            lancea Lance Andersen
            Jaikiran Pai
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated:
              Resolved: