Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Limit SAMPLESPERPIXEL to avoid runtime DOS #6700

Merged
merged 5 commits into from Oct 29, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Binary file not shown.
15 changes: 14 additions & 1 deletion Tests/test_file_tiff.py
Expand Up @@ -4,7 +4,7 @@

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 .helper import (
Expand Down Expand Up @@ -858,6 +858,19 @@ def test_timeout(self):
im.load()
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")
class TestFileTiffW32:
Expand Down
11 changes: 11 additions & 0 deletions docs/releasenotes/9.3.0.rst
Expand Up @@ -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
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
=============

Expand Down Expand Up @@ -88,3 +97,5 @@ Show all frames with ImageShow

When calling :py:meth:`~PIL.Image.Image.show` or using
:py:mod:`~PIL.ImageShow`, all frames will now be shown.

.. _OSS-Fuzz: https://github.com/google/oss-fuzz
10 changes: 10 additions & 0 deletions src/PIL/TiffImagePlugin.py
Expand Up @@ -257,6 +257,8 @@
(MM, 8, (1,), 1, (8, 8, 8), ()): ("LAB", "LAB"),
}

MAX_SAMPLESPERPIXEL = max(len(key_tp[4]) for key_tp in OPEN_INFO.keys())

PREFIXES = [
b"MM\x00\x2A", # Valid TIFF header with big-endian byte order
b"II\x2A\x00", # Valid TIFF header with little-endian byte order
Expand Down Expand Up @@ -1396,6 +1398,14 @@ def _setup(self):
SAMPLESPERPIXEL,
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 a file has more values in bps_tuple than expected,
# remove the excess.
Expand Down