6969import jdk .internal .ref .CleanerFactory ;
7070import jdk .internal .vm .annotation .Stable ;
7171import sun .nio .cs .UTF_8 ;
72+ import sun .security .action .GetBooleanAction ;
7273import sun .security .util .SignatureFileVerifier ;
7374
7475import static java .util .zip .ZipConstants64 .*;
@@ -121,6 +122,12 @@ public class ZipFile implements ZipConstants, Closeable {
121122 */
122123 public static final int OPEN_DELETE = 0x4 ;
123124
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" );
124131 /**
125132 * Opens a zip file for reading.
126133 *
@@ -1195,6 +1202,16 @@ private int checkAndAddEntry(int pos, int index)
11951202 if (entryPos + nlen > cen .length - ENDHDR ) {
11961203 zerror ("invalid CEN header (bad header size)" );
11971204 }
1205+
1206+ int elen = CENEXT (cen , pos );
1207+ if (elen > 0 && !disableZip64ExtraFieldValidation ) {
1208+ long extraStartingOffset = pos + CENHDR + nlen ;
1209+ if ((int )extraStartingOffset != extraStartingOffset ) {
1210+ zerror ("invalid CEN header (bad extra offset)" );
1211+ }
1212+ checkExtraFields (pos , (int )extraStartingOffset , elen );
1213+ }
1214+
11981215 try {
11991216 ZipCoder zcp = zipCoderForPos (pos );
12001217 int hash = zcp .checkedHash (cen , entryPos , nlen );
@@ -1211,6 +1228,119 @@ private int checkAndAddEntry(int pos, int index)
12111228 return nlen ;
12121229 }
12131230
1231+ /**
1232+ * Validate the Zip64 Extra block fields
1233+ * @param startingOffset Extra Field starting offset within the CEN
1234+ * @param extraFieldLen Length of this Extra field
1235+ * @throws ZipException If an error occurs validating the Zip64 Extra
1236+ * block
1237+ */
1238+ private void checkExtraFields (int cenPos , int startingOffset ,
1239+ int extraFieldLen ) throws ZipException {
1240+ // Extra field Length cannot exceed 65,535 bytes per the PKWare
1241+ // APP.note 4.4.11
1242+ if (extraFieldLen > 0xFFFF ) {
1243+ zerror ("invalid extra field length" );
1244+ }
1245+ // CEN Offset where this Extra field ends
1246+ int extraEndOffset = startingOffset + extraFieldLen ;
1247+ if (extraEndOffset > cen .length ) {
1248+ zerror ("Invalid CEN header (extra data field size too long)" );
1249+ }
1250+ int currentOffset = startingOffset ;
1251+ while (currentOffset < extraEndOffset ) {
1252+ int tag = get16 (cen , currentOffset );
1253+ currentOffset += Short .BYTES ;
1254+
1255+ int tagBlockSize = get16 (cen , currentOffset );
1256+ int tagBlockEndingOffset = currentOffset + tagBlockSize ;
1257+
1258+ // The ending offset for this tag block should not go past the
1259+ // offset for the end of the extra field
1260+ if (tagBlockEndingOffset > extraEndOffset ) {
1261+ zerror ("Invalid CEN header (invalid zip64 extra data field size)" );
1262+ }
1263+ currentOffset += Short .BYTES ;
1264+
1265+ if (tag == ZIP64_EXTID ) {
1266+ // Get the compressed size;
1267+ long csize = CENSIZ (cen , cenPos );
1268+ // Get the uncompressed size;
1269+ long size = CENLEN (cen , cenPos );
1270+ checkZip64ExtraFieldValues (currentOffset , tagBlockSize ,
1271+ csize , size );
1272+ }
1273+ currentOffset += tagBlockSize ;
1274+ }
1275+ }
1276+
1277+ /**
1278+ * Validate the Zip64 Extended Information Extra Field (0x0001) block
1279+ * size and that the uncompressed size and compressed size field
1280+ * values are not negative.
1281+ * Note: As we do not use the LOC offset or Starting disk number
1282+ * field value we will not validate them
1283+ * @param off the starting offset for the Zip64 field value
1284+ * @param blockSize the size of the Zip64 Extended Extra Field
1285+ * @param csize CEN header compressed size value
1286+ * @param size CEN header uncompressed size value
1287+ * @throws ZipException if an error occurs
1288+ */
1289+ private void checkZip64ExtraFieldValues (int off , int blockSize , long csize ,
1290+ long size )
1291+ throws ZipException {
1292+ byte [] cen = this .cen ;
1293+ // Validate the Zip64 Extended Information Extra Field (0x0001)
1294+ // length.
1295+ if (!isZip64ExtBlockSizeValid (blockSize )) {
1296+ zerror ("Invalid CEN header (invalid zip64 extra data field size)" );
1297+ }
1298+ // Check the uncompressed size is not negative
1299+ // Note we do not need to check blockSize is >= 8 as
1300+ // we know its length is at least 8 from the call to
1301+ // isZip64ExtBlockSizeValid()
1302+ if ((size == ZIP64_MAGICVAL )) {
1303+ if (get64 (cen , off ) < 0 ) {
1304+ zerror ("Invalid zip64 extra block size value" );
1305+ }
1306+ }
1307+ // Check the compressed size is not negative
1308+ if ((csize == ZIP64_MAGICVAL ) && (blockSize >= 16 )) {
1309+ if (get64 (cen , off + 8 ) < 0 ) {
1310+ zerror ("Invalid zip64 extra block compressed size value" );
1311+ }
1312+ }
1313+ }
1314+
1315+ /**
1316+ * Validate the size and contents of a Zip64 extended information field
1317+ * The order of the Zip64 fields is fixed, but the fields MUST
1318+ * only appear if the corresponding LOC or CEN field is set to 0xFFFF:
1319+ * or 0xFFFFFFFF:
1320+ * Uncompressed Size - 8 bytes
1321+ * Compressed Size - 8 bytes
1322+ * LOC Header offset - 8 bytes
1323+ * Disk Start Number - 4 bytes
1324+ * See PKWare APP.Note Section 4.5.3 for more details
1325+ *
1326+ * @param blockSize the Zip64 Extended Information Extra Field size
1327+ * @return true if the extra block size is valid; false otherwise
1328+ */
1329+ private static boolean isZip64ExtBlockSizeValid (int blockSize ) {
1330+ /*
1331+ * As the fields must appear in order, the block size indicates which
1332+ * fields to expect:
1333+ * 8 - uncompressed size
1334+ * 16 - uncompressed size, compressed size
1335+ * 24 - uncompressed size, compressed sise, LOC Header offset
1336+ * 28 - uncompressed size, compressed sise, LOC Header offset,
1337+ * and Disk start number
1338+ */
1339+ return switch (blockSize ) {
1340+ case 8 , 16 , 24 , 28 -> true ;
1341+ default -> false ;
1342+ };
1343+ }
12141344 private int getEntryHash (int index ) { return entries [index ]; }
12151345 private int getEntryNext (int index ) { return entries [index + 1 ]; }
12161346 private int getEntryPos (int index ) { return entries [index + 2 ]; }
0 commit comments