zimeon / iiif

IIIF Image API reference implementation and Python library
GNU General Public License v3.0
55 stars 15 forks source link

Help explain/control large image warnings from Pillow #11

Closed zimeon closed 8 years ago

zimeon commented 9 years ago

While working with iiif_static.py to generate tiles, @jgreidy ran into a DecompressionBombWarning with a large image:

Create directories. /tmp/image-to-iiif-s3/78/203936 Local copy of image. Making iiif tiles. /usr/lib64/python2.6/site-packages/PIL/Image.py:2261: DecompressionBombWarning: Image size (166109750 pixels) exceeds limit of 89478485 pixels, could be decompression bomb DOS attack. DecompressionBombWarning)

The code still seemed to work and produce good tiles

zimeon commented 9 years ago

Discussion of handling large images and giving warnings at https://github.com/python-pillow/Pillow/issues/515

zimeon commented 9 years ago

Warning is described in the Pillow docs at http://pillow.readthedocs.org/en/latest/reference/Image.html but there is no mention of what the size limit is or how to change it:

To protect against potential DOS attacks caused by “decompression bombs” (i.e. malicious files which decompress into a huge amount of data and are designed to crash or cause disruption by using up a lot of memory), Pillow will issue a DecompressionBombWarning if the image is over a certain limit. If desired, the warning can be turned into an error with warnings.simplefilter('error', Image.DecompressionBombWarning) or suppressed entirely with warnings.simplefilter('ignore', Image.DecompressionBombWarning). See also the logging documentation to have warnings output to the logging facility instead of stderr.

In commit https://github.com/python-pillow/Pillow/pull/674/files we see setting is Image.MAX_IMAGE_PIXELS and hard-coded value is int(1024 * 1024 * 1024 / 4 / 3) = 89,478,485 pixels or about 9459x9459, which agrees with the error report.

Perhaps option would be have leave the default behaviour of the iiif code as-is, but add and option to iiif_static.py that sets a different limit and simultaneously turns the warning into an error. This would have the side-effect of documenting the issue.

zimeon commented 9 years ago

Confirm that warning can be silenced we adjusting the Image.MAX_IMAGE_PIXELS setting:

from PIL import Image
Image.MAX_IMAGE_PIXELS = 1000000000                                                                                              

or turned into and error with:

from PIL import Image                                                                                         
Image.warnings.simplefilter('error', Image.DecompressionBombWarning)

Used the 44kB, 19k by 19k test image from ftp://ftp.aerasec.de/pub/advisories/decompressionbombs/pictures/picture-1G-19000x19000.png to check with:

wget ftp://ftp.aerasec.de/pub/advisories/decompressionbombs/pictures/picture-1G-19000x19000.png
iiif_static.py -d biggie -i biggie picture-1G-19000x19000.png 
zimeon commented 8 years ago

Easy way to show current behavior in my code (with the above picture-1G-19000x19000.png renamed as testimages/red-19000x19000.png is:

simeon@RottenApple iiif>./iiif_static.py -n testimages/red-19000x19000.png > /dev/null
/Library/Python/2.7/site-packages/PIL/Image.py:2224: DecompressionBombWarning: Image size (361000000 pixels) exceeds limit of 89478485 pixels, could be decompression bomb DOS attack.
  DecompressionBombWarning)
zimeon commented 8 years ago

Test fix d1f8689 with:

normal warning

simeon@RottenApple iiif>./iiif_static.py -n testimages/red-19000x19000.png > /dev/null
/Library/Python/2.7/site-packages/PIL/Image.py:2224: DecompressionBombWarning: Image size (361000000 pixels) exceeds limit of 89478485 pixels, could be decompression bomb DOS attack.
  DecompressionBombWarning)

error if > 1234 pixels

simeon@RottenApple iiif>./iiif_static.py -n testimages/red-19000x19000.png --max-image-pixels=1234 > /dev/null
iiif_static.py: Error: <?xml version='1.0' encoding='UTF-8'?>
<error xmlns="http://library.stanford.edu/iiif/image-api/ns/">
<parameter>unknown</parameter>
<text>Image size limit exceeded, failed to open testimages/red-19000x19000.png: Image size (361000000 pixels) exceeds limit of 1234 pixels, could be decompression bomb DOS attack.</text>
</error>

disable error with large limit

simeon@RottenApple iiif>./iiif_static.py -n testimages/red-19000x19000.png --max-image-pixels=1234567890 > /dev/null
simeon@RottenApple iiif>

and --help has:

  --max-image-pixels=MAX_IMAGE_PIXELS
                        Set the maximum number of pixels in an image. A non-
                        zero value will set a hard limit on the image size. If
                        left unset then the default configuration of the
                        Python Image Libary (PIL) will give a
                        DecompressionBombWarning if the image size exceeds a
                        default maximum, but otherwise continue as normal