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 5c5f8a8 COMPRESS-569 ensure sizes read for archive entries are non-negative 5c5f8a8 is described below commit 5c5f8a89e91b95c0ba984549b5804289f55b8200 Author: Stefan Bodewig <bode...@apache.org> AuthorDate: Sat Mar 6 20:32:00 2021 +0100 COMPRESS-569 ensure sizes read for archive entries are non-negative --- src/changes/changes.xml | 7 +++++++ .../compress/archivers/ar/ArArchiveEntry.java | 3 +++ .../archivers/ar/ArArchiveInputStream.java | 4 ++++ .../compress/archivers/sevenz/SevenZFile.java | 3 +++ .../compress/archivers/tar/TarArchiveEntry.java | 3 +++ .../commons/compress/archivers/zip/ZipFile.java | 24 ++++++++++++++++++---- 6 files changed, 40 insertions(+), 4 deletions(-) diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 86bd225..06b3cff 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -317,6 +317,13 @@ The <action> type attribute can be add,update,fix,remove. <action type="update" due-to="Dependabot" dev="ggregory"> Bump mockito-core from 1.10.19 to 3.8.0, #161, #170. </action> + <action issue="COMPRESS-569" type="fix" date="2021-03-06"> + Checked the sizes read for archive entries and reject archives + as broken with negative entry sizes. + + Fixes an infinite loop in the new TarFile class but affects + several formats. + </action> </release> <release version="1.20" date="2020-02-08" description="Release 1.20 (Java 7)"> diff --git a/src/main/java/org/apache/commons/compress/archivers/ar/ArArchiveEntry.java b/src/main/java/org/apache/commons/compress/archivers/ar/ArArchiveEntry.java index ea0e753..e5eeab4 100644 --- a/src/main/java/org/apache/commons/compress/archivers/ar/ArArchiveEntry.java +++ b/src/main/java/org/apache/commons/compress/archivers/ar/ArArchiveEntry.java @@ -104,6 +104,9 @@ public class ArArchiveEntry implements ArchiveEntry { public ArArchiveEntry(final String name, final long length, final int userId, final int groupId, final int mode, final long lastModified) { this.name = name; + if (length < 0) { + throw new IllegalArgumentException("length must not be negative"); + } this.length = length; this.userId = userId; this.groupId = groupId; diff --git a/src/main/java/org/apache/commons/compress/archivers/ar/ArArchiveInputStream.java b/src/main/java/org/apache/commons/compress/archivers/ar/ArArchiveInputStream.java index c1b46de..b696555 100644 --- a/src/main/java/org/apache/commons/compress/archivers/ar/ArArchiveInputStream.java +++ b/src/main/java/org/apache/commons/compress/archivers/ar/ArArchiveInputStream.java @@ -171,6 +171,10 @@ public class ArArchiveInputStream extends ArchiveInputStream { entryOffset += nameLen; } + if (len < 0) { + throw new IOException("broken archive, entry with negative size"); + } + currentEntry = new ArArchiveEntry(temp, len, asInt(metaData, USER_ID_OFFSET, USER_ID_LEN, true), asInt(metaData, GROUP_ID_OFFSET, GROUP_ID_LEN, true), diff --git a/src/main/java/org/apache/commons/compress/archivers/sevenz/SevenZFile.java b/src/main/java/org/apache/commons/compress/archivers/sevenz/SevenZFile.java index 5c34386..ba6e719 100644 --- a/src/main/java/org/apache/commons/compress/archivers/sevenz/SevenZFile.java +++ b/src/main/java/org/apache/commons/compress/archivers/sevenz/SevenZFile.java @@ -1096,6 +1096,9 @@ public class SevenZFile implements Closeable { entryAtIndex.setHasCrc(archive.subStreamsInfo.hasCrc.get(nonEmptyFileCounter)); entryAtIndex.setCrcValue(archive.subStreamsInfo.crcs[nonEmptyFileCounter]); entryAtIndex.setSize(archive.subStreamsInfo.unpackSizes[nonEmptyFileCounter]); + if (entryAtIndex.getSize() < 0) { + throw new IOException("broken archive, entry with negative size"); + } ++nonEmptyFileCounter; } else { entryAtIndex.setDirectory(isEmptyFile == null || !isEmptyFile.get(emptyFileCounter)); diff --git a/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveEntry.java b/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveEntry.java index 2e81a91..7522ad9 100644 --- a/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveEntry.java +++ b/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveEntry.java @@ -1538,6 +1538,9 @@ public class TarArchiveEntry implements ArchiveEntry, TarConstants, EntryStreamO groupId = (int) parseOctalOrBinary(header, offset, GIDLEN, lenient); offset += GIDLEN; size = TarUtils.parseOctalOrBinary(header, offset, SIZELEN); + if (size < 0) { + throw new IOException("broken archive, entry with negative size"); + } offset += SIZELEN; modTime = parseOctalOrBinary(header, offset, MODTIMELEN, lenient); offset += MODTIMELEN; diff --git a/src/main/java/org/apache/commons/compress/archivers/zip/ZipFile.java b/src/main/java/org/apache/commons/compress/archivers/zip/ZipFile.java index c8e366b..9adb8b1 100644 --- a/src/main/java/org/apache/commons/compress/archivers/zip/ZipFile.java +++ b/src/main/java/org/apache/commons/compress/archivers/zip/ZipFile.java @@ -775,10 +775,18 @@ public class ZipFile implements Closeable { ze.setCrc(ZipLong.getValue(cfhBuf, off)); off += WORD; - ze.setCompressedSize(ZipLong.getValue(cfhBuf, off)); + long size = ZipLong.getValue(cfhBuf, off); + if (size < 0) { + throw new IOException("broken archive, entry with negative compressed size"); + } + ze.setCompressedSize(size); off += WORD; - ze.setSize(ZipLong.getValue(cfhBuf, off)); + size = ZipLong.getValue(cfhBuf, off); + if (size < 0) { + throw new IOException("broken archive, entry with negative size"); + } + ze.setSize(size); off += WORD; final int fileNameLen = ZipShort.getValue(cfhBuf, off); @@ -858,13 +866,21 @@ public class ZipFile implements Closeable { hasDiskStart); if (hasUncompressedSize) { - ze.setSize(z64.getSize().getLongValue()); + final long size = z64.getSize().getLongValue(); + if (size < 0) { + throw new IOException("broken archive, entry with negative size"); + } + ze.setSize(size); } else if (hasCompressedSize) { z64.setSize(new ZipEightByteInteger(ze.getSize())); } if (hasCompressedSize) { - ze.setCompressedSize(z64.getCompressedSize().getLongValue()); + final long size = z64.getCompressedSize().getLongValue(); + if (size < 0) { + throw new IOException("broken archive, entry with negative compressed size"); + } + ze.setCompressedSize(size); } else if (hasUncompressedSize) { z64.setCompressedSize(new ZipEightByteInteger(ze.getCompressedSize())); }