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