Skip to content

Commit

Permalink
8313765: Invalid CEN header (invalid zip64 extra data field size)
Browse files Browse the repository at this point in the history
Backport-of: 13f6450e2e70df4df8bd882def837fbd5bef1524
  • Loading branch information
Ben Taylor authored and Paul Hohensee committed Aug 21, 2023
1 parent 32a1c79 commit 9d1d5e7
Show file tree
Hide file tree
Showing 4 changed files with 1,000 additions and 18 deletions.
52 changes: 43 additions & 9 deletions src/java.base/share/classes/java/util/zip/ZipFile.java
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@
import jdk.internal.vm.annotation.Stable;
import sun.nio.cs.UTF_8;
import sun.nio.fs.DefaultFileSystemProvider;
import sun.security.action.GetBooleanAction;
import sun.security.action.GetPropertyAction;
import sun.security.util.SignatureFileVerifier;

import static java.util.zip.ZipConstants64.*;
Expand Down Expand Up @@ -123,11 +123,12 @@ public class ZipFile implements ZipConstants, Closeable {
public static final int OPEN_DELETE = 0x4;

/**
* Flag which specifies whether the validation of the Zip64 extra
* fields should be disabled
* Flag to specify whether the Extra ZIP64 validation should be
* disabled.
*/
private static final boolean disableZip64ExtraFieldValidation =
GetBooleanAction.privilegedGetProperty("jdk.util.zip.disableZip64ExtraFieldValidation");
private static final boolean DISABLE_ZIP64_EXTRA_VALIDATION =
getDisableZip64ExtraFieldValidation();

/**
* Opens a zip file for reading.
*
Expand Down Expand Up @@ -1092,6 +1093,22 @@ private int[] getMetaInfVersions() {
}
}

/**
* Returns the value of the System property which indicates whether the
* Extra ZIP64 validation should be disabled.
*/
static boolean getDisableZip64ExtraFieldValidation() {
boolean result;
String value = GetPropertyAction.privilegedGetProperty(
"jdk.util.zip.disableZip64ExtraFieldValidation");
if (value == null) {
result = false;
} else {
result = value.isEmpty() || value.equalsIgnoreCase("true");
}
return result;
}

static {
SharedSecrets.setJavaUtilZipFileAccess(
new JavaUtilZipFileAccess() {
Expand Down Expand Up @@ -1208,7 +1225,7 @@ private int checkAndAddEntry(int pos, int index)
}

int elen = CENEXT(cen, pos);
if (elen > 0 && !disableZip64ExtraFieldValidation) {
if (elen > 0 && !DISABLE_ZIP64_EXTRA_VALIDATION) {
long extraStartingOffset = pos + CENHDR + nlen;
if ((int)extraStartingOffset != extraStartingOffset) {
zerror("invalid CEN header (bad extra offset)");
Expand Down Expand Up @@ -1260,25 +1277,32 @@ private void checkExtraFields(int cenPos, int startingOffset,
zerror("Invalid CEN header (extra data field size too long)");
}
int currentOffset = startingOffset;
while (currentOffset < extraEndOffset) {
// Walk through each Extra Header. Each Extra Header Must consist of:
// Header ID - 2 bytes
// Data Size - 2 bytes:
while (currentOffset + Integer.BYTES <= extraEndOffset) {
int tag = get16(cen, currentOffset);
currentOffset += Short.BYTES;

int tagBlockSize = get16(cen, currentOffset);
currentOffset += Short.BYTES;
int tagBlockEndingOffset = currentOffset + tagBlockSize;

// The ending offset for this tag block should not go past the
// offset for the end of the extra field
if (tagBlockEndingOffset > extraEndOffset) {
zerror("Invalid CEN header (invalid zip64 extra data field size)");
zerror(String.format(
"Invalid CEN header (invalid extra data field size for " +
"tag: 0x%04x at %d)",
tag, cenPos));
}
currentOffset += Short.BYTES;

if (tag == ZIP64_EXTID) {
// Get the compressed size;
long csize = CENSIZ(cen, cenPos);
// Get the uncompressed size;
long size = CENLEN(cen, cenPos);

checkZip64ExtraFieldValues(currentOffset, tagBlockSize,
csize, size);
}
Expand All @@ -1302,6 +1326,16 @@ private void checkZip64ExtraFieldValues(int off, int blockSize, long csize,
long size)
throws ZipException {
byte[] cen = this.cen;
// if ZIP64_EXTID blocksize == 0, which may occur with some older
// versions of Apache Ant and Commons Compress, validate csize and size
// to make sure neither field == ZIP64_MAGICVAL
if (blockSize == 0) {
if (csize == ZIP64_MAGICVAL || size == ZIP64_MAGICVAL) {
zerror("Invalid CEN header (invalid zip64 extra data field size)");
}
// Only validate the ZIP64_EXTID data if the block size > 0
return;
}
// Validate the Zip64 Extended Information Extra Field (0x0001)
// length.
if (!isZip64ExtBlockSizeValid(blockSize)) {
Expand Down
14 changes: 13 additions & 1 deletion src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipFileSystem.java
Original file line number Diff line number Diff line change
Expand Up @@ -3085,10 +3085,22 @@ private void readExtra(ZipFileSystem zipfs) throws IOException {
int sz = SH(extra, pos + 2);
pos += 4;
if (pos + sz > elen) { // invalid data
throw new ZipException("Invalid CEN header (invalid zip64 extra data field size)");
throw new ZipException(String.format(
"Invalid CEN header (invalid extra data field size for " +
"tag: 0x%04x size: %d)",
tag, sz));
}
switch (tag) {
case EXTID_ZIP64 :
// if ZIP64_EXTID blocksize == 0, which may occur with some older
// versions of Apache Ant and Commons Compress, validate csize
// size, and locoff to make sure the fields != ZIP64_MAGICVAL
if (sz == 0) {
if (csize == ZIP64_MINVAL || size == ZIP64_MINVAL || locoff == ZIP64_MINVAL) {
throw new ZipException("Invalid CEN header (invalid zip64 extra data field size)");
}
break;
}
// Check to see if we have a valid block size
if (!isZip64ExtBlockSizeValid(sz)) {
throw new ZipException("Invalid CEN header (invalid zip64 extra data field size)");
Expand Down
18 changes: 10 additions & 8 deletions test/jdk/java/util/zip/ZipFile/CorruptedZipFiles.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,24 +22,26 @@
*/

/* @test
* @bug 4770745 6218846 6218848 6237956
* @bug 4770745 6218846 6218848 6237956 8313765
* @summary test for correct detection and reporting of corrupted zip files
* @author Martin Buchholz
* @run junit CorruptedZipFiles
*/


import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import java.io.*;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.zip.ZipEntry;
import java.util.zip.ZipException;
import java.util.zip.ZipFile;
Expand Down Expand Up @@ -258,9 +260,9 @@ public void insufficientFilenameLength() throws IOException {
*/
@Test
public void excessiveExtraFieldLength() throws IOException {
short existingExtraLength = buffer.getShort(cenpos + CENEXT);
buffer.putShort(cenpos+CENEXT, (short) (existingExtraLength + 1));
assertZipException(".*invalid zip64 extra data field size.*");
buffer.put(cenpos+CENEXT, (byte) 0xff);
buffer.put(cenpos+CENEXT+1, (byte) 0xff);
assertZipException(".*extra data field size too long.*");
}

/*
Expand Down
Loading

1 comment on commit 9d1d5e7

@openjdk-notifier
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.