Skip to content

Commit

Permalink
Add testPaxTimeFieldsForInvalidValues
Browse files Browse the repository at this point in the history
  • Loading branch information
garydgregory committed Sep 3, 2023
1 parent df7172f commit 4335481
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,17 @@ public class TarArchiveEntry implements ArchiveEntry, TarConstants, EntryStreamO
@Deprecated
public static final int MILLIS_PER_SECOND = 1000;

/**
* Regular expression pattern for validating values in pax extended header file time fields.
* These fields contain two numeric values (seconds and sub-second values) as per this definition:
* https://pubs.opengroup.org/onlinepubs/9699919799/utilities/pax.html#tag_20_92_13_05
* <p>
* Since they are parsed into long values, maximum length of each is the same as Long.MAX_VALUE
* which is 19 digits.
* </p>
*/
private static final String PAX_EXTENDED_HEADER_FILE_TIMES_PATTERN = "-?\\d{1,19}(?:\\.\\d{1,19})?";

private static FileTime fileTimeFromOptionalSeconds(final long seconds) {
if (seconds <= 0) {
return null;
Expand Down Expand Up @@ -265,7 +276,12 @@ private static String normalizeFileName(String fileName, final boolean preserveA
return fileName;
}

private static Instant parseInstantFromDecimalSeconds(final String value) {
private static Instant parseInstantFromDecimalSeconds(final String value) throws IOException {
// Validate field values to prevent denial of service attacks with BigDecimal values (see JDK-6560193)
if (!value.matches(TarArchiveEntry.PAX_EXTENDED_HEADER_FILE_TIMES_PATTERN)) {
throw new IOException("Corrupted PAX header. Time field value is invalid '" + value + "'");
}

final BigDecimal epochSeconds = new BigDecimal(value);
final long seconds = epochSeconds.longValue();
final long nanos = epochSeconds.remainder(BigDecimal.ONE).movePointRight(9).longValue();
Expand All @@ -289,12 +305,12 @@ private static Instant parseInstantFromDecimalSeconds(final String value) {

/** The entry's size. */
private long size;

/**
* The entry's modification time.
* Corresponds to the POSIX {@code mtime} attribute.
*/
private FileTime mTime;

/**
* The entry's status change time.
* Corresponds to the POSIX {@code ctime} attribute.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Random;

import org.apache.commons.compress.AbstractTestCase;
import org.apache.commons.compress.archivers.zip.ZipEncodingHelper;
Expand Down Expand Up @@ -406,6 +407,29 @@ public void testMaxFileSize(){
t.setSize(0100000000000L);
}

@Test
public void testPaxTimeFieldsForInvalidValues() {
final String[] headerNames = { "LIBARCHIVE.creationtime", "atime", "mtime", "ctime" };
// @formatter:off
final String[] testValues = {
// Generate a number with a very large integer or fractional component
new Random().nextLong() + "." + String.join("",
Collections.nCopies(15000, String.valueOf(Long.MAX_VALUE))),
// These two examples use the exponent notation
"9e9999999",
"9E9999999"
};
// @formatter:on

final TarArchiveEntry entry = new TarArchiveEntry("test.txt");
for (String name : headerNames) {
for (String value : testValues) {
Exception exp = assertThrows(IllegalArgumentException.class, () -> entry.addPaxHeader(name, value));
assert(exp.getCause().getMessage().startsWith("Corrupted PAX header. Time field value is invalid"));
}
}
}

@Test
public void testTarFileWithFSRoot() throws IOException {
final File f = File.createTempFile("taetest", ".tar");
Expand Down

0 comments on commit 4335481

Please sign in to comment.