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 <bode...@apache.org>
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());
+    }
+
 }

Reply via email to