Merge pull request #6700 from hugovk/security-samples_per_pixel-sec

This commit is contained in:
Hugo van Kemenade 2022-10-29 13:16:49 +03:00 committed by GitHub
commit 2444cddab2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 35 additions and 1 deletions

View File

@ -4,7 +4,7 @@ from io import BytesIO
import pytest import pytest
from PIL import Image, ImageFile, TiffImagePlugin from PIL import Image, ImageFile, TiffImagePlugin, UnidentifiedImageError
from PIL.TiffImagePlugin import RESOLUTION_UNIT, X_RESOLUTION, Y_RESOLUTION from PIL.TiffImagePlugin import RESOLUTION_UNIT, X_RESOLUTION, Y_RESOLUTION
from .helper import ( from .helper import (
@ -858,6 +858,19 @@ class TestFileTiff:
im.load() im.load()
ImageFile.LOAD_TRUNCATED_IMAGES = False ImageFile.LOAD_TRUNCATED_IMAGES = False
@pytest.mark.parametrize(
"test_file",
[
"Tests/images/oom-225817ca0f8c663be7ab4b9e717b02c661e66834.tif",
],
)
@pytest.mark.timeout(2)
def test_oom(self, test_file):
with pytest.raises(UnidentifiedImageError):
with pytest.warns(UserWarning):
with Image.open(test_file):
pass
@pytest.mark.skipif(not is_win32(), reason="Windows only") @pytest.mark.skipif(not is_win32(), reason="Windows only")
class TestFileTiffW32: class TestFileTiffW32:

View File

@ -49,6 +49,15 @@ decode the data in its natural CMYK mode, then convert it to RGB and rearrange
the channels afterwards. Trying to load the data in an incorrect mode could the channels afterwards. Trying to load the data in an incorrect mode could
result in a segmentation fault. This issue was introduced in Pillow 9.1.0. result in a segmentation fault. This issue was introduced in Pillow 9.1.0.
Limit SAMPLESPERPIXEL to avoid runtime DOS
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
A large value in the ``SAMPLESPERPIXEL`` tag could lead to a memory and runtime DOS in
``TiffImagePlugin.py`` when setting up the context for image decoding.
This was introduced in Pillow 9.2.0, found with `OSS-Fuzz`_ and fixed by limiting
``SAMPLESPERPIXEL`` to the number of planes that we can decode.
Other Changes Other Changes
============= =============
@ -88,3 +97,5 @@ Show all frames with ImageShow
When calling :py:meth:`~PIL.Image.Image.show` or using When calling :py:meth:`~PIL.Image.Image.show` or using
:py:mod:`~PIL.ImageShow`, all frames will now be shown. :py:mod:`~PIL.ImageShow`, all frames will now be shown.
.. _OSS-Fuzz: https://github.com/google/oss-fuzz

View File

@ -257,6 +257,8 @@ OPEN_INFO = {
(MM, 8, (1,), 1, (8, 8, 8), ()): ("LAB", "LAB"), (MM, 8, (1,), 1, (8, 8, 8), ()): ("LAB", "LAB"),
} }
MAX_SAMPLESPERPIXEL = max(len(key_tp[4]) for key_tp in OPEN_INFO.keys())
PREFIXES = [ PREFIXES = [
b"MM\x00\x2A", # Valid TIFF header with big-endian byte order b"MM\x00\x2A", # Valid TIFF header with big-endian byte order
b"II\x2A\x00", # Valid TIFF header with little-endian byte order b"II\x2A\x00", # Valid TIFF header with little-endian byte order
@ -1396,6 +1398,14 @@ class TiffImageFile(ImageFile.ImageFile):
SAMPLESPERPIXEL, SAMPLESPERPIXEL,
3 if self._compression == "tiff_jpeg" and photo in (2, 6) else 1, 3 if self._compression == "tiff_jpeg" and photo in (2, 6) else 1,
) )
if samples_per_pixel > MAX_SAMPLESPERPIXEL:
# DOS check, samples_per_pixel can be a Long, and we extend the tuple below
logger.error(
"More samples per pixel than can be decoded: %s", samples_per_pixel
)
raise SyntaxError("Invalid value for samples per pixel")
if samples_per_pixel < bps_actual_count: if samples_per_pixel < bps_actual_count:
# If a file has more values in bps_tuple than expected, # If a file has more values in bps_tuple than expected,
# remove the excess. # remove the excess.