diff --git a/Tests/test_file_libtiff.py b/Tests/test_file_libtiff.py index a84b557cf09..5bd5369c27a 100644 --- a/Tests/test_file_libtiff.py +++ b/Tests/test_file_libtiff.py @@ -395,6 +395,26 @@ def test_non_bytes( with pytest.raises(ValueError, match="Incorrect tag value type"): im.save(out, tiffinfo=ifd) + @pytest.mark.parametrize( + "tiffinfo", + ( + {TiffImagePlugin.IMAGEWIDTH: 1 << 27}, + {TiffImagePlugin.SAMPLESPERPIXEL: 3}, + ), + ) + def test_geometry_tags( + self, tiffinfo: dict[int, int], monkeypatch: pytest.MonkeyPatch, tmp_path: Path + ) -> None: + # libtiff reads a scanline of the size described by the IMAGEWIDTH, + # SAMPLESPERPIXEL and BITSPERSAMPLE tags from a buffer that only holds one + # row of the image, so a tag describing a larger row must be rejected. + monkeypatch.setattr(TiffImagePlugin, "WRITE_LIBTIFF", True) + + out = tmp_path / "temp.tif" + im = hopper("L") + with pytest.raises(OSError, match="encoder error -8"): + im.save(out, tiffinfo=tiffinfo) + def test_inknames_tag( self, monkeypatch: pytest.MonkeyPatch, tmp_path: Path ) -> None: diff --git a/src/libImaging/TiffDecode.c b/src/libImaging/TiffDecode.c index daf7620a8cc..f985c604239 100644 --- a/src/libImaging/TiffDecode.c +++ b/src/libImaging/TiffDecode.c @@ -792,6 +792,14 @@ ImagingLibTiffEncode(Imaging im, ImagingCodecState state, UINT8 *buffer, int byt TIFF *tiff = clientstate->tiff; if (state->state == 0) { + // state->buffer holds one row of the image, but TIFFWriteScanline reads + // a scanline of the size described by the IMAGEWIDTH, SAMPLESPERPIXEL + // and BITSPERSAMPLE tags, so these must not describe a larger row. + if (TIFFScanlineSize64(tiff) > (uint64_t)state->bytes) { + state->errcode = IMAGING_CODEC_CONFIG; + return -1; + } + // Encoding line by line while (state->y < state->ysize) { state->shuffle(