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 & 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"); }