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

commit d0af873e77d16f41edfef7b69da5c8c35c96a650
Author: Stefan Bodewig <bode...@apache.org>
AuthorDate: Sat Jun 5 21:01:22 2021 +0200

    make sure PAX header value fits into the size of the current entry
---
 .../archivers/tar/TarArchiveInputStream.java       |  4 +--
 .../commons/compress/archivers/tar/TarFile.java    |  5 +--
 .../commons/compress/archivers/tar/TarUtils.java   | 42 +++++++++++++++++++++-
 3 files changed, 46 insertions(+), 5 deletions(-)

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 7bf705e..7a07926 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
@@ -567,7 +567,7 @@ public class TarArchiveInputStream extends 
ArchiveInputStream {
     }
 
     private void readGlobalPaxHeaders() throws IOException {
-        globalPaxHeaders = TarUtils.parsePaxHeaders(this, globalSparseHeaders, 
globalPaxHeaders);
+        globalPaxHeaders = TarUtils.parsePaxHeaders(this, globalSparseHeaders, 
globalPaxHeaders, entrySize);
         getNextEntry(); // Get the actual file entry
 
         if (currEntry == null) {
@@ -602,7 +602,7 @@ public class TarArchiveInputStream extends 
ArchiveInputStream {
      */
     private void paxHeaders() throws IOException {
         List<TarArchiveStructSparse> sparseHeaders = new ArrayList<>();
-        final Map<String, String> headers = TarUtils.parsePaxHeaders(this, 
sparseHeaders, globalPaxHeaders);
+        final Map<String, String> headers = TarUtils.parsePaxHeaders(this, 
sparseHeaders, globalPaxHeaders, entrySize);
 
         // for 0.1 PAX Headers
         if (headers.containsKey("GNU.sparse.map")) {
diff --git 
a/src/main/java/org/apache/commons/compress/archivers/tar/TarFile.java 
b/src/main/java/org/apache/commons/compress/archivers/tar/TarFile.java
index af87df5..70e314a 100644
--- a/src/main/java/org/apache/commons/compress/archivers/tar/TarFile.java
+++ b/src/main/java/org/apache/commons/compress/archivers/tar/TarFile.java
@@ -425,7 +425,7 @@ public class TarFile implements Closeable {
         List<TarArchiveStructSparse> sparseHeaders = new ArrayList<>();
         final Map<String, String> headers;
         try (final InputStream input = getInputStream(currEntry)) {
-            headers = TarUtils.parsePaxHeaders(input, sparseHeaders, 
globalPaxHeaders);
+            headers = TarUtils.parsePaxHeaders(input, sparseHeaders, 
globalPaxHeaders, currEntry.getSize());
         }
 
         // for 0.1 PAX Headers
@@ -455,7 +455,8 @@ public class TarFile implements Closeable {
 
     private void readGlobalPaxHeaders() throws IOException {
         try (InputStream input = getInputStream(currEntry)) {
-            globalPaxHeaders = TarUtils.parsePaxHeaders(input, 
globalSparseHeaders, globalPaxHeaders);
+            globalPaxHeaders = TarUtils.parsePaxHeaders(input, 
globalSparseHeaders, globalPaxHeaders,
+                currEntry.getSize());
         }
         getNextTarEntry(); // Get the actual file entry
 
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 1476bba..d809125 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
@@ -685,18 +685,53 @@ public class TarUtils {
      * @param globalPaxHeaders global PAX headers of the tar archive
      * @return map of PAX headers values found inside of the current (local or 
global) PAX headers tar entry.
      * @throws IOException if an I/O error occurs.
+     * @deprecated use the four-arg version instead
      */
+    @Deprecated
     protected static Map<String, String> parsePaxHeaders(final InputStream 
inputStream, final List<TarArchiveStructSparse> sparseHeaders, final 
Map<String, String> globalPaxHeaders)
             throws IOException {
+        return parsePaxHeaders(inputStream, sparseHeaders, globalPaxHeaders, 
-1);
+    }
+
+    /**
+     * For PAX Format 0.0, the sparse headers(GNU.sparse.offset and 
GNU.sparse.numbytes)
+     * may appear multi times, and they look like:
+     *
+     * GNU.sparse.size=size
+     * GNU.sparse.numblocks=numblocks
+     * repeat numblocks times
+     *   GNU.sparse.offset=offset
+     *   GNU.sparse.numbytes=numbytes
+     * end repeat
+     *
+     * For PAX Format 0.1, the sparse headers are stored in a single variable 
: GNU.sparse.map
+     *
+     * GNU.sparse.map
+     *    Map of non-null data chunks. It is a string consisting of 
comma-separated values "offset,size[,offset-1,size-1...]"
+     *
+     * @param inputStream input stream to read keys and values
+     * @param sparseHeaders used in PAX Format 0.0 &amp; 0.1, as it may appear 
multiple times,
+     *                      the sparse headers need to be stored in an array, 
not a map
+     * @param globalPaxHeaders global PAX headers of the tar archive
+     * @param headerSize total size of the PAX header, will be ignored if 
negative
+     * @return map of PAX headers values found inside of the current (local or 
global) PAX headers tar entry.
+     * @throws IOException if an I/O error occurs.
+     * @since 1.21
+     */
+    protected static Map<String, String> parsePaxHeaders(final InputStream 
inputStream,
+            final List<TarArchiveStructSparse> sparseHeaders, final 
Map<String, String> globalPaxHeaders,
+            final long headerSize) throws IOException {
         final Map<String, String> headers = new HashMap<>(globalPaxHeaders);
         Long offset = null;
         // Format is "length keyword=value\n";
+        int totalRead = 0;
         while(true) { // get length
             int ch;
             int len = 0;
             int read = 0;
             while((ch = inputStream.read()) != -1) {
                 read++;
+                totalRead++;
                 if (ch == '\n') { // blank line in header
                     break;
                 }
@@ -705,12 +740,16 @@ public class TarUtils {
                     final ByteArrayOutputStream coll = new 
ByteArrayOutputStream();
                     while((ch = inputStream.read()) != -1) {
                         read++;
+                        totalRead++;
                         if (ch == '='){ // end of keyword
                             final String keyword = 
coll.toString(CharsetNames.UTF_8);
                             // Get rest of entry
                             final int restLen = len - read;
                             if (restLen <= 1) { // only NL
                                 headers.remove(keyword);
+                            } else if (headerSize >= 0 && totalRead + restLen 
> headerSize) {
+                                throw new IOException("Paxheader value size " 
+ restLen
+                                    + " exceeds size of header record");
                             } else {
                                 final byte[] rest = new byte[restLen];
                                 final int got = IOUtils.readFully(inputStream, 
rest);
@@ -721,8 +760,9 @@ public class TarUtils {
                                             + " bytes, read "
                                             + got);
                                 }
+                                totalRead += restLen;
                                 // Drop trailing NL
-                                if (rest[rest.length - 1] != '\n') {
+                                if (rest[restLen - 1] != '\n') {
                                     throw new IOException("Failed to read 
Paxheader."
                                        + "Value should end with a newline");
                                 }

Reply via email to