From 2f169c27bf0252229c6a96ea18d9b6f9348c6b9e Mon Sep 17 00:00:00 2001
From: Marian Koncek <mkoncek@redhat.com>
Date: Fri, 5 Oct 2018 13:10:18 +0200
Subject: [PATCH] COMPRESS-463 throw exception when detecting a truncated
 stored entry

---
 .../archivers/zip/ZipArchiveInputStream.java  |  3 +-
 .../zip/Maven221MultiVolumeTest.java          |  7 ++
 .../zip/ZipArchiveInputStreamTest.java        | 69 +++++++++++++++++++
 3 files changed, 78 insertions(+), 1 deletion(-)

diff --git a/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveInputStream.java b/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveInputStream.java
index 729d92e..4c239ec 100644
--- a/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveInputStream.java
+++ b/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveInputStream.java
@@ -523,7 +523,8 @@ public class ZipArchiveInputStream extends ArchiveInputStream implements InputSt
             buf.position(0);
             final int l = in.read(buf.array());
             if (l == -1) {
-                return -1;
+                buf.limit(0);
+                throw new IOException("Truncated ZIP file");
             }
             buf.limit(l);
 
diff --git a/src/test/java/org/apache/commons/compress/archivers/zip/Maven221MultiVolumeTest.java b/src/test/java/org/apache/commons/compress/archivers/zip/Maven221MultiVolumeTest.java
index c28f3de..0a905e3 100644
--- a/src/test/java/org/apache/commons/compress/archivers/zip/Maven221MultiVolumeTest.java
+++ b/src/test/java/org/apache/commons/compress/archivers/zip/Maven221MultiVolumeTest.java
@@ -96,6 +96,13 @@ public class Maven221MultiVolumeTest {
                 assertEquals("Truncated ZIP file", e.getMessage());
             }
 
+            try {
+                zi.read(buffer);
+                fail("shouldn't be able to read from truncated entry after exception");
+            } catch (final IOException e) {
+                assertEquals("Truncated ZIP file", e.getMessage());
+            }
+
             // and now we get another entry, which should also yield
             // an exception
             try {
diff --git a/src/test/java/org/apache/commons/compress/archivers/zip/ZipArchiveInputStreamTest.java b/src/test/java/org/apache/commons/compress/archivers/zip/ZipArchiveInputStreamTest.java
index 5d1cdb1..5bf003b 100644
--- a/src/test/java/org/apache/commons/compress/archivers/zip/ZipArchiveInputStreamTest.java
+++ b/src/test/java/org/apache/commons/compress/archivers/zip/ZipArchiveInputStreamTest.java
@@ -340,6 +340,75 @@ public class ZipArchiveInputStreamTest {
         }
     }
 
+    @Test
+    public void singleByteReadThrowsAtEofForCorruptedStoredEntry() throws Exception {
+        byte[] content;
+        try (FileInputStream fs = new FileInputStream(getFile("COMPRESS-264.zip"))) {
+            content = IOUtils.toByteArray(fs);
+        }
+        // make size much bigger than entry's real size
+        for (int i = 17; i < 26; i++) {
+            content[i] = (byte) 0xff;
+        }
+        try (ByteArrayInputStream in = new ByteArrayInputStream(content);
+             ZipArchiveInputStream archive = new ZipArchiveInputStream(in)) {
+            ArchiveEntry e = archive.getNextEntry();
+            try {
+                IOUtils.toByteArray(archive);
+                fail("expected exception");
+            } catch (IOException ex) {
+                assertEquals("Truncated ZIP file", ex.getMessage());
+            }
+            try {
+                archive.read();
+                fail("expected exception");
+            } catch (IOException ex) {
+                assertEquals("Truncated ZIP file", ex.getMessage());
+            }
+            try {
+                archive.read();
+                fail("expected exception");
+            } catch (IOException ex) {
+                assertEquals("Truncated ZIP file", ex.getMessage());
+            }
+        }
+    }
+
+    @Test
+    public void multiByteReadThrowsAtEofForCorruptedStoredEntry() throws Exception {
+        byte[] content;
+        try (FileInputStream fs = new FileInputStream(getFile("COMPRESS-264.zip"))) {
+            content = IOUtils.toByteArray(fs);
+        }
+        // make size much bigger than entry's real size
+        for (int i = 17; i < 26; i++) {
+            content[i] = (byte) 0xff;
+        }
+        byte[] buf = new byte[2];
+        try (ByteArrayInputStream in = new ByteArrayInputStream(content);
+             ZipArchiveInputStream archive = new ZipArchiveInputStream(in)) {
+            ArchiveEntry e = archive.getNextEntry();
+            try {
+                IOUtils.toByteArray(archive);
+                fail("expected exception");
+            } catch (IOException ex) {
+                assertEquals("Truncated ZIP file", ex.getMessage());
+            }
+            try {
+                archive.read(buf);
+                fail("expected exception");
+            } catch (IOException ex) {
+                assertEquals("Truncated ZIP file", ex.getMessage());
+            }
+            try {
+                archive.read(buf);
+                fail("expected exception");
+            } catch (IOException ex) {
+                assertEquals("Truncated ZIP file", ex.getMessage());
+            }
+        }
+    }
+
     private static byte[] readEntry(ZipArchiveInputStream zip, ZipArchiveEntry zae) throws IOException {
         final int len = (int)zae.getSize();
         final byte[] buff = new byte[len];
-- 
2.17.1

