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

Improve ZipOutputSream validation of MAX CEN Header field limits

XMLWordPrintable

    • Icon: CSR CSR
    • Resolution: Approved
    • Icon: P3 P3
    • 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.

      The change ensures that we do the same validation when using ZipOutputStream to create a Zip/jar file
      Show
      The risk is extremely low. We have not encountered any issues with existing Zip/Jar files with the changes made via JDK-8316141 . The change ensures that we do the same validation when using ZipOutputStream to create a Zip/jar file
    • Java API

      Summary

      Add additional CEN Header validation to ZipOutputStream so that it is consistent with similar changes made to java.util.zip.ZipFile and the implementation of the ZIP file system provider.

      Problem

      As part of the fix for JDK-8316141 which was a follow up to JDK-8313765, validation was added to ZipFile and Zip FS so that a ZipException is thrown when 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 corresponding change was not made to ZipOutputStream at the time

      Solution

      Enhance ZipOutputStream so that a ZipException is thrown when the combined length of the CEN header fields exceeds 65,535 bytes

      As part of this change, the javadoc for ZipOutputStream will be clarified

      Specification

      The changes to ZipOutputStream.java

       % git diff 6f8714ee src/java.base/share/classes/java/util/zip/ZipOutputStream.java
      diff --git a/src/java.base/share/classes/java/util/zip/ZipOutputStream.java b/src/java.base/share/classes/java/util/zip/ZipOutputStream.java
      index f68c27b265e..677f91295d5 100644
      --- a/src/java.base/share/classes/java/util/zip/ZipOutputStream.java
      +++ b/src/java.base/share/classes/java/util/zip/ZipOutputStream.java
      @@ -378,6 +378,10 @@ public synchronized void write(byte[] b, int off, int len)
            * Finishes writing the contents of the ZIP output stream without closing
            * the underlying stream. Use this method when applying multiple filters
            * in succession to the same output stream.
      +     * <p>
      +     * A ZipException will be thrown if the combined length, after encoding,
      +     * of the entry name, the extra field data, the entry comment and
      +     * {@linkplain #CENHDR CEN Header size}, exceeds 65,535 bytes.
            * @throws    ZipException if a ZIP file error has occurred
            * @throws    IOException if an I/O exception has occurred
            */
      @@ -398,7 +402,9 @@ public void finish() throws IOException {
           }
      
           /**
      -     * Closes the ZIP output stream as well as the stream being filtered.
      +     * Finishes writing the contents of the ZIP output stream and closes the
      +     * underlying stream. The stream being filtered will also be closed.
      +     *
            * @throws    ZipException if a ZIP file error has occurred
            * @throws    IOException if an I/O error has occurred
            */
      @@ -589,7 +595,8 @@ private void writeCEN(XEntry xentry) throws IOException {
               writeInt(csize);            // compressed size
               writeInt(size);             // uncompressed size
               byte[] nameBytes = zc.getBytes(e.name);
      -        writeShort(nameBytes.length);
      +        int nlen = nameBytes.length;
      +        writeShort(nlen);
      
               int elen = getExtraLen(e.extra);
               if (hasZip64) {
      @@ -626,20 +633,19 @@ private void writeCEN(XEntry xentry) throws IOException {
                   }
               }
               writeShort(elen);
      -        byte[] commentBytes;
      + byte[] commentBytes = null; + int clen = 0; if (e.comment != null) { commentBytes = zc.getBytes(e.comment); - writeShort(Math.min(commentBytes.length, 0xffff)); - } else { - commentBytes = null; - writeShort(0); + clen = Math.min(commentBytes.length, 0xffff); } + writeShort(clen); // file comment length writeShort(0); // starting disk number writeShort(0); // internal file attributes (unused) // extra file attributes, used for storing posix permissions etc. writeInt(e.externalFileAttributes > 0 ? e.externalFileAttributes << 16 : 0); writeInt(offset); // relative offset of local header - writeBytes(nameBytes, 0, nameBytes.length); + writeBytes(nameBytes, 0, nlen); // take care of EXTID_ZIP64 and EXTID_EXTT if (hasZip64) { @@ -679,9 +685,17 @@ private void writeCEN(XEntry xentry) throws IOException { } } } + + // 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. + long headerSize = (long)CENHDR + nlen + clen + elen; + if (headerSize > 0xFFFF ) { + throw new ZipException("invalid CEN header (bad header size)"); + } writeExtra(e.extra); if (commentBytes != null) { - writeBytes(commentBytes, 0, Math.min(commentBytes.length, 0xffff)); + writeBytes(commentBytes, 0, clen); } }

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

              Created:
              Updated:
              Resolved: