From 2f409261eb1228e166868f8f0b5da5cda52e55bf Mon Sep 17 00:00:00 2001 From: Eric Soroos Date: Thu, 17 Dec 2020 00:17:53 +0100 Subject: [PATCH 1/2] Fix for CVE CVE-2020-35655 - Read Overflow in PCX Decoding. * Don't trust the image to specify a buffer size --- Tests/images/ossfuzz-4836216264589312.pcx | Bin 0 -> 129 bytes Tests/test_image.py | 27 ++++++++++++---------- src/PIL/PcxImagePlugin.py | 9 ++++++-- 3 files changed, 22 insertions(+), 14 deletions(-) create mode 100644 Tests/images/ossfuzz-4836216264589312.pcx diff --git a/Tests/images/ossfuzz-4836216264589312.pcx b/Tests/images/ossfuzz-4836216264589312.pcx new file mode 100644 index 0000000000000000000000000000000000000000..fdde9716a0cbd84900f9499c2f8c6d13067d456a GIT binary patch literal 129 wcmd;LP+(+WP*4Ej|6rg11t1QLjY`90z%&y`Cj@}_2tCMbm "7.0.0" - def test_overrun(self): - """For overrun completeness, test as: - valgrind pytest -qq Tests/test_image.py::TestImage::test_overrun | grep decode.c - """ - for file in [ + @pytest.mark.parametrize("path", [ "fli_overrun.bin", "sgi_overrun.bin", "sgi_overrun_expandrow.bin", "sgi_overrun_expandrow2.bin", "pcx_overrun.bin", "pcx_overrun2.bin", + "ossfuzz-4836216264589312.pcx", "01r_00.pcx", - ]: - with Image.open(os.path.join("Tests/images", file)) as im: - try: - im.load() - assert False - except OSError as e: - assert str(e) == "buffer overrun when reading image file" + ]) + def test_overrun(self, path): + """For overrun completeness, test as: + valgrind pytest -qq Tests/test_image.py::TestImage::test_overrun | grep decode.c + """ + with Image.open(os.path.join("Tests/images", path)) as im: + try: + im.load() + assert False + except OSError as e: + assert (str(e) == "buffer overrun when reading image file" or + "image file is truncated" in str(e)) + def test_fli_overrun2(self): with Image.open("Tests/images/fli_overrun2.bin") as im: try: im.seek(1) diff --git a/src/PIL/PcxImagePlugin.py b/src/PIL/PcxImagePlugin.py index b337b7dde20..a24d44b4278 100644 --- a/src/PIL/PcxImagePlugin.py +++ b/src/PIL/PcxImagePlugin.py @@ -66,13 +66,13 @@ def _open(self): version = s[1] bits = s[3] planes = s[65] - stride = i16(s, 66) + ignored_stride = i16(s, 66) logger.debug( "PCX version %s, bits %s, planes %s, stride %s", version, bits, planes, - stride, + ignored_stride, ) self.info["dpi"] = i16(s, 12), i16(s, 14) @@ -110,6 +110,11 @@ def _open(self): self.mode = mode self._size = bbox[2] - bbox[0], bbox[3] - bbox[1] + # don't trust the passed in stride. Calculate for ourselves. + # CVE-2020-35655 + stride = (self._size[0] * bits + 7) // 8 + stride += stride % 2 + bbox = (0, 0) + self.size logger.debug("size: %sx%s", *self.size) From 903c67353da1dc3a59d5367338e76101a9cfb4b1 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Sat, 2 Jan 2021 20:41:17 +1100 Subject: [PATCH 2/2] Lint fix --- Tests/test_image.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/Tests/test_image.py b/Tests/test_image.py index d91f1c263f8..f2a1917e856 100644 --- a/Tests/test_image.py +++ b/Tests/test_image.py @@ -775,7 +775,9 @@ def test_pillow_version(self, test_module): with pytest.warns(DeprecationWarning): assert test_module.PILLOW_VERSION > "7.0.0" - @pytest.mark.parametrize("path", [ + @pytest.mark.parametrize( + "path", + [ "fli_overrun.bin", "sgi_overrun.bin", "sgi_overrun_expandrow.bin", @@ -784,7 +786,8 @@ def test_pillow_version(self, test_module): "pcx_overrun2.bin", "ossfuzz-4836216264589312.pcx", "01r_00.pcx", - ]) + ], + ) def test_overrun(self, path): """For overrun completeness, test as: valgrind pytest -qq Tests/test_image.py::TestImage::test_overrun | grep decode.c @@ -794,8 +797,10 @@ def test_overrun(self, path): im.load() assert False except OSError as e: - assert (str(e) == "buffer overrun when reading image file" or - "image file is truncated" in str(e)) + buffer_overrun = str(e) == "buffer overrun when reading image file" + truncated = "image file is truncated" in str(e) + + assert buffer_overrun or truncated def test_fli_overrun2(self): with Image.open("Tests/images/fli_overrun2.bin") as im: