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

BE-2346-cve-2022-45199 #20

Merged
merged 4 commits into from Apr 24, 2023
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
3 changes: 3 additions & 0 deletions CHANGES.rst
Expand Up @@ -27,6 +27,9 @@ Changelog (Pillow)
combination of \r and \n as line endings.
[rickprice]

- Fix CVE-2022-45199: Pillow before 9.3.0 allows denial of service via SAMPLESPERPIXEL.
[rickprice]

- Fix CVE-2021-28676: FliDecode did not properly check that the block advance
was non-zero, potentally leading to an infinite loop on load.
[rickprice]
Expand Down
Binary file not shown.
20 changes: 16 additions & 4 deletions Tests/test_file_tiff.py
Expand Up @@ -2,7 +2,9 @@
import sys
from io import BytesIO

from PIL import Image, TiffImagePlugin
import pytest

from PIL import Image, ImageFile, TiffImagePlugin, UnidentifiedImageError
from PIL._util import py3
from PIL.TiffImagePlugin import RESOLUTION_UNIT, X_RESOLUTION, Y_RESOLUTION

Expand All @@ -13,7 +15,6 @@

class TestFileTiff(PillowTestCase):
def test_sanity(self):

filename = self.tempfile("temp.tif")

hopper("RGB").save(filename)
Expand Down Expand Up @@ -223,8 +224,8 @@ def test_16bit_s(self):
self.assertEqual(im.getpixel((0, 1)), 0)

def test_12bit_rawmode(self):
""" Are we generating the same interpretation
of the image as Imagemagick is? """
"""Are we generating the same interpretation
of the image as Imagemagick is?"""

im = Image.open("Tests/images/12bit.cropped.tif")

Expand Down Expand Up @@ -616,6 +617,17 @@ def test_fd_leak(self):
tmpfile = self.tempfile("temp.tif")
import os

@pytest.mark.parametrize(
"test_file",
[
"Tests/images/oom-225817ca0f8c663be7ab4b9e717b02c661e66834.tif",
],
)
def test_oom(self, test_file):
with pytest.raises(UnidentifiedImageError):
with Image.open(test_file) as im:
pass

# this is an mmaped file.
with Image.open("Tests/images/uint16_1_4660.tif") as im:
im.save(tmpfile)
Expand Down
2 changes: 2 additions & 0 deletions docs/releasenotes/6.2.2.5.rst
Expand Up @@ -37,3 +37,5 @@ This release addresses several critical CVEs.
Pillow in the open phase, before an image was accepted
for opening.

:cve: `CVE-2022-45199`: Pillow before 9.3.0 allows denial of service via SAMPLESPERPIXEL.

25 changes: 21 additions & 4 deletions src/PIL/TiffImagePlugin.py
Expand Up @@ -261,6 +261,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 @@ -1264,10 +1266,25 @@ def _setup(self):
else:
bps_count = 1
bps_count += len(extra_tuple)
# Some files have only one value in bps_tuple,
# while should have more. Fix it
if bps_count > len(bps_tuple) and len(bps_tuple) == 1:
bps_tuple = bps_tuple * bps_count
bps_actual_count = len(bps_tuple)
samples_per_pixel = self.tag_v2.get(
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.
bps_tuple = bps_tuple[:samples_per_pixel]
elif samples_per_pixel > bps_actual_count and bps_actual_count == 1:
# If a file has only one value in bps_tuple, when it should have more,
# presume it is the same number of bits for all of the samples.
bps_tuple = bps_tuple * samples_per_pixel

# mode: check photometric interpretation and bits per pixel
key = (
Expand Down