69
69
import jdk .internal .vm .annotation .Stable ;
70
70
import sun .nio .cs .UTF_8 ;
71
71
import sun .nio .fs .DefaultFileSystemProvider ;
72
+ import sun .security .action .GetBooleanAction ;
72
73
import sun .security .util .SignatureFileVerifier ;
73
74
74
75
import static java .util .zip .ZipConstants64 .*;
@@ -121,6 +122,12 @@ public class ZipFile implements ZipConstants, Closeable {
121
122
*/
122
123
public static final int OPEN_DELETE = 0x4 ;
123
124
125
+ /**
126
+ * Flag which specifies whether the validation of the Zip64 extra
127
+ * fields should be disabled
128
+ */
129
+ private static final boolean disableZip64ExtraFieldValidation =
130
+ GetBooleanAction .privilegedGetProperty ("jdk.util.zip.disableZip64ExtraFieldValidation" );
124
131
/**
125
132
* Opens a zip file for reading.
126
133
*
@@ -1199,6 +1206,16 @@ private int checkAndAddEntry(int pos, int index)
1199
1206
if (entryPos + nlen > cen .length - ENDHDR ) {
1200
1207
zerror ("invalid CEN header (bad header size)" );
1201
1208
}
1209
+
1210
+ int elen = CENEXT (cen , pos );
1211
+ if (elen > 0 && !disableZip64ExtraFieldValidation ) {
1212
+ long extraStartingOffset = pos + CENHDR + nlen ;
1213
+ if ((int )extraStartingOffset != extraStartingOffset ) {
1214
+ zerror ("invalid CEN header (bad extra offset)" );
1215
+ }
1216
+ checkExtraFields (pos , (int )extraStartingOffset , elen );
1217
+ }
1218
+
1202
1219
try {
1203
1220
ZipCoder zcp = zipCoderForPos (pos );
1204
1221
int hash = zcp .checkedHash (cen , entryPos , nlen );
@@ -1214,7 +1231,6 @@ private int checkAndAddEntry(int pos, int index)
1214
1231
// a String via zcp.toString, an Exception will be thrown
1215
1232
int clen = CENCOM (cen , pos );
1216
1233
if (clen > 0 ) {
1217
- int elen = CENEXT (cen , pos );
1218
1234
int start = entryPos + nlen + elen ;
1219
1235
zcp .toString (cen , start , clen );
1220
1236
}
@@ -1224,6 +1240,119 @@ private int checkAndAddEntry(int pos, int index)
1224
1240
return nlen ;
1225
1241
}
1226
1242
1243
+ /**
1244
+ * Validate the Zip64 Extra block fields
1245
+ * @param startingOffset Extra Field starting offset within the CEN
1246
+ * @param extraFieldLen Length of this Extra field
1247
+ * @throws ZipException If an error occurs validating the Zip64 Extra
1248
+ * block
1249
+ */
1250
+ private void checkExtraFields (int cenPos , int startingOffset ,
1251
+ int extraFieldLen ) throws ZipException {
1252
+ // Extra field Length cannot exceed 65,535 bytes per the PKWare
1253
+ // APP.note 4.4.11
1254
+ if (extraFieldLen > 0xFFFF ) {
1255
+ zerror ("invalid extra field length" );
1256
+ }
1257
+ // CEN Offset where this Extra field ends
1258
+ int extraEndOffset = startingOffset + extraFieldLen ;
1259
+ if (extraEndOffset > cen .length ) {
1260
+ zerror ("Invalid CEN header (extra data field size too long)" );
1261
+ }
1262
+ int currentOffset = startingOffset ;
1263
+ while (currentOffset < extraEndOffset ) {
1264
+ int tag = get16 (cen , currentOffset );
1265
+ currentOffset += Short .BYTES ;
1266
+
1267
+ int tagBlockSize = get16 (cen , currentOffset );
1268
+ int tagBlockEndingOffset = currentOffset + tagBlockSize ;
1269
+
1270
+ // The ending offset for this tag block should not go past the
1271
+ // offset for the end of the extra field
1272
+ if (tagBlockEndingOffset > extraEndOffset ) {
1273
+ zerror ("Invalid CEN header (invalid zip64 extra data field size)" );
1274
+ }
1275
+ currentOffset += Short .BYTES ;
1276
+
1277
+ if (tag == ZIP64_EXTID ) {
1278
+ // Get the compressed size;
1279
+ long csize = CENSIZ (cen , cenPos );
1280
+ // Get the uncompressed size;
1281
+ long size = CENLEN (cen , cenPos );
1282
+ checkZip64ExtraFieldValues (currentOffset , tagBlockSize ,
1283
+ csize , size );
1284
+ }
1285
+ currentOffset += tagBlockSize ;
1286
+ }
1287
+ }
1288
+
1289
+ /**
1290
+ * Validate the Zip64 Extended Information Extra Field (0x0001) block
1291
+ * size and that the uncompressed size and compressed size field
1292
+ * values are not negative.
1293
+ * Note: As we do not use the LOC offset or Starting disk number
1294
+ * field value we will not validate them
1295
+ * @param off the starting offset for the Zip64 field value
1296
+ * @param blockSize the size of the Zip64 Extended Extra Field
1297
+ * @param csize CEN header compressed size value
1298
+ * @param size CEN header uncompressed size value
1299
+ * @throws ZipException if an error occurs
1300
+ */
1301
+ private void checkZip64ExtraFieldValues (int off , int blockSize , long csize ,
1302
+ long size )
1303
+ throws ZipException {
1304
+ byte [] cen = this .cen ;
1305
+ // Validate the Zip64 Extended Information Extra Field (0x0001)
1306
+ // length.
1307
+ if (!isZip64ExtBlockSizeValid (blockSize )) {
1308
+ zerror ("Invalid CEN header (invalid zip64 extra data field size)" );
1309
+ }
1310
+ // Check the uncompressed size is not negative
1311
+ // Note we do not need to check blockSize is >= 8 as
1312
+ // we know its length is at least 8 from the call to
1313
+ // isZip64ExtBlockSizeValid()
1314
+ if ((size == ZIP64_MAGICVAL )) {
1315
+ if (get64 (cen , off ) < 0 ) {
1316
+ zerror ("Invalid zip64 extra block size value" );
1317
+ }
1318
+ }
1319
+ // Check the compressed size is not negative
1320
+ if ((csize == ZIP64_MAGICVAL ) && (blockSize >= 16 )) {
1321
+ if (get64 (cen , off + 8 ) < 0 ) {
1322
+ zerror ("Invalid zip64 extra block compressed size value" );
1323
+ }
1324
+ }
1325
+ }
1326
+
1327
+ /**
1328
+ * Validate the size and contents of a Zip64 extended information field
1329
+ * The order of the Zip64 fields is fixed, but the fields MUST
1330
+ * only appear if the corresponding LOC or CEN field is set to 0xFFFF:
1331
+ * or 0xFFFFFFFF:
1332
+ * Uncompressed Size - 8 bytes
1333
+ * Compressed Size - 8 bytes
1334
+ * LOC Header offset - 8 bytes
1335
+ * Disk Start Number - 4 bytes
1336
+ * See PKWare APP.Note Section 4.5.3 for more details
1337
+ *
1338
+ * @param blockSize the Zip64 Extended Information Extra Field size
1339
+ * @return true if the extra block size is valid; false otherwise
1340
+ */
1341
+ private static boolean isZip64ExtBlockSizeValid (int blockSize ) {
1342
+ /*
1343
+ * As the fields must appear in order, the block size indicates which
1344
+ * fields to expect:
1345
+ * 8 - uncompressed size
1346
+ * 16 - uncompressed size, compressed size
1347
+ * 24 - uncompressed size, compressed sise, LOC Header offset
1348
+ * 28 - uncompressed size, compressed sise, LOC Header offset,
1349
+ * and Disk start number
1350
+ */
1351
+ return switch (blockSize ) {
1352
+ case 8 , 16 , 24 , 28 -> true ;
1353
+ default -> false ;
1354
+ };
1355
+ }
1227
1356
private int getEntryHash (int index ) { return entries [index ]; }
1228
1357
private int getEntryNext (int index ) { return entries [index + 1 ]; }
1229
1358
private int getEntryPos (int index ) { return entries [index + 2 ]; }
0 commit comments