1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
|
/*
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/* @test
* @bug 8340553
* @summary Verify that ZipEntry(String), ZipEntry::setComment, and
* ZipEntry::setExtra throws a IllegalArgumentException when the
* combined length of the fields, including the size of the CEN Header,
* exceeds 65,535 bytes
* @run junit MaxZipEntryFieldSizeTest
*/
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import static org.junit.jupiter.api.Assertions.assertThrows;
public class MaxZipEntryFieldSizeTest {
// CEN header size + name length + comment length + extra length
// should not exceed 65,535 bytes per the PKWare APP.NOTE
// 4.4.10, 4.4.11, & 4.4.12.
static final int MAX_COMBINED_CEN_HEADER_SIZE = 0xFFFF;
// Maximum possible size of name length + comment length + extra length
// for entries in order to not exceed 65,489 bytes
static final int MAX_NAME_COMMENT_EXTRA_SIZE =
MAX_COMBINED_CEN_HEADER_SIZE - ZipFile.CENHDR;
// Tag for the 'unknown' field type, specified in APPNOTE.txt 'Third party mappings'
static final short UNKNOWN_ZIP_TAG = (short) 0x9902;
// Zip Entry name used by tests
static final String ENTRY_NAME = "EntryName";
// Max length minus the size of the ENTRY_NAME or ENTRY_COMMENT
static final int MAX_FIELD_LEN_MINUS_ENTRY_NAME =
MAX_NAME_COMMENT_EXTRA_SIZE - 9;
/**
* Validate an IllegalArgumentException is thrown when the
* combined length of the entry name, entry comment, entry extra data,
* and CEN Header size exceeds 65,535 bytes.
*/
@ParameterizedTest
@ValueSource(ints = {30000, 35000})
void combinedLengthTest(int length) {
String comment = "a".repeat(length);
byte[] bytes = creatExtraData(length);
int combinedLength = ENTRY_NAME.length() + comment.length() + bytes.length;
boolean expectException = combinedLength > MAX_COMBINED_CEN_HEADER_SIZE;
System.out.printf("Combined Len= %s, exception: %s%n", combinedLength, expectException);
ZipEntry zipEntry = new ZipEntry(ENTRY_NAME);
zipEntry.setComment(comment);
// The extra data length will trigger the IllegalArgumentException
if (expectException) {
assertThrows(IllegalArgumentException.class, () ->
zipEntry.setExtra(bytes));
} else {
zipEntry.setExtra(bytes);
}
}
/**
* Validate an IllegalArgumentException is thrown when the comment
* length exceeds 65,489 bytes.
*/
@ParameterizedTest
@ValueSource(ints = {MAX_COMBINED_CEN_HEADER_SIZE,
MAX_NAME_COMMENT_EXTRA_SIZE,
MAX_NAME_COMMENT_EXTRA_SIZE + 1,
MAX_FIELD_LEN_MINUS_ENTRY_NAME,
MAX_FIELD_LEN_MINUS_ENTRY_NAME - 1})
void setCommentLengthTest(int length) {
boolean expectException = length >= MAX_NAME_COMMENT_EXTRA_SIZE;
ZipEntry zipEntry = new ZipEntry(ENTRY_NAME);
String comment = "a".repeat(length);
System.out.printf("Comment Len= %s, exception: %s%n", comment.length(), expectException);
// The comment length will trigger the IllegalArgumentException
if (expectException) {
assertThrows(IllegalArgumentException.class, () ->
zipEntry.setComment(comment));
} else {
zipEntry.setComment(comment);
}
}
/**
* Validate an IllegalArgumentException is thrown when the name
* length exceeds 65,489 bytes.
*/
@ParameterizedTest
@ValueSource(ints = {MAX_COMBINED_CEN_HEADER_SIZE,
MAX_NAME_COMMENT_EXTRA_SIZE,
MAX_NAME_COMMENT_EXTRA_SIZE + 1,
MAX_FIELD_LEN_MINUS_ENTRY_NAME,
MAX_FIELD_LEN_MINUS_ENTRY_NAME - 1})
void nameLengthTest(int length) {
boolean expectException = length > MAX_NAME_COMMENT_EXTRA_SIZE;
String name = "a".repeat(length);
System.out.printf("name Len= %s, exception: %s%n", name.length(), expectException);
// The name length will trigger the IllegalArgumentException
if (expectException) {
assertThrows(IllegalArgumentException.class, () -> new ZipEntry(name));
} else {
new ZipEntry(name);
}
}
/**
* Validate an IllegalArgumentException is thrown when the extra data
* length exceeds 65,489 bytes.
*/
@ParameterizedTest
@ValueSource(ints = {MAX_COMBINED_CEN_HEADER_SIZE,
MAX_NAME_COMMENT_EXTRA_SIZE,
MAX_NAME_COMMENT_EXTRA_SIZE + 1,
MAX_FIELD_LEN_MINUS_ENTRY_NAME,
MAX_FIELD_LEN_MINUS_ENTRY_NAME - 1})
void setExtraLengthTest(int length) {
boolean expectException = length >= MAX_NAME_COMMENT_EXTRA_SIZE;
byte[] bytes = creatExtraData(length);
ZipEntry zipEntry = new ZipEntry(ENTRY_NAME);
System.out.printf("extra Len= %s, exception: %s%n", bytes.length, expectException);
// The extra data length will trigger the IllegalArgumentException
if (expectException) {
assertThrows(IllegalArgumentException.class, () -> zipEntry.setExtra(bytes));
} else {
zipEntry.setExtra(bytes);
}
}
/**
* Create the extra field data which will be passed to ZipEntry::setExtra
* @param length size of the extra data
* @return byte array containing the extra data
*/
private static byte[] creatExtraData(int length) {
byte[] bytes = new byte[length];
// Little-endian ByteBuffer for updating the header fields
ByteBuffer buffer = ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN);
// We use the 'unknown' tag, specified in APPNOTE.TXT, 4.6.1 Third party mappings'
buffer.putShort(UNKNOWN_ZIP_TAG);
// Size of the actual (empty) data
buffer.putShort((short) (length - 2 * Short.BYTES));
return bytes;
}
}
|