6969import jdk .internal .vm .annotation .Stable ;
7070import sun .nio .cs .UTF_8 ;
7171import sun .nio .fs .DefaultFileSystemProvider ;
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 *
@@ -1199,6 +1206,16 @@ private int checkAndAddEntry(int pos, int index)
11991206 if (entryPos + nlen > cen .length - ENDHDR ) {
12001207 zerror ("invalid CEN header (bad header size)" );
12011208 }
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+
12021219 try {
12031220 ZipCoder zcp = zipCoderForPos (pos );
12041221 int hash = zcp .checkedHash (cen , entryPos , nlen );
@@ -1214,7 +1231,6 @@ private int checkAndAddEntry(int pos, int index)
12141231 // a String via zcp.toString, an Exception will be thrown
12151232 int clen = CENCOM (cen , pos );
12161233 if (clen > 0 ) {
1217- int elen = CENEXT (cen , pos );
12181234 int start = entryPos + nlen + elen ;
12191235 zcp .toString (cen , start , clen );
12201236 }
@@ -1224,6 +1240,119 @@ private int checkAndAddEntry(int pos, int index)
12241240 return nlen ;
12251241 }
12261242
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+ }
12271356 private int getEntryHash (int index ) { return entries [index ]; }
12281357 private int getEntryNext (int index ) { return entries [index + 1 ]; }
12291358 private int getEntryPos (int index ) { return entries [index + 2 ]; }
0 commit comments