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

ZipFile don't throw exception when LOCHOW is invalid

XMLWordPrintable

      A DESCRIPTION OF THE PROBLEM :
      When a ZIP file's LOCAL FILE HEADER contains an invalid compression method (LOCHOW), ZipFile.getInputStream() fails to correctly throw a ZipException. The implementation should verify that the compression method in the local header (LOCHOW) matches the one specified in the central directory (CENHOW) and also validate that it's a supported compression method before attempting decompression.

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      test passed
      ACTUAL -
      test failed

      ---------- BEGIN SOURCE ----------
      /*
       * Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved.
       * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       *
       * This code is free software; you can redistribute it and/or modify it
       * under the terms of the GNU General Public License version 2 only, as
       * published by the Free Software Foundation.
       *
       * This code is distributed in the hope that it will be useful, but WITHOUT
       * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
       * version 2 for more details (a copy is included in the LICENSE file that
       * accompanied this code).
       *
       * You should have received a copy of the GNU General Public License version
       * 2 along with this work; if not, write to the Free Software Foundation,
       * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       *
       * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       * or visit www.oracle.com if you need additional information or have any
       * questions.
       */

      /* @test
       * @bug 4770745 6218846 6218848 6237956 8313765
       * @summary test for correct detection and reporting of corrupted zip files
       * @author Martin Buchholz
       */

      import java.util.*;
      import java.util.zip.*;
      import java.io.*;
      import static java.lang.System.*;
      import static java.util.zip.ZipFile.*;

      public class CorruptedZipFiles {
          static int passed = 0, failed = 0;

          static void fail(String msg) {
              failed++;
              err.println(msg);
          }

          static void unexpected(Throwable t) {
              failed++;
              t.printStackTrace();
          }

          public static void main(String[] args) throws Exception {
              try (FileOutputStream fos = new FileOutputStream("x.zip");
                   ZipOutputStream zos = new ZipOutputStream(fos))
              {
                  ZipEntry e = new ZipEntry("x");
                  zos.putNextEntry(e);
                  zos.write((int)'x');
              }

              int len = (int)(new File("x.zip").length());
              byte[] good = new byte[len];
              try (FileInputStream fis = new FileInputStream("x.zip")) {
                  fis.read(good);
              }
              new File("x.zip").delete();

              int endpos = len - ENDHDR;
              int cenpos = u16(good, endpos+ENDOFF);
              int locpos = u16(good, cenpos+CENOFF);
              if (u32(good, endpos) != ENDSIG) fail("Where's ENDSIG?");
              if (u32(good, cenpos) != CENSIG) fail("Where's CENSIG?");
              if (u32(good, locpos) != LOCSIG) fail("Where's LOCSIG?");
              if (u16(good, locpos+LOCNAM) != u16(good,cenpos+CENNAM))
                  fail("Name field length mismatch");
              if (u16(good, locpos+LOCEXT) != u16(good,cenpos+CENEXT))
                  fail("Extra field length mismatch");

              byte[] bad;
              
              // Test Case: Invalid compression method in local header
              err.println("\n========================================");
              err.println("TEST: corrupted LOCHOW (invalid compression method in local header)");
              bad = good.clone();
              bad[locpos + LOCHOW] = 2; // Set invalid method (2)
              checkZipExceptionInGetInputStream(bad, ".*invalid compression method.*"); // Fix: Corrected regex to match actual message

              out.printf("passed = %d, failed = %d%n", passed, failed);
              if (failed > 0) throw new Exception("Some tests failed");
          }

          static int uniquifier = 432;

          static void checkZipExceptionImpl(byte[] data,
                                            String msgPattern,
                                            boolean getInputStream) {
              String zipName = "bad" + (uniquifier++) + ".zip";
              String testType = getInputStream ? "getInputStream" : "openZipFile";
              err.println("== TEST CASE: " + zipName + " (" + testType + ") ==");
              err.println("Expected exception pattern: " + msgPattern);
              
              try {
                  try (FileOutputStream fos = new FileOutputStream(zipName)) {
                      fos.write(data);
                  }
                  try (ZipFile zf = new ZipFile(zipName)) {
                      if (getInputStream) {
                          err.println(" Attempting to get input stream...");
                          InputStream is = zf.getInputStream(new ZipEntry("x"));
                          is.read();
                      } else {
                          err.println(" ZipFile opened successfully without exception");
                      }
                  }
                  err.println(" TEST FAILED: No exception thrown");
                  fail("Failed to throw expected ZipException");
              } catch (ZipException e) {
                  err.println(" Caught ZipException: \"" + e.getMessage() + "\"");
                  if (e.getMessage().matches(msgPattern)) {
                      err.println(" TEST PASSED: Exception matches expected pattern");
                      passed++;
                  } else {
                      err.println(" TEST FAILED: Exception message doesn't match pattern");
                      err.println(" Actual: \"" + e.getMessage() + "\"");
                      err.println(" Expected pattern: \"" + msgPattern + "\"");
                      unexpected(e);
                  }
              } catch (Throwable t) {
                  err.println(" TEST FAILED: Caught unexpected exception type: " + t.getClass().getName());
                  unexpected(t);
              } finally {
                  new File(zipName).delete();
              }
              err.println();
          }

          static void checkZipException(byte[] data, String msgPattern) {
              checkZipExceptionImpl(data, msgPattern, false);
          }

          static void checkZipExceptionInGetInputStream(byte[] data, String msgPattern) {
              checkZipExceptionImpl(data, msgPattern, true);
          }

          static int u8(byte[] data, int offset) {
              return data[offset]&0xff;
          }

          static int u16(byte[] data, int offset) {
              return u8(data,offset) + (u8(data,offset+1)<<8);
          }

          static int u32(byte[] data, int offset) {
              return u16(data,offset) + (u16(data,offset+2)<<16);
          }

          // The following can be deleted once this bug is fixed:
          // 6225935: "import static" accessibility rules for symbols different for no reason
          static final long LOCSIG = ZipFile.LOCSIG;
          static final long EXTSIG = ZipFile.EXTSIG;
          static final long CENSIG = ZipFile.CENSIG;
          static final long ENDSIG = ZipFile.ENDSIG;

          static final int LOCHDR = ZipFile.LOCHDR;
          static final int EXTHDR = ZipFile.EXTHDR;
          static final int CENHDR = ZipFile.CENHDR;
          static final int ENDHDR = ZipFile.ENDHDR;

          static final int LOCVER = ZipFile.LOCVER;
          static final int LOCFLG = ZipFile.LOCFLG;
          static final int LOCHOW = ZipFile.LOCHOW;
          static final int LOCTIM = ZipFile.LOCTIM;
          static final int LOCCRC = ZipFile.LOCCRC;
          static final int LOCSIZ = ZipFile.LOCSIZ;
          static final int LOCLEN = ZipFile.LOCLEN;
          static final int LOCNAM = ZipFile.LOCNAM;
          static final int LOCEXT = ZipFile.LOCEXT;

          static final int CENVEM = ZipFile.CENVEM;
          static final int CENVER = ZipFile.CENVER;
          static final int CENFLG = ZipFile.CENFLG;
          static final int CENHOW = ZipFile.CENHOW;
          static final int CENTIM = ZipFile.CENTIM;
          static final int CENCRC = ZipFile.CENCRC;
          static final int CENSIZ = ZipFile.CENSIZ;
          static final int CENLEN = ZipFile.CENLEN;
          static final int CENNAM = ZipFile.CENNAM;
          static final int CENEXT = ZipFile.CENEXT;
          static final int CENCOM = ZipFile.CENCOM;
          static final int CENDSK = ZipFile.CENDSK;
          static final int CENATT = ZipFile.CENATT;
          static final int CENATX = ZipFile.CENATX;
          static final int CENOFF = ZipFile.CENOFF;

          static final int ENDSUB = ZipFile.ENDSUB;
          static final int ENDTOT = ZipFile.ENDTOT;
          static final int ENDSIZ = ZipFile.ENDSIZ;
          static final int ENDOFF = ZipFile.ENDOFF;
          static final int ENDCOM = ZipFile.ENDCOM;
      }

      ---------- END SOURCE ----------

            lancea Lance Andersen
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

              Created:
              Updated:
              Resolved: