147 lines
4.3 KiB
Diff
147 lines
4.3 KiB
Diff
|
From 7fe3dff241c11206616bf6229be898854ce0d066 Mon Sep 17 00:00:00 2001
|
||
|
From: Lumir Balhar <lbalhar@redhat.com>
|
||
|
Date: Mon, 14 Jun 2021 11:33:36 +0200
|
||
|
Subject: [PATCH] CVE-2021-28675
|
||
|
|
||
|
---
|
||
|
src/PIL/ImageFile.py | 12 ++++++++++--
|
||
|
src/PIL/PsdImagePlugin.py | 33 +++++++++++++++++++++++----------
|
||
|
2 files changed, 33 insertions(+), 12 deletions(-)
|
||
|
|
||
|
diff --git a/src/PIL/ImageFile.py b/src/PIL/ImageFile.py
|
||
|
index 1a3c4aa..2cef9ee 100644
|
||
|
--- a/src/PIL/ImageFile.py
|
||
|
+++ b/src/PIL/ImageFile.py
|
||
|
@@ -522,12 +522,18 @@ def _safe_read(fp, size):
|
||
|
|
||
|
:param fp: File handle. Must implement a <b>read</b> method.
|
||
|
:param size: Number of bytes to read.
|
||
|
- :returns: A string containing up to <i>size</i> bytes of data.
|
||
|
+ :returns: A string containing <i>size</i> bytes of data.
|
||
|
+
|
||
|
+ Raises an OSError if the file is truncated and the read can not be completed
|
||
|
+
|
||
|
"""
|
||
|
if size <= 0:
|
||
|
return b""
|
||
|
if size <= SAFEBLOCK:
|
||
|
- return fp.read(size)
|
||
|
+ data = fp.read(size)
|
||
|
+ if len(data) < size:
|
||
|
+ raise OSError("Truncated File Read")
|
||
|
+ return data
|
||
|
data = []
|
||
|
while size > 0:
|
||
|
block = fp.read(min(size, SAFEBLOCK))
|
||
|
@@ -535,6 +541,8 @@ def _safe_read(fp, size):
|
||
|
break
|
||
|
data.append(block)
|
||
|
size -= len(block)
|
||
|
+ if sum(len(d) for d in data) < size:
|
||
|
+ raise OSError("Truncated File Read")
|
||
|
return b"".join(data)
|
||
|
|
||
|
|
||
|
diff --git a/src/PIL/PsdImagePlugin.py b/src/PIL/PsdImagePlugin.py
|
||
|
index fe2a2ff..add9996 100644
|
||
|
--- a/src/PIL/PsdImagePlugin.py
|
||
|
+++ b/src/PIL/PsdImagePlugin.py
|
||
|
@@ -18,6 +18,8 @@
|
||
|
|
||
|
__version__ = "0.4"
|
||
|
|
||
|
+import io
|
||
|
+
|
||
|
from . import Image, ImageFile, ImagePalette
|
||
|
from ._binary import i8, i16be as i16, i32be as i32
|
||
|
|
||
|
@@ -114,7 +116,8 @@ class PsdImageFile(ImageFile.ImageFile):
|
||
|
end = self.fp.tell() + size
|
||
|
size = i32(read(4))
|
||
|
if size:
|
||
|
- self.layers = _layerinfo(self.fp)
|
||
|
+ _layer_data = io.BytesIO(ImageFile._safe_read(self.fp, size))
|
||
|
+ self.layers = _layerinfo(_layer_data, size)
|
||
|
self.fp.seek(end)
|
||
|
|
||
|
#
|
||
|
@@ -164,11 +167,20 @@ class PsdImageFile(ImageFile.ImageFile):
|
||
|
Image.Image.load(self)
|
||
|
|
||
|
|
||
|
-def _layerinfo(file):
|
||
|
+def _layerinfo(fp, ct_bytes):
|
||
|
# read layerinfo block
|
||
|
layers = []
|
||
|
- read = file.read
|
||
|
- for i in range(abs(i16(read(2)))):
|
||
|
+
|
||
|
+ def read(size):
|
||
|
+ return ImageFile._safe_read(fp, size)
|
||
|
+
|
||
|
+ ct = i16(read(2))
|
||
|
+
|
||
|
+ # sanity check
|
||
|
+ if ct_bytes < (abs(ct) * 20):
|
||
|
+ raise SyntaxError("Layer block too short for number of layers requested")
|
||
|
+
|
||
|
+ for i in range(abs(ct)):
|
||
|
|
||
|
# bounding box
|
||
|
y0 = i32(read(4))
|
||
|
@@ -179,7 +191,8 @@ def _layerinfo(file):
|
||
|
# image info
|
||
|
info = []
|
||
|
mode = []
|
||
|
- types = list(range(i16(read(2))))
|
||
|
+ ct_types = i16(read(2))
|
||
|
+ types = list(range(ct_types))
|
||
|
if len(types) > 4:
|
||
|
continue
|
||
|
|
||
|
@@ -212,7 +225,7 @@ def _layerinfo(file):
|
||
|
size = i32(read(4)) # length of the extra data field
|
||
|
combined = 0
|
||
|
if size:
|
||
|
- data_end = file.tell() + size
|
||
|
+ data_end = fp.tell() + size
|
||
|
|
||
|
length = i32(read(4))
|
||
|
if length:
|
||
|
@@ -220,12 +233,12 @@ def _layerinfo(file):
|
||
|
mask_x = i32(read(4))
|
||
|
mask_h = i32(read(4)) - mask_y
|
||
|
mask_w = i32(read(4)) - mask_x
|
||
|
- file.seek(length - 16, 1)
|
||
|
+ fp.seek(length - 16, 1)
|
||
|
combined += length + 4
|
||
|
|
||
|
length = i32(read(4))
|
||
|
if length:
|
||
|
- file.seek(length, 1)
|
||
|
+ fp.seek(length, 1)
|
||
|
combined += length + 4
|
||
|
|
||
|
length = i8(read(1))
|
||
|
@@ -235,7 +248,7 @@ def _layerinfo(file):
|
||
|
name = read(length).decode('latin-1', 'replace')
|
||
|
combined += length + 1
|
||
|
|
||
|
- file.seek(data_end)
|
||
|
+ fp.seek(data_end)
|
||
|
layers.append((name, mode, (x0, y0, x1, y1)))
|
||
|
|
||
|
# get tiles
|
||
|
@@ -243,7 +256,7 @@ def _layerinfo(file):
|
||
|
for name, mode, bbox in layers:
|
||
|
tile = []
|
||
|
for m in mode:
|
||
|
- t = _maketile(file, m, bbox, 1)
|
||
|
+ t = _maketile(fp, m, bbox, 1)
|
||
|
if t:
|
||
|
tile.extend(t)
|
||
|
layers[i] = name, mode, bbox, tile
|
||
|
--
|
||
|
2.31.1
|
||
|
|