This is an automated email from the ASF dual-hosted git repository.
bodewig pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-compress.git
The following commit(s) were added to refs/heads/master by this push:
new 61615b3 COMPRESS-575 harden parser for PAX 0.0 sparse headers
61615b3 is described below
commit 61615b31c57fd96e122a70bd823e155117422328
Author: Stefan Bodewig <[email protected]>
AuthorDate: Sat May 1 10:11:57 2021 +0200
COMPRESS-575 harden parser for PAX 0.0 sparse headers
---
.../commons/compress/archivers/tar/TarUtils.java | 28 ++++++-
.../compress/archivers/tar/TarUtilsTest.java | 92 +++++++++++++++++++++-
2 files changed, 117 insertions(+), 3 deletions(-)
diff --git
a/src/main/java/org/apache/commons/compress/archivers/tar/TarUtils.java
b/src/main/java/org/apache/commons/compress/archivers/tar/TarUtils.java
index 5b7fb28..ea4741a 100644
--- a/src/main/java/org/apache/commons/compress/archivers/tar/TarUtils.java
+++ b/src/main/java/org/apache/commons/compress/archivers/tar/TarUtils.java
@@ -695,6 +695,10 @@ public class TarUtils {
+ got);
}
// Drop trailing NL
+ if (rest[rest.length - 1] != '\n') {
+ throw new IOException("Failed to read
Paxheader."
+ + "Value should end with a newline");
+ }
final String value = new String(rest, 0,
restLen - 1, StandardCharsets.UTF_8);
headers.put(keyword, value);
@@ -705,7 +709,16 @@ public class TarUtils {
// previous GNU.sparse.offset header
but but no numBytes
sparseHeaders.add(new
TarArchiveStructSparse(offset, 0));
}
- offset = Long.valueOf(value);
+ try {
+ offset = Long.valueOf(value);
+ } catch (NumberFormatException ex) {
+ throw new IOException("Failed to read
Paxheader."
+ + "GNU.sparse.offset contains a
non-numeric value");
+ }
+ if (offset < 0) {
+ throw new IOException("Failed to read
Paxheader."
+ + "GNU.sparse.offset contains
negative value");
+ }
}
// for 0.0 PAX Headers
@@ -714,7 +727,18 @@ public class TarUtils {
throw new IOException("Failed to read
Paxheader." +
"GNU.sparse.offset is expected
before GNU.sparse.numbytes shows up.");
}
- sparseHeaders.add(new
TarArchiveStructSparse(offset, Long.parseLong(value)));
+ long numbytes;
+ try {
+ numbytes = Long.parseLong(value);
+ } catch (NumberFormatException ex) {
+ throw new IOException("Failed to read
Paxheader."
+ + "GNU.sparse.numbytes contains a
non-numeric value.");
+ }
+ if (numbytes < 0) {
+ throw new IOException("Failed to read
Paxheader."
+ + "GNU.sparse.numbytes contains
negative value");
+ }
+ sparseHeaders.add(new
TarArchiveStructSparse(offset, numbytes));
offset = null;
}
}
diff --git
a/src/test/java/org/apache/commons/compress/archivers/tar/TarUtilsTest.java
b/src/test/java/org/apache/commons/compress/archivers/tar/TarUtilsTest.java
index 446a059..4e04f06 100644
--- a/src/test/java/org/apache/commons/compress/archivers/tar/TarUtilsTest.java
+++ b/src/test/java/org/apache/commons/compress/archivers/tar/TarUtilsTest.java
@@ -23,7 +23,10 @@ import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
+import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import org.apache.commons.compress.archivers.zip.ZipEncoding;
@@ -31,9 +34,12 @@ import
org.apache.commons.compress.archivers.zip.ZipEncodingHelper;
import org.apache.commons.compress.utils.ByteUtils;
import org.apache.commons.compress.utils.CharsetNames;
import org.apache.commons.compress.utils.IOUtils;
+import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.ExpectedException;
import static org.apache.commons.compress.AbstractTestCase.getFile;
+import static org.hamcrest.CoreMatchers.startsWith;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@@ -41,6 +47,8 @@ import static org.junit.Assert.fail;
public class TarUtilsTest {
+ @Rule
+ public ExpectedException thrown = ExpectedException.none();
@Test
public void testName(){
@@ -449,8 +457,9 @@ public class TarUtilsTest {
assertEquals(ae, headers.get("path"));
}
- @Test(expected = IOException.class)
+ @Test
public void testParseTarWithSpecialPaxHeaders() throws IOException {
+ thrown.expect(IOException.class);
try (InputStream in =
Files.newInputStream(getFile("COMPRESS-530.tar").toPath());
TarArchiveInputStream archive = new TarArchiveInputStream(in)) {
archive.getNextEntry();
@@ -458,4 +467,85 @@ public class TarUtilsTest {
}
}
+ @Test
+ public void readPaxHeaderWithoutTrailingNewline() throws Exception {
+ thrown.expect(IOException.class);
+ thrown.expectMessage(startsWith("Failed to read Paxheader"));
+ TarUtils.parsePaxHeaders(
+ new ByteArrayInputStream("30
atime=1321711775.9720594634".getBytes(StandardCharsets.UTF_8)),
+ null, Collections.emptyMap());
+ }
+
+ @Test
+ public void readPax00SparseHeader() throws Exception {
+ final String header = "23 GNU.sparse.offset=0\n"
+ + "26 GNU.sparse.numbytes=10\n";
+ final List<TarArchiveStructSparse> sparseHeaders = new ArrayList<>();
+ TarUtils.parsePaxHeaders(
+ new ByteArrayInputStream(header.getBytes(StandardCharsets.UTF_8)),
+ sparseHeaders, Collections.emptyMap());
+ assertEquals(1, sparseHeaders.size());
+ assertEquals(0, sparseHeaders.get(0).getOffset());
+ assertEquals(10, sparseHeaders.get(0).getNumbytes());
+ }
+
+ @Test
+ public void readPax00SparseHeaderMakesNumbytesOptional() throws Exception {
+ final String header = "23 GNU.sparse.offset=0\n"
+ + "24 GNU.sparse.offset=10\n";
+ final List<TarArchiveStructSparse> sparseHeaders = new ArrayList<>();
+ TarUtils.parsePaxHeaders(
+ new ByteArrayInputStream(header.getBytes(StandardCharsets.UTF_8)),
+ sparseHeaders, Collections.emptyMap());
+ assertEquals(2, sparseHeaders.size());
+ assertEquals(0, sparseHeaders.get(0).getOffset());
+ assertEquals(0, sparseHeaders.get(0).getNumbytes());
+ assertEquals(10, sparseHeaders.get(1).getOffset());
+ assertEquals(0, sparseHeaders.get(1).getNumbytes());
+ }
+
+ @Test
+ public void readPax00SparseHeaderRejectsNonNumericOffset() throws
Exception {
+ thrown.expect(IOException.class);
+ thrown.expectMessage(startsWith("Failed to read Paxheader"));
+ final String header = "23 GNU.sparse.offset=a\n"
+ + "26 GNU.sparse.numbytes=10\n";
+ TarUtils.parsePaxHeaders(
+ new ByteArrayInputStream(header.getBytes(StandardCharsets.UTF_8)),
+ null, Collections.emptyMap());
+ }
+
+ @Test
+ public void readPax00SparseHeaderRejectsNonNumericNumbytes() throws
Exception {
+ thrown.expect(IOException.class);
+ thrown.expectMessage(startsWith("Failed to read Paxheader"));
+ final String header = "23 GNU.sparse.offset=0\n"
+ + "26 GNU.sparse.numbytes=1a\n";
+ TarUtils.parsePaxHeaders(
+ new ByteArrayInputStream(header.getBytes(StandardCharsets.UTF_8)),
+ null, Collections.emptyMap());
+ }
+
+ @Test
+ public void readPax00SparseHeaderRejectsNegativeOffset() throws Exception {
+ thrown.expect(IOException.class);
+ thrown.expectMessage(startsWith("Failed to read Paxheader"));
+ final String header = "24 GNU.sparse.offset=-1\n"
+ + "26 GNU.sparse.numbytes=10\n";
+ TarUtils.parsePaxHeaders(
+ new ByteArrayInputStream(header.getBytes(StandardCharsets.UTF_8)),
+ null, Collections.emptyMap());
+ }
+
+ @Test
+ public void readPax00SparseHeaderRejectsNegativeNumbytes() throws
Exception {
+ thrown.expect(IOException.class);
+ thrown.expectMessage(startsWith("Failed to read Paxheader"));
+ final String header = "23 GNU.sparse.offset=0\n"
+ + "26 GNU.sparse.numbytes=-1\n";
+ TarUtils.parsePaxHeaders(
+ new ByteArrayInputStream(header.getBytes(StandardCharsets.UTF_8)),
+ null, Collections.emptyMap());
+ }
+
}