From ac31061f221d4dab40ae36d61f1b09e76c20d484 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Thu, 21 Jan 2021 19:29:11 +1100 Subject: [PATCH] Handle PCX images with an odd stride --- Tests/images/odd_stride.pcx | Bin 0 -> 14313 bytes Tests/test_file_pcx.py | 8 ++++++++ src/PIL/PcxImagePlugin.py | 13 +++++++++---- 3 files changed, 17 insertions(+), 4 deletions(-) create mode 100644 Tests/images/odd_stride.pcx diff --git a/Tests/images/odd_stride.pcx b/Tests/images/odd_stride.pcx new file mode 100644 index 0000000000000000000000000000000000000000..ee0c2eecaebe5a629ccfab523971c347a878ae79 GIT binary patch literal 14313 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 literal 0 HcmV?d00001 diff --git a/Tests/test_file_pcx.py b/Tests/test_file_pcx.py index 670c03b95..61e33a57b 100644 --- a/Tests/test_file_pcx.py +++ b/Tests/test_file_pcx.py @@ -44,6 +44,14 @@ def test_odd(tmp_path): _roundtrip(tmp_path, hopper(mode).resize((511, 511))) +def test_odd_read(): + # Reading an image with an odd stride, making it malformed + with Image.open("Tests/images/odd_stride.pcx") as im: + im.load() + + assert im.size == (371, 150) + + def test_pil184(): # Check reading of files where xmin/xmax is not zero. diff --git a/src/PIL/PcxImagePlugin.py b/src/PIL/PcxImagePlugin.py index 3874e5436..d2e166bdd 100644 --- a/src/PIL/PcxImagePlugin.py +++ b/src/PIL/PcxImagePlugin.py @@ -66,13 +66,13 @@ class PcxImageFile(ImageFile.ImageFile): version = s[1] bits = s[3] planes = s[65] - ignored_stride = i16(s, 66) + provided_stride = i16(s, 66) logger.debug( "PCX version %s, bits %s, planes %s, stride %s", version, bits, planes, - ignored_stride, + provided_stride, ) self.info["dpi"] = i16(s, 12), i16(s, 14) @@ -110,10 +110,15 @@ class PcxImageFile(ImageFile.ImageFile): self.mode = mode self._size = bbox[2] - bbox[0], bbox[3] - bbox[1] - # don't trust the passed in stride. Calculate for ourselves. + # Don't trust the passed in stride. + # Calculate the approximate position for ourselves. # CVE-2020-35653 stride = (self._size[0] * bits + 7) // 8 - stride += stride % 2 + + # While the specification states that this must be even, + # not all images follow this + if provided_stride != stride: + stride += stride % 2 bbox = (0, 0) + self.size logger.debug("size: %sx%s", *self.size)