diff --git a/Tests/images/tiff_tiled_jpeg_oob_read.tif b/Tests/images/tiff_tiled_jpeg_oob_read.tif new file mode 100644 index 00000000000..51cd33e729d Binary files /dev/null and b/Tests/images/tiff_tiled_jpeg_oob_read.tif differ diff --git a/Tests/test_file_libtiff.py b/Tests/test_file_libtiff.py index 30280f9ecf9..97337a82882 100644 --- a/Tests/test_file_libtiff.py +++ b/Tests/test_file_libtiff.py @@ -1028,6 +1028,16 @@ def test_tiled_ycbcr_jpeg_2x2_sampling(self) -> None: with Image.open(infile) as im: assert_image_similar_tofile(im, "Tests/images/flower.jpg", 1.5) + def test_tiled_jpeg_oob_read(self) -> None: + # A tiled TIFF whose libtiff-decoded, JPEG-compressed tile storage + # (TIFFTileSize) is smaller than tile_length rows of the *unpacked* + # rawmode's bytes-per-pixel would require. Decoding must fail safely + # rather than let the row unpacker read past the tile buffer + infile = "Tests/images/tiff_tiled_jpeg_oob_read.tif" + with Image.open(infile) as im: + with pytest.raises(OSError): + im.load() + def test_strip_planar_rgb(self) -> None: # gdal_translate -co TILED=no -co INTERLEAVE=BAND -co COMPRESS=LZW \ # tiff_strip_raw.tif tiff_strip_planar_lzw.tiff diff --git a/src/libImaging/TiffDecode.c b/src/libImaging/TiffDecode.c index 92e23f9c6a2..36039a28167 100644 --- a/src/libImaging/TiffDecode.c +++ b/src/libImaging/TiffDecode.c @@ -352,7 +352,8 @@ _decodeTile( return -1; } - if (tile_bytes_size > ((tile_length * state->bits / planes + 7) / 8) * tile_width) { + if (tile_bytes_size != + ((tile_length * state->bits / planes + 7) / 8) * tile_width) { // If the tile size as expected by LibTiff isn't what we're expecting, abort. // man: TIFFTileSize returns the equivalent size for a tile of data as it // would be returned in a call to TIFFReadTile ...