mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-08-14 01:04:45 +03:00
Merge pull request #18 from ActiveState/BE-139-cve-2021-28676
BE-139-cve-2021-28676
This commit is contained in:
commit
fefc469fda
|
@ -27,6 +27,10 @@ Changelog (Pillow)
|
||||||
combination of \r and \n as line endings.
|
combination of \r and \n as line endings.
|
||||||
[rickprice]
|
[rickprice]
|
||||||
|
|
||||||
|
- Fix CVE-2021-28676: FliDecode did not properly check that the block advance
|
||||||
|
was non-zero, potentally leading to an infinite loop on load.
|
||||||
|
[rickprice]
|
||||||
|
|
||||||
6.2.2.4 (2023-03-29)
|
6.2.2.4 (2023-03-29)
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -46,7 +46,8 @@ class TestFileFli(PillowTestCase):
|
||||||
def test_invalid_file(self):
|
def test_invalid_file(self):
|
||||||
invalid_file = "Tests/images/flower.jpg"
|
invalid_file = "Tests/images/flower.jpg"
|
||||||
|
|
||||||
self.assertRaises(SyntaxError, FliImagePlugin.FliImageFile, invalid_file)
|
self.assertRaises(
|
||||||
|
SyntaxError, FliImagePlugin.FliImageFile, invalid_file)
|
||||||
|
|
||||||
def test_n_frames(self):
|
def test_n_frames(self):
|
||||||
im = Image.open(static_test_file)
|
im = Image.open(static_test_file)
|
||||||
|
@ -96,3 +97,13 @@ class TestFileFli(PillowTestCase):
|
||||||
|
|
||||||
expected = Image.open("Tests/images/a_fli.png")
|
expected = Image.open("Tests/images/a_fli.png")
|
||||||
self.assert_image_equal(im, expected)
|
self.assert_image_equal(im, expected)
|
||||||
|
|
||||||
|
def test_timeouts(self):
|
||||||
|
for test_file in [
|
||||||
|
"Tests/images/timeout-9139147ce93e20eb14088fe238e541443ffd64b3.fli",
|
||||||
|
"Tests/images/timeout-bff0a9dc7243a8e6ede2408d2ffa6a9964698b87.fli",
|
||||||
|
]:
|
||||||
|
with open(test_file, "rb") as f:
|
||||||
|
with Image.open(f) as im:
|
||||||
|
with self.assertRaises(OSError):
|
||||||
|
im.load()
|
||||||
|
|
|
@ -25,6 +25,9 @@ This release addresses several critical CVEs.
|
||||||
|
|
||||||
:cve:`CVE-2020-10994`: In libImaging/Jpeg2KDecode.c in Pillow before 7.1.0, there are multiple out-of-bounds reads via a crafted JP2 file.
|
:cve:`CVE-2020-10994`: In libImaging/Jpeg2KDecode.c in Pillow before 7.1.0, there are multiple out-of-bounds reads via a crafted JP2 file.
|
||||||
|
|
||||||
|
:cve:`CVE-2021-28676``: FliDecode did not properly check that the block advance was non-zero,
|
||||||
|
potentally leading to an infinite loop on load.
|
||||||
|
|
||||||
:cve:`CVE-2021-28677`: An issue was discovered in Pillow before 8.2.0. For EPS
|
:cve:`CVE-2021-28677`: An issue was discovered in Pillow before 8.2.0. For EPS
|
||||||
data, the readline implementation used in EPSImageFile
|
data, the readline implementation used in EPSImageFile
|
||||||
has to deal with any combination of \r and \n as line
|
has to deal with any combination of \r and \n as line
|
||||||
|
|
|
@ -14,21 +14,22 @@
|
||||||
* See the README file for information on usage and redistribution.
|
* See the README file for information on usage and redistribution.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#include "Imaging.h"
|
#include "Imaging.h"
|
||||||
|
|
||||||
|
#define I16(ptr) ((ptr)[0] + ((ptr)[1] << 8))
|
||||||
|
|
||||||
#define I16(ptr)\
|
#define I32(ptr) \
|
||||||
((ptr)[0] + ((ptr)[1] << 8))
|
|
||||||
|
|
||||||
#define I32(ptr)\
|
|
||||||
((ptr)[0] + ((ptr)[1] << 8) + ((ptr)[2] << 16) + ((ptr)[3] << 24))
|
((ptr)[0] + ((ptr)[1] << 8) + ((ptr)[2] << 16) + ((ptr)[3] << 24))
|
||||||
|
|
||||||
|
#define ERR_IF_DATA_OOB(offset) \
|
||||||
|
if ((data + (offset)) > ptr + bytes) { \
|
||||||
|
state->errcode = IMAGING_CODEC_OVERRUN; \
|
||||||
|
return -1; \
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int ImagingFliDecode(Imaging im, ImagingCodecState state, UINT8 *buf,
|
||||||
ImagingFliDecode(Imaging im, ImagingCodecState state, UINT8* buf, Py_ssize_t bytes)
|
Py_ssize_t bytes) {
|
||||||
{
|
UINT8 *ptr;
|
||||||
UINT8* ptr;
|
|
||||||
int framesize;
|
int framesize;
|
||||||
int c, chunks, advance;
|
int c, chunks, advance;
|
||||||
int l, lines;
|
int l, lines;
|
||||||
|
@ -55,34 +56,39 @@ ImagingFliDecode(Imaging im, ImagingCodecState state, UINT8* buf, Py_ssize_t byt
|
||||||
state->errcode = IMAGING_CODEC_OVERRUN;
|
state->errcode = IMAGING_CODEC_OVERRUN;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (I16(ptr+4) != 0xF1FA) {
|
if (I16(ptr + 4) != 0xF1FA) {
|
||||||
state->errcode = IMAGING_CODEC_UNKNOWN;
|
state->errcode = IMAGING_CODEC_UNKNOWN;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
chunks = I16(ptr+6);
|
chunks = I16(ptr + 6);
|
||||||
ptr += 16;
|
ptr += 16;
|
||||||
bytes -= 16;
|
bytes -= 16;
|
||||||
|
|
||||||
/* Process subchunks */
|
/* Process subchunks */
|
||||||
for (c = 0; c < chunks; c++) {
|
for (c = 0; c < chunks; c++) {
|
||||||
UINT8* data;
|
UINT8 *data;
|
||||||
if (bytes < 10) {
|
if (bytes < 10) {
|
||||||
state->errcode = IMAGING_CODEC_OVERRUN;
|
state->errcode = IMAGING_CODEC_OVERRUN;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
data = ptr + 6;
|
data = ptr + 6;
|
||||||
switch (I16(ptr+4)) {
|
switch (I16(ptr + 4)) {
|
||||||
case 4: case 11:
|
case 4:
|
||||||
|
case 11:
|
||||||
/* FLI COLOR chunk */
|
/* FLI COLOR chunk */
|
||||||
break; /* ignored; handled by Python code */
|
break; /* ignored; handled by Python code */
|
||||||
case 7:
|
case 7:
|
||||||
/* FLI SS2 chunk (word delta) */
|
/* FLI SS2 chunk (word delta) */
|
||||||
lines = I16(data); data += 2;
|
/* OOB ok, we've got 4 bytes min on entry */
|
||||||
|
lines = I16(data);
|
||||||
|
data += 2;
|
||||||
for (l = y = 0; l < lines && y < state->ysize; l++, y++) {
|
for (l = y = 0; l < lines && y < state->ysize; l++, y++) {
|
||||||
UINT8* buf = (UINT8*) im->image[y];
|
UINT8 *local_buf = (UINT8 *)im->image[y];
|
||||||
int p, packets;
|
int p, packets;
|
||||||
packets = I16(data); data += 2;
|
ERR_IF_DATA_OOB(2)
|
||||||
|
packets = I16(data);
|
||||||
|
data += 2;
|
||||||
while (packets & 0x8000) {
|
while (packets & 0x8000) {
|
||||||
/* flag word */
|
/* flag word */
|
||||||
if (packets & 0x4000) {
|
if (packets & 0x4000) {
|
||||||
|
@ -91,36 +97,44 @@ ImagingFliDecode(Imaging im, ImagingCodecState state, UINT8* buf, Py_ssize_t byt
|
||||||
state->errcode = IMAGING_CODEC_OVERRUN;
|
state->errcode = IMAGING_CODEC_OVERRUN;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
buf = (UINT8*) im->image[y];
|
local_buf = (UINT8 *)im->image[y];
|
||||||
} else {
|
} else {
|
||||||
/* store last byte (used if line width is odd) */
|
/* store last byte (used if line width is odd) */
|
||||||
buf[state->xsize-1] = (UINT8) packets;
|
local_buf[state->xsize - 1] = (UINT8)packets;
|
||||||
}
|
}
|
||||||
packets = I16(data); data += 2;
|
ERR_IF_DATA_OOB(2)
|
||||||
|
packets = I16(data);
|
||||||
|
data += 2;
|
||||||
}
|
}
|
||||||
for (p = x = 0; p < packets; p++) {
|
for (p = x = 0; p < packets; p++) {
|
||||||
|
ERR_IF_DATA_OOB(2)
|
||||||
x += data[0]; /* pixel skip */
|
x += data[0]; /* pixel skip */
|
||||||
if (data[1] >= 128) {
|
if (data[1] >= 128) {
|
||||||
i = 256-data[1]; /* run */
|
ERR_IF_DATA_OOB(4)
|
||||||
if (x + i + i > state->xsize)
|
i = 256 - data[1]; /* run */
|
||||||
|
if (x + i + i > state->xsize) {
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
for (j = 0; j < i; j++) {
|
for (j = 0; j < i; j++) {
|
||||||
buf[x++] = data[2];
|
local_buf[x++] = data[2];
|
||||||
buf[x++] = data[3];
|
local_buf[x++] = data[3];
|
||||||
}
|
}
|
||||||
data += 2 + 2;
|
data += 2 + 2;
|
||||||
} else {
|
} else {
|
||||||
i = 2 * (int) data[1]; /* chunk */
|
i = 2 * (int)data[1]; /* chunk */
|
||||||
if (x + i > state->xsize)
|
if (x + i > state->xsize) {
|
||||||
break;
|
break;
|
||||||
memcpy(buf + x, data + 2, i);
|
}
|
||||||
|
ERR_IF_DATA_OOB(2 + i)
|
||||||
|
memcpy(local_buf + x, data + 2, i);
|
||||||
data += 2 + i;
|
data += 2 + i;
|
||||||
x += i;
|
x += i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (p < packets)
|
if (p < packets) {
|
||||||
break; /* didn't process all packets */
|
break; /* didn't process all packets */
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (l < lines) {
|
if (l < lines) {
|
||||||
/* didn't process all lines */
|
/* didn't process all lines */
|
||||||
state->errcode = IMAGING_CODEC_OVERRUN;
|
state->errcode = IMAGING_CODEC_OVERRUN;
|
||||||
|
@ -129,29 +143,39 @@ ImagingFliDecode(Imaging im, ImagingCodecState state, UINT8* buf, Py_ssize_t byt
|
||||||
break;
|
break;
|
||||||
case 12:
|
case 12:
|
||||||
/* FLI LC chunk (byte delta) */
|
/* FLI LC chunk (byte delta) */
|
||||||
y = I16(data); ymax = y + I16(data+2); data += 4;
|
/* OOB Check ok, we have 4 bytes min here */
|
||||||
|
y = I16(data);
|
||||||
|
ymax = y + I16(data + 2);
|
||||||
|
data += 4;
|
||||||
for (; y < ymax && y < state->ysize; y++) {
|
for (; y < ymax && y < state->ysize; y++) {
|
||||||
UINT8* out = (UINT8*) im->image[y];
|
UINT8 *out = (UINT8 *)im->image[y];
|
||||||
|
ERR_IF_DATA_OOB(1)
|
||||||
int p, packets = *data++;
|
int p, packets = *data++;
|
||||||
for (p = x = 0; p < packets; p++, x += i) {
|
for (p = x = 0; p < packets; p++, x += i) {
|
||||||
|
ERR_IF_DATA_OOB(2)
|
||||||
x += data[0]; /* skip pixels */
|
x += data[0]; /* skip pixels */
|
||||||
if (data[1] & 0x80) {
|
if (data[1] & 0x80) {
|
||||||
i = 256-data[1]; /* run */
|
i = 256 - data[1]; /* run */
|
||||||
if (x + i > state->xsize)
|
if (x + i > state->xsize) {
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
ERR_IF_DATA_OOB(3)
|
||||||
memset(out + x, data[2], i);
|
memset(out + x, data[2], i);
|
||||||
data += 3;
|
data += 3;
|
||||||
} else {
|
} else {
|
||||||
i = data[1]; /* chunk */
|
i = data[1]; /* chunk */
|
||||||
if (x + i > state->xsize)
|
if (x + i > state->xsize) {
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
ERR_IF_DATA_OOB(2 + i)
|
||||||
memcpy(out + x, data + 2, i);
|
memcpy(out + x, data + 2, i);
|
||||||
data += i + 2;
|
data += i + 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (p < packets)
|
if (p < packets) {
|
||||||
break; /* didn't process all packets */
|
break; /* didn't process all packets */
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (y < ymax) {
|
if (y < ymax) {
|
||||||
/* didn't process all lines */
|
/* didn't process all lines */
|
||||||
state->errcode = IMAGING_CODEC_OVERRUN;
|
state->errcode = IMAGING_CODEC_OVERRUN;
|
||||||
|
@ -160,25 +184,31 @@ ImagingFliDecode(Imaging im, ImagingCodecState state, UINT8* buf, Py_ssize_t byt
|
||||||
break;
|
break;
|
||||||
case 13:
|
case 13:
|
||||||
/* FLI BLACK chunk */
|
/* FLI BLACK chunk */
|
||||||
for (y = 0; y < state->ysize; y++)
|
for (y = 0; y < state->ysize; y++) {
|
||||||
memset(im->image[y], 0, state->xsize);
|
memset(im->image[y], 0, state->xsize);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 15:
|
case 15:
|
||||||
/* FLI BRUN chunk */
|
/* FLI BRUN chunk */
|
||||||
|
/* OOB, ok, we've got 4 bytes min on entry */
|
||||||
for (y = 0; y < state->ysize; y++) {
|
for (y = 0; y < state->ysize; y++) {
|
||||||
UINT8* out = (UINT8*) im->image[y];
|
UINT8 *out = (UINT8 *)im->image[y];
|
||||||
data += 1; /* ignore packetcount byte */
|
data += 1; /* ignore packetcount byte */
|
||||||
for (x = 0; x < state->xsize; x += i) {
|
for (x = 0; x < state->xsize; x += i) {
|
||||||
|
ERR_IF_DATA_OOB(2)
|
||||||
if (data[0] & 0x80) {
|
if (data[0] & 0x80) {
|
||||||
i = 256 - data[0];
|
i = 256 - data[0];
|
||||||
if (x + i > state->xsize)
|
if (x + i > state->xsize) {
|
||||||
break; /* safety first */
|
break; /* safety first */
|
||||||
|
}
|
||||||
|
ERR_IF_DATA_OOB(i + 1)
|
||||||
memcpy(out + x, data + 1, i);
|
memcpy(out + x, data + 1, i);
|
||||||
data += i + 1;
|
data += i + 1;
|
||||||
} else {
|
} else {
|
||||||
i = data[0];
|
i = data[0];
|
||||||
if (x + i > state->xsize)
|
if (x + i > state->xsize) {
|
||||||
break; /* safety first */
|
break; /* safety first */
|
||||||
|
}
|
||||||
memset(out + x, data[1], i);
|
memset(out + x, data[1], i);
|
||||||
data += 2;
|
data += 2;
|
||||||
}
|
}
|
||||||
|
@ -192,9 +222,13 @@ ImagingFliDecode(Imaging im, ImagingCodecState state, UINT8* buf, Py_ssize_t byt
|
||||||
break;
|
break;
|
||||||
case 16:
|
case 16:
|
||||||
/* COPY chunk */
|
/* COPY chunk */
|
||||||
|
if (state->xsize > bytes / state->ysize) {
|
||||||
|
/* not enough data for frame */
|
||||||
|
return ptr - buf; /* bytes consumed */
|
||||||
|
}
|
||||||
for (y = 0; y < state->ysize; y++) {
|
for (y = 0; y < state->ysize; y++) {
|
||||||
UINT8* buf = (UINT8*) im->image[y];
|
UINT8 *local_buf = (UINT8 *)im->image[y];
|
||||||
memcpy(buf, data, state->xsize);
|
memcpy(local_buf, data, state->xsize);
|
||||||
data += state->xsize;
|
data += state->xsize;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -208,6 +242,15 @@ ImagingFliDecode(Imaging im, ImagingCodecState state, UINT8* buf, Py_ssize_t byt
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
advance = I32(ptr);
|
advance = I32(ptr);
|
||||||
|
if (advance == 0) {
|
||||||
|
// If there's no advance, we're in in infinite loop
|
||||||
|
state->errcode = IMAGING_CODEC_BROKEN;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (advance < 0 || advance > bytes) {
|
||||||
|
state->errcode = IMAGING_CODEC_OVERRUN;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
ptr += advance;
|
ptr += advance;
|
||||||
bytes -= advance;
|
bytes -= advance;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user