1 /*
   2  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 /* @test
  25  * @bug 4770745 6218846 6218848 6237956
  26  * @summary test for correct detection and reporting of corrupted zip files
  27  * @author Martin Buchholz
  28  */
  29 
  30 import java.util.*;
  31 import java.util.zip.*;
  32 import java.io.*;
  33 import static java.lang.System.*;
  34 import static java.util.zip.ZipFile.*;
  35 
  36 public class CorruptedZipFiles {
  37     static int passed = 0, failed = 0;
  38 
  39     static void fail(String msg) {
  40         failed++;
  41         err.println(msg);
  42     }
  43 
  44     static void unexpected(Throwable t) {
  45         failed++;
  46         t.printStackTrace();
  47     }
  48 
  49     public static void main(String[] args) throws Exception {
  50         try (FileOutputStream fos = new FileOutputStream("x.zip");
  51              ZipOutputStream zos = new ZipOutputStream(fos))
  52         {
  53             ZipEntry e = new ZipEntry("x");
  54             zos.putNextEntry(e);
  55             zos.write((int)'x');
  56         }
  57 
  58         int len = (int)(new File("x.zip").length());
  59         byte[] good = new byte[len];
  60         try (FileInputStream fis = new FileInputStream("x.zip")) {
  61             fis.read(good);
  62         }
  63         new File("x.zip").delete();
  64 
  65         int endpos = len - ENDHDR;
  66         int cenpos = u16(good, endpos+ENDOFF);
  67         int locpos = u16(good, cenpos+CENOFF);
  68         if (u32(good, endpos) != ENDSIG) fail("Where's ENDSIG?");
  69         if (u32(good, cenpos) != CENSIG) fail("Where's CENSIG?");
  70         if (u32(good, locpos) != LOCSIG) fail("Where's LOCSIG?");
  71         if (u16(good, locpos+LOCNAM) != u16(good,cenpos+CENNAM))
  72             fail("Name field length mismatch");
  73         if (u16(good, locpos+LOCEXT) != u16(good,cenpos+CENEXT))
  74             fail("Extra field length mismatch");
  75 
  76         byte[] bad;
  77 
  78         err.println("corrupted ENDSIZ");
  79         bad = good.clone();
  80         bad[endpos+ENDSIZ]=(byte)0xff;
  81         checkZipException(bad, ".*bad central directory size.*");
  82 
  83         err.println("corrupted ENDOFF");
  84         bad = good.clone();
  85         bad[endpos+ENDOFF]=(byte)0xff;
  86         checkZipException(bad, ".*bad central directory offset.*");
  87 
  88         err.println("corrupted CENSIG");
  89         bad = good.clone();
  90         bad[cenpos]++;
  91         checkZipException(bad, ".*bad signature.*");
  92 
  93         err.println("corrupted CENFLG");
  94         bad = good.clone();
  95         bad[cenpos+CENFLG] |= 1;
  96         checkZipException(bad, ".*encrypted entry.*");
  97 
  98         err.println("corrupted CENNAM 1");
  99         bad = good.clone();
 100         bad[cenpos+CENNAM]++;
 101         checkZipException(bad, ".*bad header size.*");
 102 
 103         err.println("corrupted CENNAM 2");
 104         bad = good.clone();
 105         bad[cenpos+CENNAM]--;
 106         checkZipException(bad, ".*bad header size.*");
 107 
 108         err.println("corrupted CENNAM 3");
 109         bad = good.clone();
 110         bad[cenpos+CENNAM]   = (byte)0xfd;
 111         bad[cenpos+CENNAM+1] = (byte)0xfd;
 112         checkZipException(bad, ".*bad header size.*");
 113 
 114         err.println("corrupted CENEXT 1");
 115         bad = good.clone();
 116         bad[cenpos+CENEXT]++;
 117         checkZipException(bad, ".*bad header size.*");
 118 
 119         err.println("corrupted CENEXT 2");
 120         bad = good.clone();
 121         bad[cenpos+CENEXT]   = (byte)0xfd;
 122         bad[cenpos+CENEXT+1] = (byte)0xfd;
 123         checkZipException(bad, ".*bad header size.*");
 124 
 125         err.println("corrupted CENCOM");
 126         bad = good.clone();
 127         bad[cenpos+CENCOM]++;
 128         checkZipException(bad, ".*bad header size.*");
 129 
 130         err.println("corrupted CENHOW");
 131         bad = good.clone();
 132         bad[cenpos+CENHOW] = 2;
 133         checkZipException(bad, ".*bad compression method.*");
 134 
 135         err.println("corrupted LOCSIG");
 136         bad = good.clone();
 137         bad[locpos]++;
 138         checkZipExceptionInGetInputStream(bad, ".*bad signature.*");
 139 
 140         out.printf("passed = %d, failed = %d%n", passed, failed);
 141         if (failed > 0) throw new Exception("Some tests failed");
 142     }
 143 
 144     static int uniquifier = 432;
 145 
 146     static void checkZipExceptionImpl(byte[] data,
 147                                       String msgPattern,
 148                                       boolean getInputStream) {
 149         String zipName = "bad" + (uniquifier++) + ".zip";
 150         try {
 151             try (FileOutputStream fos = new FileOutputStream(zipName)) {
 152                 fos.write(data);
 153             }
 154             try (ZipFile zf = new ZipFile(zipName)) {
 155                 if (getInputStream) {
 156                     InputStream is = zf.getInputStream(new ZipEntry("x"));
 157                     is.read();
 158                 }
 159             }
 160             fail("Failed to throw expected ZipException");
 161         } catch (ZipException e) {
 162             if (e.getMessage().matches(msgPattern))
 163                 passed++;
 164             else
 165                 unexpected(e);
 166         } catch (Throwable t) {
 167             unexpected(t);
 168         } finally {
 169             new File(zipName).delete();
 170         }
 171     }
 172 
 173     static void checkZipException(byte[] data, String msgPattern) {
 174         checkZipExceptionImpl(data, msgPattern, false);
 175     }
 176 
 177     static void checkZipExceptionInGetInputStream(byte[] data, String msgPattern) {
 178         checkZipExceptionImpl(data, msgPattern, true);
 179     }
 180 
 181     static int u8(byte[] data, int offset) {
 182         return data[offset]&0xff;
 183     }
 184 
 185     static int u16(byte[] data, int offset) {
 186         return u8(data,offset) + (u8(data,offset+1)<<8);
 187     }
 188 
 189     static int u32(byte[] data, int offset) {
 190         return u16(data,offset) + (u16(data,offset+2)<<16);
 191     }
 192 
 193     // The following can be deleted once this bug is fixed:
 194     // 6225935: "import static" accessibility rules for symbols different for no reason
 195     static final long LOCSIG = ZipFile.LOCSIG;
 196     static final long EXTSIG = ZipFile.EXTSIG;
 197     static final long CENSIG = ZipFile.CENSIG;
 198     static final long ENDSIG = ZipFile.ENDSIG;
 199 
 200     static final int LOCHDR = ZipFile.LOCHDR;
 201     static final int EXTHDR = ZipFile.EXTHDR;
 202     static final int CENHDR = ZipFile.CENHDR;
 203     static final int ENDHDR = ZipFile.ENDHDR;
 204 
 205     static final int LOCVER = ZipFile.LOCVER;
 206     static final int LOCFLG = ZipFile.LOCFLG;
 207     static final int LOCHOW = ZipFile.LOCHOW;
 208     static final int LOCTIM = ZipFile.LOCTIM;
 209     static final int LOCCRC = ZipFile.LOCCRC;
 210     static final int LOCSIZ = ZipFile.LOCSIZ;
 211     static final int LOCLEN = ZipFile.LOCLEN;
 212     static final int LOCNAM = ZipFile.LOCNAM;
 213     static final int LOCEXT = ZipFile.LOCEXT;
 214 
 215     static final int CENVEM = ZipFile.CENVEM;
 216     static final int CENVER = ZipFile.CENVER;
 217     static final int CENFLG = ZipFile.CENFLG;
 218     static final int CENHOW = ZipFile.CENHOW;
 219     static final int CENTIM = ZipFile.CENTIM;
 220     static final int CENCRC = ZipFile.CENCRC;
 221     static final int CENSIZ = ZipFile.CENSIZ;
 222     static final int CENLEN = ZipFile.CENLEN;
 223     static final int CENNAM = ZipFile.CENNAM;
 224     static final int CENEXT = ZipFile.CENEXT;
 225     static final int CENCOM = ZipFile.CENCOM;
 226     static final int CENDSK = ZipFile.CENDSK;
 227     static final int CENATT = ZipFile.CENATT;
 228     static final int CENATX = ZipFile.CENATX;
 229     static final int CENOFF = ZipFile.CENOFF;
 230 
 231     static final int ENDSUB = ZipFile.ENDSUB;
 232     static final int ENDTOT = ZipFile.ENDTOT;
 233     static final int ENDSIZ = ZipFile.ENDSIZ;
 234     static final int ENDOFF = ZipFile.ENDOFF;
 235     static final int ENDCOM = ZipFile.ENDCOM;
 236 }