diff --git a/Tests/images/crash-0da013a13571cc8eb457a39fee8db18f8a3c7127.tif b/Tests/images/crash-0da013a13571cc8eb457a39fee8db18f8a3c7127.tif new file mode 100644 index 00000000000..6e4e9b9caa5 Binary files /dev/null and b/Tests/images/crash-0da013a13571cc8eb457a39fee8db18f8a3c7127.tif differ diff --git a/Tests/images/crash-74d2a78403a5a59db1fb0a2b8735ac068a75f6e3.tif b/Tests/images/crash-74d2a78403a5a59db1fb0a2b8735ac068a75f6e3.tif new file mode 100644 index 00000000000..053e4e4e952 Binary files /dev/null and b/Tests/images/crash-74d2a78403a5a59db1fb0a2b8735ac068a75f6e3.tif differ diff --git a/Tests/images/crash-81154a65438ba5aaeca73fd502fa4850fbde60f8.tif b/Tests/images/crash-81154a65438ba5aaeca73fd502fa4850fbde60f8.tif new file mode 100644 index 00000000000..56e82419968 Binary files /dev/null and b/Tests/images/crash-81154a65438ba5aaeca73fd502fa4850fbde60f8.tif differ diff --git a/Tests/test_tiff_crashes.py b/Tests/test_tiff_crashes.py index ae4d0f1006e..6cdb8e44da2 100644 --- a/Tests/test_tiff_crashes.py +++ b/Tests/test_tiff_crashes.py @@ -33,6 +33,9 @@ "Tests/images/crash-86214e58da443d2b80820cff9677a38a33dcbbca.tif", "Tests/images/crash-f46f5b2f43c370fe65706c11449f567ecc345e74.tif", "Tests/images/crash-63b1dffefc8c075ddc606c0a2f5fdc15ece78863.tif", + "Tests/images/crash-74d2a78403a5a59db1fb0a2b8735ac068a75f6e3.tif", + "Tests/images/crash-81154a65438ba5aaeca73fd502fa4850fbde60f8.tif", + "Tests/images/crash-0da013a13571cc8eb457a39fee8db18f8a3c7127.tif", ], ) @pytest.mark.filterwarnings("ignore:Possibly corrupt EXIF data") diff --git a/src/PIL/TiffImagePlugin.py b/src/PIL/TiffImagePlugin.py index 24821d1304b..9d821dcf965 100644 --- a/src/PIL/TiffImagePlugin.py +++ b/src/PIL/TiffImagePlugin.py @@ -1250,6 +1250,10 @@ def _setup(self): if bps_count > len(bps_tuple) and len(bps_tuple) == 1: bps_tuple = bps_tuple * bps_count + samplesPerPixel = self.tag_v2.get(SAMPLESPERPIXEL, 1) + if len(bps_tuple) != samplesPerPixel: + raise SyntaxError("unknown data organization") + # mode: check photometric interpretation and bits per pixel key = ( self.tag_v2.prefix, diff --git a/src/libImaging/TiffDecode.c b/src/libImaging/TiffDecode.c index 26197c8f63c..bae3afff4c1 100644 --- a/src/libImaging/TiffDecode.c +++ b/src/libImaging/TiffDecode.c @@ -265,7 +265,7 @@ _decodeAsRGBA(Imaging im, ImagingCodecState state, TIFF *tiff) { ret = TIFFGetFieldDefaulted(tiff, TIFFTAG_ROWSPERSTRIP, &rows_per_block); } - if (ret != 1) { + if (ret != 1 || rows_per_block==(UINT32)(-1)) { rows_per_block = state->ysize; } @@ -281,17 +281,6 @@ _decodeAsRGBA(Imaging im, ImagingCodecState state, TIFF *tiff) { img.req_orientation = ORIENTATION_TOPLEFT; img.col_offset = 0; - if (state->xsize != img.width || state->ysize != img.height) { - TRACE( - ("Inconsistent Image Error: %d =? %d, %d =? %d", - state->xsize, - img.width, - state->ysize, - img.height)); - state->errcode = IMAGING_CODEC_BROKEN; - goto decodergba_err; - } - /* overflow check for row byte size */ if (INT_MAX / 4 < img.width) { state->errcode = IMAGING_CODEC_MEMORY; @@ -462,7 +451,7 @@ _decodeStrip(Imaging im, ImagingCodecState state, TIFF *tiff, int planes, Imagin UINT8 *new_data; UINT32 rows_per_strip; int ret; - tsize_t strip_size, row_byte_size; + tsize_t strip_size, row_byte_size, unpacker_row_byte_size; ret = TIFFGetField(tiff, TIFFTAG_ROWSPERSTRIP, &rows_per_strip); if (ret != 1 || rows_per_strip==(UINT32)(-1)) { @@ -482,7 +471,8 @@ _decodeStrip(Imaging im, ImagingCodecState state, TIFF *tiff, int planes, Imagin return -1; } - if (strip_size > ((state->xsize * state->bits / planes + 7) / 8) * rows_per_strip) { + unpacker_row_byte_size = (state->xsize * state->bits / planes + 7) / 8; + if (strip_size > (unpacker_row_byte_size * rows_per_strip)) { // If the strip size as expected by LibTiff isn't what we're expecting, abort. // man: TIFFStripSize returns the equivalent size for a strip of data as it would be returned in a // call to TIFFReadEncodedStrip ... @@ -496,7 +486,9 @@ _decodeStrip(Imaging im, ImagingCodecState state, TIFF *tiff, int planes, Imagin row_byte_size = TIFFScanlineSize(tiff); - if (row_byte_size == 0 || row_byte_size > strip_size) { + // if the unpacker calculated row size is > row byte size, (at least) the last + // row of the strip will have a read buffer overflow. + if (row_byte_size == 0 || unpacker_row_byte_size > row_byte_size) { state->errcode = IMAGING_CODEC_BROKEN; return -1; } @@ -559,6 +551,7 @@ ImagingLibTiffDecode( uint16 planarconfig = 0; int planes = 1; ImagingShuffler unpackers[4]; + UINT32 img_width, img_height; memset(unpackers, 0, sizeof(ImagingShuffler) * 4); @@ -655,6 +648,20 @@ ImagingLibTiffDecode( } } + TIFFGetField(tiff, TIFFTAG_IMAGEWIDTH, &img_width); + TIFFGetField(tiff, TIFFTAG_IMAGELENGTH, &img_height); + + if (state->xsize != img_width || state->ysize != img_height) { + TRACE( + ("Inconsistent Image Error: %d =? %d, %d =? %d", + state->xsize, + img_width, + state->ysize, + img_height)); + state->errcode = IMAGING_CODEC_BROKEN; + goto decode_err; + } + TIFFGetField(tiff, TIFFTAG_PHOTOMETRIC, &photometric); TIFFGetField(tiff, TIFFTAG_COMPRESSION, &compression);