mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-01-26 17:24:31 +03:00
Limit total text chunk size to 64k
This commit is contained in:
parent
b73c4b9e8b
commit
0b75526ffe
|
@ -72,9 +72,15 @@ _MODES = {
|
|||
|
||||
_simple_palette = re.compile(b'^\xff+\x00\xff*$')
|
||||
|
||||
# Maximum decompressed size for a iTXt or zTXt chunk.
|
||||
# Eliminates decompression bombs where compressed chunks can expand 1000x
|
||||
MAX_TEXT_CHUNK = ImageFile.SAFEBLOCK
|
||||
# Set the maximum total text chunk size.
|
||||
MAX_TEXT_MEMORY = 64 * MAX_TEXT_CHUNK
|
||||
|
||||
def _safe_zlib_decompress(s):
|
||||
dobj = zlib.decompressobj()
|
||||
plaintext = dobj.decompress(s, ImageFile.SAFEBLOCK)
|
||||
plaintext = dobj.decompress(s, MAX_TEXT_CHUNK)
|
||||
if dobj.unconsumed_tail:
|
||||
raise ValueError("Decompressed Data Too Large")
|
||||
return plaintext
|
||||
|
@ -267,6 +273,14 @@ class PngStream(ChunkStream):
|
|||
self.im_tile = None
|
||||
self.im_palette = None
|
||||
|
||||
self.text_memory = 0
|
||||
|
||||
def check_text_memory(self, chunklen):
|
||||
self.text_memory += chunklen
|
||||
if self.text_memory > MAX_TEXT_MEMORY:
|
||||
raise ValueError("Too much memory used in text chunks: %s>MAX_TEXT_MEMORY" %
|
||||
self.text_memory)
|
||||
|
||||
def chunk_iCCP(self, pos, length):
|
||||
|
||||
# ICC profile
|
||||
|
@ -379,6 +393,8 @@ class PngStream(ChunkStream):
|
|||
v = v.decode('latin-1', 'replace')
|
||||
|
||||
self.im_info[k] = self.im_text[k] = v
|
||||
self.check_text_memory(len(v))
|
||||
|
||||
return s
|
||||
|
||||
def chunk_zTXt(self, pos, length):
|
||||
|
@ -408,6 +424,8 @@ class PngStream(ChunkStream):
|
|||
v = v.decode('latin-1', 'replace')
|
||||
|
||||
self.im_info[k] = self.im_text[k] = v
|
||||
self.check_text_memory(len(v))
|
||||
|
||||
return s
|
||||
|
||||
def chunk_iTXt(self, pos, length):
|
||||
|
@ -443,7 +461,8 @@ class PngStream(ChunkStream):
|
|||
return s
|
||||
|
||||
self.im_info[k] = self.im_text[k] = iTXt(v, lang, tk)
|
||||
|
||||
self.check_text_memory(len(v))
|
||||
|
||||
return s
|
||||
|
||||
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
from helper import unittest, PillowTestCase
|
||||
import sys
|
||||
from PIL import Image
|
||||
from PIL import Image, PngImagePlugin
|
||||
from io import BytesIO
|
||||
import zlib
|
||||
|
||||
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:
|
||||
|
@ -20,5 +19,30 @@ class TestPngDos(PillowTestCase):
|
|||
for s in im.text.values():
|
||||
self.assert_(len(s) < 1024*1024, "Text chunk larger than 1M")
|
||||
|
||||
def test_dos_total_memory(self):
|
||||
im = Image.new('L',(1,1))
|
||||
compressed_data = zlib.compress('a'*1024*1023)
|
||||
|
||||
info = PngImagePlugin.PngInfo()
|
||||
|
||||
for x in range(64):
|
||||
info.add_text('t%s'%x, compressed_data, 1)
|
||||
info.add_itxt('i%s'%x, compressed_data, zip=True)
|
||||
|
||||
b = BytesIO()
|
||||
im.save(b, 'PNG', pnginfo=info)
|
||||
b.seek(0)
|
||||
|
||||
try:
|
||||
im2 = Image.open(b)
|
||||
except ValueError as msg:
|
||||
self.assert_("Too much memory" in msg)
|
||||
return
|
||||
|
||||
total_len = 0
|
||||
for txt in im2.text.values():
|
||||
total_len += len(txt)
|
||||
self.assert_(total_len < 64*1024*1024)
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
Loading…
Reference in New Issue
Block a user