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