This is an automated email from the ASF dual-hosted git repository.

peterlee 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 b927280  COMPRESS-544 : truncated tar detect
b927280 is described below

commit b92728060ae6b82904d7d1453b05223f2917fc73
Author: PeterAlfredLee <peteralfred...@gmail.com>
AuthorDate: Thu Aug 13 16:30:55 2020 +0800

    COMPRESS-544 : truncated tar detect
    
    TarArchiveInputStream can not detect truncated tar archive when skipping
    bytes. This is a fix for it.
---
 src/changes/changes.xml                            |   4 ++
 .../archivers/tar/TarArchiveInputStream.java       |  50 ++++++++++++++++++---
 .../archivers/tar/TarArchiveInputStreamTest.java   |  18 ++++++++
 .../COMPRESS-544_truncated_in_content.tar          | Bin 0 -> 2067 bytes
 .../COMPRESS-544_truncated_in_padding.tar          | Bin 0 -> 2076 bytes
 5 files changed, 65 insertions(+), 7 deletions(-)

diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 934573d..4301093 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -173,6 +173,10 @@ The <action> type attribute can be add,update,fix,remove.
         Fix for test fails on Windows. The tests are failing because the
         default charset is not UTF-8.
       </action>
+      <action issue="COMPRESS-544" type="fix" date="2020-08-13" due-to="Aditya 
Prasad" dev="PeterLee">
+        TarArchiveInputStream can not detect a truncated tar in skip()
+        and skipRecordPadding().
+      </action>
     </release>
     <release version="1.20" date="2020-02-08"
              description="Release 1.20">
diff --git 
a/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveInputStream.java
 
b/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveInputStream.java
index 5c08ba0..3b99366 100644
--- 
a/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveInputStream.java
+++ 
b/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveInputStream.java
@@ -24,6 +24,7 @@
 package org.apache.commons.compress.archivers.tar;
 
 import java.io.ByteArrayOutputStream;
+import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.nio.charset.StandardCharsets;
@@ -261,8 +262,8 @@ public class TarArchiveInputStream extends 
ArchiveInputStream {
      * @param n
      *            the number of bytes to be skipped.
      * @return the actual number of bytes skipped.
-     * @throws IOException
-     *                if some other I/O error occurs.
+     * @throws IOException if a truncated tar archive is detected
+     *                     or some other I/O error occurs
      */
     @Override
     public long skip(final long n) throws IOException {
@@ -270,13 +271,19 @@ public class TarArchiveInputStream extends 
ArchiveInputStream {
             return 0;
         }
 
+        final long availableOfInputStream = inputStream.available();
         final long available = currEntry.getRealSize() - entryOffset;
-        final long skipped;
+        final long numToSkip = Math.min(n, available);
+        long skipped;
+
         if (!currEntry.isSparse()) {
-            skipped = IOUtils.skip(inputStream, Math.min(n, available));
+            skipped = IOUtils.skip(inputStream, numToSkip);
         } else {
-            skipped = skipSparse(Math.min(n, available));
+            skipped = skipSparse(numToSkip);
         }
+
+        skipped = getActuallySkipped(availableOfInputStream, skipped, 
numToSkip);
+
         count(skipped);
         entryOffset += skipped;
         return skipped;
@@ -436,18 +443,47 @@ public class TarArchiveInputStream extends 
ArchiveInputStream {
 
     /**
      * The last record block should be written at the full size, so skip any
-     * additional space used to fill a record after an entry
+     * additional space used to fill a record after an entry.
+     *
+     * @throws IOException if a truncated tar archive is detected
      */
     private void skipRecordPadding() throws IOException {
         if (!isDirectory() && this.entrySize > 0 && this.entrySize % 
this.recordSize != 0) {
+            final long available = inputStream.available();
             final long numRecords = (this.entrySize / this.recordSize) + 1;
             final long padding = (numRecords * this.recordSize) - 
this.entrySize;
-            final long skipped = IOUtils.skip(inputStream, padding);
+            long skipped = IOUtils.skip(inputStream, padding);
+
+            skipped = getActuallySkipped(available, skipped, padding);
+
             count(skipped);
         }
     }
 
     /**
+     * For FileInputStream, the skip always return the number you input, so we
+     * need the available bytes to determine how many bytes are actually 
skipped
+     *
+     * @param available available bytes returned by inputStream.available()
+     * @param skipped   skipped bytes returned by inputStream.skip()
+     * @param expected  bytes expected to skip
+     * @return number of bytes actually skipped
+     * @throws IOException if a truncated tar archive is detected
+     */
+    private long getActuallySkipped(final long available, final long skipped, 
final long expected) throws IOException {
+        long actuallySkipped = skipped;
+        if (inputStream instanceof FileInputStream) {
+            actuallySkipped = Math.min(skipped, available);
+        }
+
+        if (actuallySkipped != expected) {
+            throw new IOException("Truncated TAR archive");
+        }
+
+        return actuallySkipped;
+    }
+
+    /**
      * Get the next entry in this tar archive as longname data.
      *
      * @return The next entry in the archive as longname data, or null.
diff --git 
a/src/test/java/org/apache/commons/compress/archivers/tar/TarArchiveInputStreamTest.java
 
b/src/test/java/org/apache/commons/compress/archivers/tar/TarArchiveInputStreamTest.java
index 8218af5..924542f 100644
--- 
a/src/test/java/org/apache/commons/compress/archivers/tar/TarArchiveInputStreamTest.java
+++ 
b/src/test/java/org/apache/commons/compress/archivers/tar/TarArchiveInputStreamTest.java
@@ -442,6 +442,24 @@ public class TarArchiveInputStreamTest extends 
AbstractTestCase {
         }
     }
 
+    @Test(expected = IOException.class)
+    public void testParseTarTruncatedInPadding() throws IOException {
+        try (FileInputStream in = new 
FileInputStream(getFile("./COMPRESS-544_truncated_in_padding.tar"));
+             TarArchiveInputStream archive = new TarArchiveInputStream(in)) {
+            while (archive.getNextTarEntry() != null) {
+            }
+        }
+    }
+
+    @Test(expected = IOException.class)
+    public void testParseTarTruncatedInContent() throws IOException {
+        try (FileInputStream in = new 
FileInputStream(getFile("./COMPRESS-544_truncated_in_content.tar"));
+             TarArchiveInputStream archive = new TarArchiveInputStream(in)) {
+            while (archive.getNextTarEntry() != null) {
+            }
+        }
+    }
+
     private TarArchiveInputStream getTestStream(final String name) {
         return new TarArchiveInputStream(
                 TarArchiveInputStreamTest.class.getResourceAsStream(name));
diff --git a/src/test/resources/COMPRESS-544_truncated_in_content.tar 
b/src/test/resources/COMPRESS-544_truncated_in_content.tar
new file mode 100644
index 0000000..bfcfb9b
Binary files /dev/null and 
b/src/test/resources/COMPRESS-544_truncated_in_content.tar differ
diff --git a/src/test/resources/COMPRESS-544_truncated_in_padding.tar 
b/src/test/resources/COMPRESS-544_truncated_in_padding.tar
new file mode 100644
index 0000000..94caf3f
Binary files /dev/null and 
b/src/test/resources/COMPRESS-544_truncated_in_padding.tar differ

Reply via email to