1 /*
2  * Copyright (c) 2005, 2011, 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 
fail(String msg)39     static void fail(String msg) {
40         failed++;
41         err.println(msg);
42     }
43 
unexpected(Throwable t)44     static void unexpected(Throwable t) {
45         failed++;
46         t.printStackTrace();
47     }
48 
main(String[] args)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 
checkZipExceptionImpl(byte[] data, String msgPattern, boolean getInputStream)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 
checkZipException(byte[] data, String msgPattern)173     static void checkZipException(byte[] data, String msgPattern) {
174         checkZipExceptionImpl(data, msgPattern, false);
175     }
176 
checkZipExceptionInGetInputStream(byte[] data, String msgPattern)177     static void checkZipExceptionInGetInputStream(byte[] data, String msgPattern) {
178         checkZipExceptionImpl(data, msgPattern, true);
179     }
180 
u8(byte[] data, int offset)181     static int u8(byte[] data, int offset) {
182         return data[offset]&0xff;
183     }
184 
u16(byte[] data, int offset)185     static int u16(byte[] data, int offset) {
186         return u8(data,offset) + (u8(data,offset+1)<<8);
187     }
188 
u32(byte[] data, int offset)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 }
237