mirror of
https://github.com/python-pillow/Pillow.git
synced 2024-12-25 09:26:16 +03:00
Fix BLP DOS -- CVE-2021-28678
* BlpImagePlugin did not properly check that reads after jumping to file offsets returned data. This could lead to a DOS where the decoder could be run a large number of times on empty data * This dates to Pillow 5.1.0
This commit is contained in:
parent
22e9bee4ef
commit
496245aa43
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -17,3 +17,22 @@ def test_load_blp2_dxt1():
|
|||
def test_load_blp2_dxt1a():
|
||||
with Image.open("Tests/images/blp/blp2_dxt1a.blp") as im:
|
||||
assert_image_equal_tofile(im, "Tests/images/blp/blp2_dxt1a.png")
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"test_file",
|
||||
[
|
||||
"Tests/images/timeout-060745d3f534ad6e4128c51d336ea5489182c69d.blp",
|
||||
"Tests/images/timeout-31c8f86233ea728339c6e586be7af661a09b5b98.blp",
|
||||
"Tests/images/timeout-60d8b7c8469d59fc9ffff6b3a3dc0faeae6ea8ee.blp",
|
||||
"Tests/images/timeout-8073b430977660cdd48d96f6406ddfd4114e69c7.blp",
|
||||
"Tests/images/timeout-bba4f2e026b5786529370e5dfe9a11b1bf991f07.blp",
|
||||
"Tests/images/timeout-d6ec061c4afdef39d3edf6da8927240bb07fe9b7.blp",
|
||||
"Tests/images/timeout-ef9112a065e7183fa7faa2e18929b03e44ee16bf.blp",
|
||||
],
|
||||
)
|
||||
def test_crashes(test_file):
|
||||
with open(test_file, "rb") as f:
|
||||
with Image.open(f) as im:
|
||||
with pytest.raises(OSError):
|
||||
im.load()
|
||||
|
|
|
@ -286,33 +286,36 @@ class _BLPBaseDecoder(ImageFile.PyDecoder):
|
|||
raise OSError("Truncated Blp file") from e
|
||||
return 0, 0
|
||||
|
||||
def _safe_read(self, length):
|
||||
return ImageFile._safe_read(self.fd, length)
|
||||
|
||||
def _read_palette(self):
|
||||
ret = []
|
||||
for i in range(256):
|
||||
try:
|
||||
b, g, r, a = struct.unpack("<4B", self.fd.read(4))
|
||||
b, g, r, a = struct.unpack("<4B", self._safe_read(4))
|
||||
except struct.error:
|
||||
break
|
||||
ret.append((b, g, r, a))
|
||||
return ret
|
||||
|
||||
def _read_blp_header(self):
|
||||
(self._blp_compression,) = struct.unpack("<i", self.fd.read(4))
|
||||
(self._blp_compression,) = struct.unpack("<i", self._safe_read(4))
|
||||
|
||||
(self._blp_encoding,) = struct.unpack("<b", self.fd.read(1))
|
||||
(self._blp_alpha_depth,) = struct.unpack("<b", self.fd.read(1))
|
||||
(self._blp_alpha_encoding,) = struct.unpack("<b", self.fd.read(1))
|
||||
(self._blp_mips,) = struct.unpack("<b", self.fd.read(1))
|
||||
(self._blp_encoding,) = struct.unpack("<b", self._safe_read(1))
|
||||
(self._blp_alpha_depth,) = struct.unpack("<b", self._safe_read(1))
|
||||
(self._blp_alpha_encoding,) = struct.unpack("<b", self._safe_read(1))
|
||||
(self._blp_mips,) = struct.unpack("<b", self._safe_read(1))
|
||||
|
||||
self.size = struct.unpack("<II", self.fd.read(8))
|
||||
self.size = struct.unpack("<II", self._safe_read(8))
|
||||
|
||||
if self.magic == b"BLP1":
|
||||
# Only present for BLP1
|
||||
(self._blp_encoding,) = struct.unpack("<i", self.fd.read(4))
|
||||
(self._blp_subtype,) = struct.unpack("<i", self.fd.read(4))
|
||||
(self._blp_encoding,) = struct.unpack("<i", self._safe_read(4))
|
||||
(self._blp_subtype,) = struct.unpack("<i", self._safe_read(4))
|
||||
|
||||
self._blp_offsets = struct.unpack("<16I", self.fd.read(16 * 4))
|
||||
self._blp_lengths = struct.unpack("<16I", self.fd.read(16 * 4))
|
||||
self._blp_offsets = struct.unpack("<16I", self._safe_read(16 * 4))
|
||||
self._blp_lengths = struct.unpack("<16I", self._safe_read(16 * 4))
|
||||
|
||||
|
||||
class BLP1Decoder(_BLPBaseDecoder):
|
||||
|
@ -324,7 +327,7 @@ class BLP1Decoder(_BLPBaseDecoder):
|
|||
if self._blp_encoding in (4, 5):
|
||||
data = bytearray()
|
||||
palette = self._read_palette()
|
||||
_data = BytesIO(self.fd.read(self._blp_lengths[0]))
|
||||
_data = BytesIO(self._safe_read(self._blp_lengths[0]))
|
||||
while True:
|
||||
try:
|
||||
(offset,) = struct.unpack("<B", _data.read(1))
|
||||
|
@ -346,10 +349,10 @@ class BLP1Decoder(_BLPBaseDecoder):
|
|||
def _decode_jpeg_stream(self):
|
||||
from PIL.JpegImagePlugin import JpegImageFile
|
||||
|
||||
(jpeg_header_size,) = struct.unpack("<I", self.fd.read(4))
|
||||
jpeg_header = self.fd.read(jpeg_header_size)
|
||||
self.fd.read(self._blp_offsets[0] - self.fd.tell()) # What IS this?
|
||||
data = self.fd.read(self._blp_lengths[0])
|
||||
(jpeg_header_size,) = struct.unpack("<I", self._safe_read(4))
|
||||
jpeg_header = self._safe_read(jpeg_header_size)
|
||||
self._safe_read(self._blp_offsets[0] - self.fd.tell()) # What IS this?
|
||||
data = self._safe_read(self._blp_lengths[0])
|
||||
data = jpeg_header + data
|
||||
data = BytesIO(data)
|
||||
image = JpegImageFile(data)
|
||||
|
@ -370,7 +373,7 @@ class BLP2Decoder(_BLPBaseDecoder):
|
|||
# Uncompressed or DirectX compression
|
||||
|
||||
if self._blp_encoding == BLP_ENCODING_UNCOMPRESSED:
|
||||
_data = BytesIO(self.fd.read(self._blp_lengths[0]))
|
||||
_data = BytesIO(self._safe_read(self._blp_lengths[0]))
|
||||
while True:
|
||||
try:
|
||||
(offset,) = struct.unpack("<B", _data.read(1))
|
||||
|
@ -384,20 +387,20 @@ class BLP2Decoder(_BLPBaseDecoder):
|
|||
linesize = (self.size[0] + 3) // 4 * 8
|
||||
for yb in range((self.size[1] + 3) // 4):
|
||||
for d in decode_dxt1(
|
||||
self.fd.read(linesize), alpha=bool(self._blp_alpha_depth)
|
||||
self._safe_read(linesize), alpha=bool(self._blp_alpha_depth)
|
||||
):
|
||||
data += d
|
||||
|
||||
elif self._blp_alpha_encoding == BLP_ALPHA_ENCODING_DXT3:
|
||||
linesize = (self.size[0] + 3) // 4 * 16
|
||||
for yb in range((self.size[1] + 3) // 4):
|
||||
for d in decode_dxt3(self.fd.read(linesize)):
|
||||
for d in decode_dxt3(self._safe_read(linesize)):
|
||||
data += d
|
||||
|
||||
elif self._blp_alpha_encoding == BLP_ALPHA_ENCODING_DXT5:
|
||||
linesize = (self.size[0] + 3) // 4 * 16
|
||||
for yb in range((self.size[1] + 3) // 4):
|
||||
for d in decode_dxt5(self.fd.read(linesize)):
|
||||
for d in decode_dxt5(self._safe_read(linesize)):
|
||||
data += d
|
||||
else:
|
||||
raise BLPFormatError(
|
||||
|
|
Loading…
Reference in New Issue
Block a user