From 44286ba3c9bfa6ed565d11bd61460d8ec215e1ea Mon Sep 17 00:00:00 2001 From: wiredfool Date: Sun, 30 Nov 2014 23:31:29 -0800 Subject: [PATCH] Fix for zlib.decompression bomb in iTXt,zTXt, and iCCP chunks --- PIL/PngImagePlugin.py | 13 ++++++++++--- Tests/check_png_dos.py | 24 ++++++++++++++++++++++++ Tests/images/png_decompression_dos.png | Bin 0 -> 6289 bytes 3 files changed, 34 insertions(+), 3 deletions(-) create mode 100644 Tests/check_png_dos.py create mode 100644 Tests/images/png_decompression_dos.png diff --git a/PIL/PngImagePlugin.py b/PIL/PngImagePlugin.py index 8403461be..514b76f14 100644 --- a/PIL/PngImagePlugin.py +++ b/PIL/PngImagePlugin.py @@ -72,6 +72,13 @@ _MODES = { _simple_palette = re.compile(b'^\xff+\x00\xff*$') +def _safe_zlib_decompress(s): + dobj = zlib.decompressobj() + plaintext = dobj.decompress(s, ImageFile.SAFEBLOCK) + if dobj.unconsumed_tail: + raise ValueError("Decompressed Data Too Large") + return plaintext + # -------------------------------------------------------------------- # Support classes. Suitable for PNG and related formats like MNG etc. @@ -278,7 +285,7 @@ class PngStream(ChunkStream): raise SyntaxError("Unknown compression method %s in iCCP chunk" % comp_method) try: - icc_profile = zlib.decompress(s[i+2:]) + icc_profile = _safe_zlib_decompress(s[i+2:]) except zlib.error: icc_profile = None # FIXME self.im_info["icc_profile"] = icc_profile @@ -391,7 +398,7 @@ class PngStream(ChunkStream): raise SyntaxError("Unknown compression method %s in zTXt chunk" % comp_method) try: - v = zlib.decompress(v[1:]) + v = _safe_zlib_decompress(v[1:]) except zlib.error: v = b"" @@ -421,7 +428,7 @@ class PngStream(ChunkStream): if cf != 0: if cm == 0: try: - v = zlib.decompress(v) + v = _safe_zlib_decompress(v) except zlib.error: return s else: diff --git a/Tests/check_png_dos.py b/Tests/check_png_dos.py new file mode 100644 index 000000000..4e9b76537 --- /dev/null +++ b/Tests/check_png_dos.py @@ -0,0 +1,24 @@ +from helper import unittest, PillowTestCase +import sys +from PIL import Image +from io import BytesIO + +test_file = "Tests/images/png_decompression_dos.png" + +@unittest.skipIf(sys.platform.startswith('win32'), "requires Unix or MacOS") +class TestPngDos(PillowTestCase): + + def test_dos_text(self): + + try: + im = Image.open(test_file) + im.load() + except ValueError as msg: + self.assert_(msg, "Decompressed Data Too Large") + return + + for s in im.text.values(): + self.assert_(len(s) < 1024*1024, "Text chunk larger than 1M") + +if __name__ == '__main__': + unittest.main() diff --git a/Tests/images/png_decompression_dos.png b/Tests/images/png_decompression_dos.png new file mode 100644 index 0000000000000000000000000000000000000000..986561b2e78e76e92e0a8b07886dc26f6444257b GIT binary patch literal 6289 zcmeAS@N?(olHy`uVBq!ia0vp^j3CSbBp9sfW`{B`aPU=yM3f|DrW-OaRLpsM&=92H z&;qa5^Uq1xIe<8$U^E0qLtr!nMnhmU1V%$(c!xj@@8mO4jE~Ov%|>b&7>%|JhIg!w z`ffA?MnhmU1V%$(Gz4&k0HkHWQYFiY)G{z0Z5iMSuTk;Q5Eu=C(GVC7fzc2c-XQ>K p8N9c+xC7`9Q7kcv6U2|zXz1Ea_KC51p1gQu&X%Q~loCIE&GIWYhL literal 0 HcmV?d00001