diff --git a/Tests/images/tiff_overflow_rows_per_strip.tif b/Tests/images/tiff_overflow_rows_per_strip.tif new file mode 100644 index 000000000..979c7f176 Binary files /dev/null and b/Tests/images/tiff_overflow_rows_per_strip.tif differ diff --git a/Tests/test_file_libtiff.py b/Tests/test_file_libtiff.py index ea73a7ad5..0f5993467 100644 --- a/Tests/test_file_libtiff.py +++ b/Tests/test_file_libtiff.py @@ -870,3 +870,13 @@ class TestFileLibTiff(LibTiffTestCase): out.seek(0) with Image.open(out) as im: im.load() + + def test_realloc_overflow(self): + TiffImagePlugin.READ_LIBTIFF = True + with Image.open("Tests/images/tiff_overflow_rows_per_strip.tif") as im: + with self.assertRaises(IOError) as e: + im.load() + + # Assert that the error code is IMAGING_CODEC_MEMORY + self.assertEqual(str(e.exception), "-9") + TiffImagePlugin.READ_LIBTIFF = False diff --git a/src/libImaging/TiffDecode.c b/src/libImaging/TiffDecode.c index 7592f7f39..c3df1174e 100644 --- a/src/libImaging/TiffDecode.c +++ b/src/libImaging/TiffDecode.c @@ -353,16 +353,18 @@ int ImagingLibTiffDecode(Imaging im, ImagingCodecState state, UINT8* buffer, Py_ // We could use TIFFTileSize, but for YCbCr data it returns subsampled data size row_byte_size = (tile_width * state->bits + 7) / 8; - state->bytes = row_byte_size * tile_length; - /* overflow check for malloc */ - if (state->bytes > INT_MAX - 1) { + /* overflow check for realloc */ + if (INT_MAX / row_byte_size < tile_length) { state->errcode = IMAGING_CODEC_MEMORY; TIFFClose(tiff); return -1; } + + state->bytes = row_byte_size * tile_length; /* realloc to fit whole tile */ + /* malloc check above */ new_data = realloc (state->buffer, state->bytes); if (!new_data) { state->errcode = IMAGING_CODEC_MEMORY; @@ -415,11 +417,20 @@ int ImagingLibTiffDecode(Imaging im, ImagingCodecState state, UINT8* buffer, Py_ // We could use TIFFStripSize, but for YCbCr data it returns subsampled data size row_byte_size = (state->xsize * state->bits + 7) / 8; + + /* overflow check for realloc */ + if (INT_MAX / row_byte_size < rows_per_strip) { + state->errcode = IMAGING_CODEC_MEMORY; + TIFFClose(tiff); + return -1; + } + state->bytes = rows_per_strip * row_byte_size; TRACE(("StripSize: %d \n", state->bytes)); /* realloc to fit whole strip */ + /* malloc check above */ new_data = realloc (state->buffer, state->bytes); if (!new_data) { state->errcode = IMAGING_CODEC_MEMORY;