You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by bo...@apache.org on 2021/05/01 11:48:14 UTC

[commons-compress] branch master updated: COMPRESS-575 harden parser for PAX 1.0 sparse struct blocks

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 2887391  COMPRESS-575 harden parser for PAX 1.0 sparse struct blocks
2887391 is described below

commit 2887391296216e5196921f04bea8cd834843cfe2
Author: Stefan Bodewig <bo...@apache.org>
AuthorDate: Sat May 1 13:47:25 2021 +0200

    COMPRESS-575 harden parser for PAX 1.0 sparse struct blocks
---
 .../commons/compress/archivers/tar/TarUtils.java   |  19 +++-
 .../compress/archivers/tar/TarUtilsTest.java       | 119 +++++++++++++++++++++
 2 files changed, 136 insertions(+), 2 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 eee894e..3ba7a1b 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
@@ -882,14 +882,26 @@ public class TarUtils {
 
         long[] readResult = readLineOfNumberForPax1X(inputStream);
         long sparseHeadersCount = readResult[0];
+        if (sparseHeadersCount < 0) {
+            // overflow while reading number?
+            throw new IOException("Corrupted TAR archive. Negative value in sparse headers block");
+        }
         bytesRead += readResult[1];
         while (sparseHeadersCount-- > 0) {
             readResult = readLineOfNumberForPax1X(inputStream);
-            long sparseOffset = readResult[0];
+            final long sparseOffset = readResult[0];
+            if (sparseOffset < 0) {
+                throw new IOException("Corrupted TAR archive."
+                    + " Sparse header block offset contains negative value");
+            }
             bytesRead += readResult[1];
 
             readResult = readLineOfNumberForPax1X(inputStream);
-            long sparseNumbytes = readResult[0];
+            final long sparseNumbytes = readResult[0];
+            if (sparseNumbytes < 0) {
+                throw new IOException("Corrupted TAR archive."
+                    + " Sparse header block numbytes contains negative value");
+            }
             bytesRead += readResult[1];
             sparseHeaders.add(new TarArchiveStructSparse(sparseOffset, sparseNumbytes));
         }
@@ -918,6 +930,9 @@ public class TarUtils {
             if (number == -1) {
                 throw new IOException("Unexpected EOF when reading parse information of 1.X PAX format");
             }
+            if (number < '0' || number > '9') {
+                throw new IOException("Corrupted TAR archive. Non-numeric value in sparse headers block");
+            }
             result = result * 10 + (number - '0');
         }
         bytesRead += 1;
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 0bca2f0..adb2408 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
@@ -672,4 +672,123 @@ public class TarUtilsTest {
         TarUtils.parsePAX01SparseHeaders(map);
     }
 
+    @Test
+    public void parsePAX1XSparseHeaders() throws Exception {
+        final byte[] header = ("1\n"
+                + "0\n"
+                + "20\n")
+            .getBytes();
+        final byte[] block = new byte[512];
+        System.arraycopy(header, 0, block, 0, header.length);
+        try (ByteArrayInputStream in = new ByteArrayInputStream(block)) {
+            final List<TarArchiveStructSparse> sparse = TarUtils.parsePAX1XSparseHeaders(in, 512);
+            assertEquals(1, sparse.size());
+            assertEquals(0, sparse.get(0).getOffset());
+            assertEquals(20, sparse.get(0).getNumbytes());
+            assertEquals(-1, in.read());
+        }
+    }
+
+    @Test
+    public void parsePAX1XSparseHeadersRejectsIncompleteLastLine() throws Exception {
+        thrown.expect(IOException.class);
+        thrown.expectMessage(startsWith("Unexpected EOF"));
+        final byte[] header = ("1\n"
+                + "0\n"
+                + "20")
+            .getBytes();
+        try (ByteArrayInputStream in = new ByteArrayInputStream(header)) {
+            TarUtils.parsePAX1XSparseHeaders(in, 512);
+        }
+    }
+
+    @Test
+    public void parsePAX1XSparseHeadersRejectsNonNumericNumberOfEntries() throws Exception {
+        thrown.expect(IOException.class);
+        thrown.expectMessage(startsWith("Corrupted TAR archive."));
+        final byte[] header = ("x\n"
+                + "0\n"
+                + "20\n")
+            .getBytes();
+        final byte[] block = new byte[512];
+        System.arraycopy(header, 0, block, 0, header.length);
+        try (ByteArrayInputStream in = new ByteArrayInputStream(block)) {
+            TarUtils.parsePAX1XSparseHeaders(in, 512);
+        }
+    }
+
+    @Test
+    public void parsePAX1XSparseHeadersRejectsNonNumericOffset() throws Exception {
+        thrown.expect(IOException.class);
+        thrown.expectMessage(startsWith("Corrupted TAR archive."));
+        final byte[] header = ("1\n"
+                + "x\n"
+                + "20\n")
+            .getBytes();
+        final byte[] block = new byte[512];
+        System.arraycopy(header, 0, block, 0, header.length);
+        try (ByteArrayInputStream in = new ByteArrayInputStream(block)) {
+            TarUtils.parsePAX1XSparseHeaders(in, 512);
+        }
+    }
+
+    @Test
+    public void parsePAX1XSparseHeadersRejectsNonNumericNumbytes() throws Exception {
+        thrown.expect(IOException.class);
+        thrown.expectMessage(startsWith("Corrupted TAR archive."));
+        final byte[] header = ("1\n"
+                + "0\n"
+                + "2x\n")
+            .getBytes();
+        final byte[] block = new byte[512];
+        System.arraycopy(header, 0, block, 0, header.length);
+        try (ByteArrayInputStream in = new ByteArrayInputStream(block)) {
+            TarUtils.parsePAX1XSparseHeaders(in, 512);
+        }
+    }
+    @Test
+    public void parsePAX1XSparseHeadersRejectsNegativeNumberOfEntries() throws Exception {
+        thrown.expect(IOException.class);
+        thrown.expectMessage(startsWith("Corrupted TAR archive."));
+        final byte[] header = ("111111111111111111111111111111111111111111111111111111111111111\n"
+                + "0\n"
+                + "20\n")
+            .getBytes();
+        final byte[] block = new byte[512];
+        System.arraycopy(header, 0, block, 0, header.length);
+        try (ByteArrayInputStream in = new ByteArrayInputStream(block)) {
+            TarUtils.parsePAX1XSparseHeaders(in, 512);
+        }
+    }
+
+    @Test
+    public void parsePAX1XSparseHeadersRejectsNegativeOffset() throws Exception {
+        thrown.expect(IOException.class);
+        thrown.expectMessage(startsWith("Corrupted TAR archive."));
+        final byte[] header = ("1\n"
+                + "111111111111111111111111111111111111111111111111111111111111111\n"
+                + "20\n")
+            .getBytes();
+        final byte[] block = new byte[512];
+        System.arraycopy(header, 0, block, 0, header.length);
+        try (ByteArrayInputStream in = new ByteArrayInputStream(block)) {
+            TarUtils.parsePAX1XSparseHeaders(in, 512);
+        }
+    }
+
+    @Test
+    public void parsePAX1XSparseHeadersRejectsNegativeNumbytes() throws Exception {
+        thrown.expect(IOException.class);
+        thrown.expectMessage(startsWith("Corrupted TAR archive."));
+        final byte[] header = ("1\n"
+                + "0\n"
+                + "111111111111111111111111111111111111111111111111111111111111111\n")
+            .getBytes();
+        final byte[] block = new byte[512];
+        System.arraycopy(header, 0, block, 0, header.length);
+        try (ByteArrayInputStream in = new ByteArrayInputStream(block)) {
+            TarUtils.parsePAX1XSparseHeaders(in, 512);
+        }
+    }
+
 }