From c3b970f046460be093997a67c926dea321ff4fad Mon Sep 17 00:00:00 2001 From: Konstantin Kopachev Date: Wed, 29 Jun 2016 12:24:37 -0700 Subject: [PATCH 1/3] Ability to skip crc checks for ancillary chunks --- PIL/PngImagePlugin.py | 6 ++++++ Tests/test_file_png.py | 30 ++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/PIL/PngImagePlugin.py b/PIL/PngImagePlugin.py index 0e98dbf76..4d82c9a97 100644 --- a/PIL/PngImagePlugin.py +++ b/PIL/PngImagePlugin.py @@ -138,6 +138,12 @@ class ChunkStream(object): def crc(self, cid, data): "Read and verify checksum" + # Skip CRC checks for ancillary chunks if allowed to load truncated images + # 5th byte of first char is 1 [specs, section 5.4] + if ImageFile.LOAD_TRUNCATED_IMAGES and (ord(cid[0]) >> 5 & 1): + self.crc_skip(cid, data) + return + try: crc1 = Image.core.crc32(data, Image.core.crc32(cid)) crc2 = i16(self.fp.read(2)), i16(self.fp.read(2)) diff --git a/Tests/test_file_png.py b/Tests/test_file_png.py index 0ba51865c..d3ee54e54 100644 --- a/Tests/test_file_png.py +++ b/Tests/test_file_png.py @@ -3,6 +3,7 @@ from helper import unittest, PillowTestCase, hopper from io import BytesIO from PIL import Image +from PIL import ImageFile from PIL import PngImagePlugin import zlib @@ -319,6 +320,35 @@ class TestFilePng(PillowTestCase): self.assertTrue(im.fp is not None) self.assertRaises((IOError, SyntaxError), im.verify) + def test_verify_ignores_crc_error(self): + # check ignores crc errors in ancillary chunks + + chunk_data = chunk(b'tEXt', b'spam') + broken_crc_chunk_data = chunk_data[:-1] + 'q' # break CRC + + image_data = HEAD + broken_crc_chunk_data + TAIL + self.assertRaises(SyntaxError, + lambda: PngImagePlugin.PngImageFile(BytesIO(image_data))) + + ImageFile.LOAD_TRUNCATED_IMAGES = True + try: + im = load(image_data) + self.assertTrue(im is not None) + finally: + ImageFile.LOAD_TRUNCATED_IMAGES = False + + def test_verify_not_ignores_crc_error_in_required_chunk(self): + # check does not ignore crc errors in required chunks + + image_data = MAGIC + IHDR[:-1] + 'q' + TAIL + + ImageFile.LOAD_TRUNCATED_IMAGES = True + try: + self.assertRaises(SyntaxError, + lambda: PngImagePlugin.PngImageFile(BytesIO(image_data))) + finally: + ImageFile.LOAD_TRUNCATED_IMAGES = False + def test_roundtrip_dpi(self): # Check dpi roundtripping From 885297d21f239af8d48f3d9a4ef5499b1db90033 Mon Sep 17 00:00:00 2001 From: Konstantin Kopachev Date: Wed, 29 Jun 2016 13:01:37 -0700 Subject: [PATCH 2/3] Fix python 3 bytes to string concat error --- PIL/PngImagePlugin.py | 2 +- Tests/test_file_png.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/PIL/PngImagePlugin.py b/PIL/PngImagePlugin.py index 4d82c9a97..12a7ef17e 100644 --- a/PIL/PngImagePlugin.py +++ b/PIL/PngImagePlugin.py @@ -140,7 +140,7 @@ class ChunkStream(object): # Skip CRC checks for ancillary chunks if allowed to load truncated images # 5th byte of first char is 1 [specs, section 5.4] - if ImageFile.LOAD_TRUNCATED_IMAGES and (ord(cid[0]) >> 5 & 1): + if ImageFile.LOAD_TRUNCATED_IMAGES and (i8(cid[0]) >> 5 & 1): self.crc_skip(cid, data) return diff --git a/Tests/test_file_png.py b/Tests/test_file_png.py index d3ee54e54..e09abb172 100644 --- a/Tests/test_file_png.py +++ b/Tests/test_file_png.py @@ -324,7 +324,7 @@ class TestFilePng(PillowTestCase): # check ignores crc errors in ancillary chunks chunk_data = chunk(b'tEXt', b'spam') - broken_crc_chunk_data = chunk_data[:-1] + 'q' # break CRC + broken_crc_chunk_data = chunk_data[:-1] + b'q' # break CRC image_data = HEAD + broken_crc_chunk_data + TAIL self.assertRaises(SyntaxError, @@ -340,7 +340,7 @@ class TestFilePng(PillowTestCase): def test_verify_not_ignores_crc_error_in_required_chunk(self): # check does not ignore crc errors in required chunks - image_data = MAGIC + IHDR[:-1] + 'q' + TAIL + image_data = MAGIC + IHDR[:-1] + b'q' + TAIL ImageFile.LOAD_TRUNCATED_IMAGES = True try: From 5f2fe6083caee718d27a844328c49ad93ffcf2c3 Mon Sep 17 00:00:00 2001 From: Konstantin Kopachev Date: Wed, 29 Jun 2016 17:29:55 -0700 Subject: [PATCH 3/3] CR feedback: don't use lambda --- Tests/test_file_png.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Tests/test_file_png.py b/Tests/test_file_png.py index e09abb172..d4494cad0 100644 --- a/Tests/test_file_png.py +++ b/Tests/test_file_png.py @@ -327,8 +327,7 @@ class TestFilePng(PillowTestCase): broken_crc_chunk_data = chunk_data[:-1] + b'q' # break CRC image_data = HEAD + broken_crc_chunk_data + TAIL - self.assertRaises(SyntaxError, - lambda: PngImagePlugin.PngImageFile(BytesIO(image_data))) + self.assertRaises(SyntaxError, PngImagePlugin.PngImageFile, BytesIO(image_data)) ImageFile.LOAD_TRUNCATED_IMAGES = True try: @@ -344,8 +343,7 @@ class TestFilePng(PillowTestCase): ImageFile.LOAD_TRUNCATED_IMAGES = True try: - self.assertRaises(SyntaxError, - lambda: PngImagePlugin.PngImageFile(BytesIO(image_data))) + self.assertRaises(SyntaxError, PngImagePlugin.PngImageFile, BytesIO(image_data)) finally: ImageFile.LOAD_TRUNCATED_IMAGES = False