From 42ee7d1c3e3e5d7d7384f011986caeaa4dc256a5 Mon Sep 17 00:00:00 2001 From: dajiaohuang Date: Sun, 25 Oct 2026 11:39:28 +0800 Subject: [PATCH] [IMAGING-387] Reject overflowing TIFF strip sizes Validate the long strip byte count through Allocator.check before passing it to decompression. Add regressions for oversized and valid strip sizes. --- .../formats/tiff/datareaders/DataReaderStrips.java | 12 +++++++++--- .../tiff/datareaders/DataReaderStripsTest.java | 13 +++++++++++++ 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/apache/commons/imaging/formats/tiff/datareaders/DataReaderStrips.java b/src/main/java/org/apache/commons/imaging/formats/tiff/datareaders/DataReaderStrips.java index 2ca073cf39..a5929cd827 100644 --- a/src/main/java/org/apache/commons/imaging/formats/tiff/datareaders/DataReaderStrips.java +++ b/src/main/java/org/apache/commons/imaging/formats/tiff/datareaders/DataReaderStrips.java @@ -244,6 +244,10 @@ private void interpretStrip(final ImageBuilder imageBuilder, final byte[] bytes, } } + static int checkStripSize(final long bytesPerStrip) { + return Allocator.check(bytesPerStrip, Byte.BYTES); + } + @Override public ImageBuilder readImageData(final Rectangle subImageSpecification, final boolean hasAlpha, final boolean isAlphaPreMultiplied) throws IOException, ImagingException { @@ -297,6 +301,7 @@ public ImageBuilder readImageData(final Rectangle subImageSpecification, final b final long rowsInThisStrip = Math.min(rowsRemaining, rowsPerStripLong); final long bytesPerRow = (bitsPerPixel * width + 7) / 8; final long bytesPerStrip = rowsInThisStrip * bytesPerRow; + final int expectedSize = checkStripSize(bytesPerStrip); final long pixelsPerStrip = rowsInThisStrip * width; final byte[] compressed = imageData.getImageData(strip).getData(); @@ -308,7 +313,7 @@ public ImageBuilder readImageData(final Rectangle subImageSpecification, final b continue; } - final byte[] decompressed = decompress(compressed, compression, (int) bytesPerStrip, width, (int) rowsInThisStrip); + final byte[] decompressed = decompress(compressed, compression, expectedSize, width, (int) rowsInThisStrip); interpretStrip(workingBuilder, decompressed, (int) pixelsPerStrip, yLimit); } @@ -327,13 +332,14 @@ public ImageBuilder readImageData(final Rectangle subImageSpecification, final b final long rowsInThisStrip = Math.min(rowsRemaining, rowsPerStripLong); final long bytesPerRow = (bitsPerPixel * width + 7) / 8; final long bytesPerStrip = rowsInThisStrip * bytesPerRow; + final int expectedSize = checkStripSize(bytesPerStrip); final long pixelsPerStrip = rowsInThisStrip * width; - final byte[] b = Allocator.byteArray((int) bytesPerStrip); + final byte[] b = Allocator.byteArray(expectedSize); for (int iPlane = 0; iPlane < 3; iPlane++) { final int planeStrip = iPlane * nStripsInPlane + strip; final byte[] compressed = imageData.getImageData(planeStrip).getData(); - final byte[] decompressed = decompress(compressed, compression, (int) bytesPerStrip, width, (int) rowsInThisStrip); + final byte[] decompressed = decompress(compressed, compression, expectedSize, width, (int) rowsInThisStrip); int index = iPlane; for (final byte element : decompressed) { b[index] = element; diff --git a/src/test/java/org/apache/commons/imaging/formats/tiff/datareaders/DataReaderStripsTest.java b/src/test/java/org/apache/commons/imaging/formats/tiff/datareaders/DataReaderStripsTest.java index b5862e8e5d..ed8db3ecab 100644 --- a/src/test/java/org/apache/commons/imaging/formats/tiff/datareaders/DataReaderStripsTest.java +++ b/src/test/java/org/apache/commons/imaging/formats/tiff/datareaders/DataReaderStripsTest.java @@ -17,11 +17,24 @@ package org.apache.commons.imaging.formats.tiff.datareaders; import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import org.apache.commons.imaging.common.AllocationRequestException; import org.apache.commons.imaging.formats.tiff.constants.TiffPlanarConfiguration; import org.junit.jupiter.api.Test; class DataReaderStripsTest { + @Test + void testCheckStripSizeRejectsLongThatWouldOverflowInt() { + assertThrows(AllocationRequestException.class, () -> DataReaderStrips.checkStripSize(28_994_135_625L)); + } + + @Test + void testCheckStripSizeReturnsIntForValidRequest() { + assertEquals(4096, DataReaderStrips.checkStripSize(4096)); + } + @Test void testApplyPredictor() { final int[] bitsPerPixel = { 1, 2, 3 };