diff --git a/PIL/Image.py b/PIL/Image.py index 9936aad46..6768b3eb2 100644 --- a/PIL/Image.py +++ b/PIL/Image.py @@ -36,6 +36,8 @@ logger = logging.getLogger(__name__) class DecompressionBombWarning(RuntimeWarning): pass +class DecompressionBombError(Exception): + pass class _imaging_not_installed(object): # module placeholder @@ -2379,6 +2381,12 @@ def _decompression_bomb_check(size): pixels = size[0] * size[1] + if pixels > 2 * MAX_IMAGE_PIXELS: + raise DecompressionBombError( + "Image size (%d pixels) exceeds limit of %d pixels, " + "could be decompression bomb DOS attack." % + (pixels, 2* MAX_IMAGE_PIXELS)) + if pixels > MAX_IMAGE_PIXELS: warnings.warn( "Image size (%d pixels) exceeds limit of %d pixels, " diff --git a/Tests/test_decompression_bomb.py b/Tests/test_decompression_bomb.py index 5598fd9c8..62bca6d10 100644 --- a/Tests/test_decompression_bomb.py +++ b/Tests/test_decompression_bomb.py @@ -29,15 +29,21 @@ class TestDecompressionBomb(PillowTestCase): Image.open(TEST_FILE) def test_warning(self): - # Arrange - # Set limit to a low, easily testable value - Image.MAX_IMAGE_PIXELS = 10 - self.assertEqual(Image.MAX_IMAGE_PIXELS, 10) + # Set limit to trigger warning on the test file + Image.MAX_IMAGE_PIXELS = 128 * 128 -1 + self.assertEqual(Image.MAX_IMAGE_PIXELS, 128 * 128 - 1) - # Act / Assert self.assert_warning(Image.DecompressionBombWarning, lambda: Image.open(TEST_FILE)) + def test_exception(self): + # Set limit to trigger exception on the test file + Image.MAX_IMAGE_PIXELS = 64 * 128 -1 + self.assertEqual(Image.MAX_IMAGE_PIXELS, 64 * 128 - 1) + + self.assertRaises(Image.DecompressionBombError, + lambda: Image.open(TEST_FILE)) + class TestDecompressionCrop(PillowTestCase): def setUp(self): @@ -54,5 +60,6 @@ class TestDecompressionCrop(PillowTestCase): self.assert_warning(Image.DecompressionBombWarning, lambda: self.src.crop(box)) + if __name__ == '__main__': unittest.main()