Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

8313765: Invalid CEN header (invalid zip64 extra data field size) #72

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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