mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-02-10 00:20:57 +03:00
Merge pull request #4503 from hugovk/fix_fli_6.2.x
Fix multiple OOB reads in FLI decoding
This commit is contained in:
commit
0da1eca7cf
68
Tests/check_fli_oob.py
Normal file
68
Tests/check_fli_oob.py
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
from PIL import Image
|
||||||
|
|
||||||
|
repro_ss2 = (
|
||||||
|
"images/fli_oob/06r/06r00.fli",
|
||||||
|
"images/fli_oob/06r/others/06r01.fli",
|
||||||
|
"images/fli_oob/06r/others/06r02.fli",
|
||||||
|
"images/fli_oob/06r/others/06r03.fli",
|
||||||
|
"images/fli_oob/06r/others/06r04.fli",
|
||||||
|
)
|
||||||
|
|
||||||
|
repro_lc = (
|
||||||
|
"images/fli_oob/05r/05r00.fli",
|
||||||
|
"images/fli_oob/05r/others/05r03.fli",
|
||||||
|
"images/fli_oob/05r/others/05r06.fli",
|
||||||
|
"images/fli_oob/05r/others/05r05.fli",
|
||||||
|
"images/fli_oob/05r/others/05r01.fli",
|
||||||
|
"images/fli_oob/05r/others/05r04.fli",
|
||||||
|
"images/fli_oob/05r/others/05r02.fli",
|
||||||
|
"images/fli_oob/05r/others/05r07.fli",
|
||||||
|
"images/fli_oob/patch0/000000",
|
||||||
|
"images/fli_oob/patch0/000001",
|
||||||
|
"images/fli_oob/patch0/000002",
|
||||||
|
"images/fli_oob/patch0/000003",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
repro_advance = (
|
||||||
|
"images/fli_oob/03r/03r00.fli",
|
||||||
|
"images/fli_oob/03r/others/03r01.fli",
|
||||||
|
"images/fli_oob/03r/others/03r09.fli",
|
||||||
|
"images/fli_oob/03r/others/03r11.fli",
|
||||||
|
"images/fli_oob/03r/others/03r05.fli",
|
||||||
|
"images/fli_oob/03r/others/03r10.fli",
|
||||||
|
"images/fli_oob/03r/others/03r06.fli",
|
||||||
|
"images/fli_oob/03r/others/03r08.fli",
|
||||||
|
"images/fli_oob/03r/others/03r03.fli",
|
||||||
|
"images/fli_oob/03r/others/03r07.fli",
|
||||||
|
"images/fli_oob/03r/others/03r02.fli",
|
||||||
|
"images/fli_oob/03r/others/03r04.fli",
|
||||||
|
)
|
||||||
|
|
||||||
|
repro_brun = (
|
||||||
|
"images/fli_oob/04r/initial.fli",
|
||||||
|
"images/fli_oob/04r/others/04r02.fli",
|
||||||
|
"images/fli_oob/04r/others/04r05.fli",
|
||||||
|
"images/fli_oob/04r/others/04r04.fli",
|
||||||
|
"images/fli_oob/04r/others/04r03.fli",
|
||||||
|
"images/fli_oob/04r/others/04r01.fli",
|
||||||
|
"images/fli_oob/04r/04r00.fli",
|
||||||
|
)
|
||||||
|
|
||||||
|
repro_copy = (
|
||||||
|
"images/fli_oob/02r/others/02r02.fli",
|
||||||
|
"images/fli_oob/02r/others/02r04.fli",
|
||||||
|
"images/fli_oob/02r/others/02r03.fli",
|
||||||
|
"images/fli_oob/02r/others/02r01.fli",
|
||||||
|
"images/fli_oob/02r/02r00.fli",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
for path in repro_ss2 + repro_lc + repro_advance + repro_brun + repro_copy:
|
||||||
|
im = Image.open(path)
|
||||||
|
try:
|
||||||
|
im.load()
|
||||||
|
except Exception as msg:
|
||||||
|
print(msg)
|
BIN
Tests/images/fli_oob/02r/02r00.fli
Normal file
BIN
Tests/images/fli_oob/02r/02r00.fli
Normal file
Binary file not shown.
1
Tests/images/fli_oob/02r/notes
Normal file
1
Tests/images/fli_oob/02r/notes
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Is this because a file-originating field is being interpreted as a *signed* int32, allowing it to provide negative values for 'advance'?
|
BIN
Tests/images/fli_oob/02r/others/02r01.fli
Normal file
BIN
Tests/images/fli_oob/02r/others/02r01.fli
Normal file
Binary file not shown.
BIN
Tests/images/fli_oob/02r/others/02r02.fli
Normal file
BIN
Tests/images/fli_oob/02r/others/02r02.fli
Normal file
Binary file not shown.
BIN
Tests/images/fli_oob/02r/others/02r03.fli
Normal file
BIN
Tests/images/fli_oob/02r/others/02r03.fli
Normal file
Binary file not shown.
BIN
Tests/images/fli_oob/02r/others/02r04.fli
Normal file
BIN
Tests/images/fli_oob/02r/others/02r04.fli
Normal file
Binary file not shown.
1
Tests/images/fli_oob/02r/reproducing
Normal file
1
Tests/images/fli_oob/02r/reproducing
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Image.open(...).seek(212)
|
BIN
Tests/images/fli_oob/03r/03r00.fli
Normal file
BIN
Tests/images/fli_oob/03r/03r00.fli
Normal file
Binary file not shown.
1
Tests/images/fli_oob/03r/notes
Normal file
1
Tests/images/fli_oob/03r/notes
Normal file
|
@ -0,0 +1 @@
|
||||||
|
ridiculous bytes value passed to ImagingFliDecode
|
BIN
Tests/images/fli_oob/03r/others/03r01.fli
Normal file
BIN
Tests/images/fli_oob/03r/others/03r01.fli
Normal file
Binary file not shown.
BIN
Tests/images/fli_oob/03r/others/03r02.fli
Normal file
BIN
Tests/images/fli_oob/03r/others/03r02.fli
Normal file
Binary file not shown.
BIN
Tests/images/fli_oob/03r/others/03r03.fli
Normal file
BIN
Tests/images/fli_oob/03r/others/03r03.fli
Normal file
Binary file not shown.
BIN
Tests/images/fli_oob/03r/others/03r04.fli
Normal file
BIN
Tests/images/fli_oob/03r/others/03r04.fli
Normal file
Binary file not shown.
BIN
Tests/images/fli_oob/03r/others/03r05.fli
Normal file
BIN
Tests/images/fli_oob/03r/others/03r05.fli
Normal file
Binary file not shown.
BIN
Tests/images/fli_oob/03r/others/03r06.fli
Normal file
BIN
Tests/images/fli_oob/03r/others/03r06.fli
Normal file
Binary file not shown.
BIN
Tests/images/fli_oob/03r/others/03r07.fli
Normal file
BIN
Tests/images/fli_oob/03r/others/03r07.fli
Normal file
Binary file not shown.
BIN
Tests/images/fli_oob/03r/others/03r08.fli
Normal file
BIN
Tests/images/fli_oob/03r/others/03r08.fli
Normal file
Binary file not shown.
BIN
Tests/images/fli_oob/03r/others/03r09.fli
Normal file
BIN
Tests/images/fli_oob/03r/others/03r09.fli
Normal file
Binary file not shown.
BIN
Tests/images/fli_oob/03r/others/03r10.fli
Normal file
BIN
Tests/images/fli_oob/03r/others/03r10.fli
Normal file
Binary file not shown.
BIN
Tests/images/fli_oob/03r/others/03r11.fli
Normal file
BIN
Tests/images/fli_oob/03r/others/03r11.fli
Normal file
Binary file not shown.
1
Tests/images/fli_oob/03r/reproducing
Normal file
1
Tests/images/fli_oob/03r/reproducing
Normal file
|
@ -0,0 +1 @@
|
||||||
|
im = Image.open(d); im.seek(0); im.getdata()
|
BIN
Tests/images/fli_oob/04r/04r00.fli
Normal file
BIN
Tests/images/fli_oob/04r/04r00.fli
Normal file
Binary file not shown.
BIN
Tests/images/fli_oob/04r/initial.fli
Normal file
BIN
Tests/images/fli_oob/04r/initial.fli
Normal file
Binary file not shown.
1
Tests/images/fli_oob/04r/notes
Normal file
1
Tests/images/fli_oob/04r/notes
Normal file
|
@ -0,0 +1 @@
|
||||||
|
failure to check input buffer (`data`) boundaries in BRUN chunk
|
BIN
Tests/images/fli_oob/04r/others/04r01.fli
Normal file
BIN
Tests/images/fli_oob/04r/others/04r01.fli
Normal file
Binary file not shown.
BIN
Tests/images/fli_oob/04r/others/04r02.fli
Normal file
BIN
Tests/images/fli_oob/04r/others/04r02.fli
Normal file
Binary file not shown.
BIN
Tests/images/fli_oob/04r/others/04r03.fli
Normal file
BIN
Tests/images/fli_oob/04r/others/04r03.fli
Normal file
Binary file not shown.
BIN
Tests/images/fli_oob/04r/others/04r04.fli
Normal file
BIN
Tests/images/fli_oob/04r/others/04r04.fli
Normal file
Binary file not shown.
BIN
Tests/images/fli_oob/04r/others/04r05.fli
Normal file
BIN
Tests/images/fli_oob/04r/others/04r05.fli
Normal file
Binary file not shown.
1
Tests/images/fli_oob/04r/reproducing
Normal file
1
Tests/images/fli_oob/04r/reproducing
Normal file
|
@ -0,0 +1 @@
|
||||||
|
im = Image.open(d); im.seek(0); im.getdata()
|
BIN
Tests/images/fli_oob/05r/05r00.fli
Normal file
BIN
Tests/images/fli_oob/05r/05r00.fli
Normal file
Binary file not shown.
1
Tests/images/fli_oob/05r/notes
Normal file
1
Tests/images/fli_oob/05r/notes
Normal file
|
@ -0,0 +1 @@
|
||||||
|
failure to check input buffer (`data`) boundaries in LC chunk
|
BIN
Tests/images/fli_oob/05r/others/05r01.fli
Normal file
BIN
Tests/images/fli_oob/05r/others/05r01.fli
Normal file
Binary file not shown.
BIN
Tests/images/fli_oob/05r/others/05r02.fli
Normal file
BIN
Tests/images/fli_oob/05r/others/05r02.fli
Normal file
Binary file not shown.
BIN
Tests/images/fli_oob/05r/others/05r03.fli
Normal file
BIN
Tests/images/fli_oob/05r/others/05r03.fli
Normal file
Binary file not shown.
BIN
Tests/images/fli_oob/05r/others/05r04.fli
Normal file
BIN
Tests/images/fli_oob/05r/others/05r04.fli
Normal file
Binary file not shown.
BIN
Tests/images/fli_oob/05r/others/05r05.fli
Normal file
BIN
Tests/images/fli_oob/05r/others/05r05.fli
Normal file
Binary file not shown.
BIN
Tests/images/fli_oob/05r/others/05r06.fli
Normal file
BIN
Tests/images/fli_oob/05r/others/05r06.fli
Normal file
Binary file not shown.
BIN
Tests/images/fli_oob/05r/others/05r07.fli
Normal file
BIN
Tests/images/fli_oob/05r/others/05r07.fli
Normal file
Binary file not shown.
1
Tests/images/fli_oob/05r/reproducing
Normal file
1
Tests/images/fli_oob/05r/reproducing
Normal file
|
@ -0,0 +1 @@
|
||||||
|
im = Image.open(d); im.seek(0); im.getdata()
|
BIN
Tests/images/fli_oob/06r/06r00.fli
Normal file
BIN
Tests/images/fli_oob/06r/06r00.fli
Normal file
Binary file not shown.
1
Tests/images/fli_oob/06r/notes
Normal file
1
Tests/images/fli_oob/06r/notes
Normal file
|
@ -0,0 +1 @@
|
||||||
|
failure to check input buffer (`data`) boundaries in SS2 chunk
|
BIN
Tests/images/fli_oob/06r/others/06r01.fli
Normal file
BIN
Tests/images/fli_oob/06r/others/06r01.fli
Normal file
Binary file not shown.
BIN
Tests/images/fli_oob/06r/others/06r02.fli
Normal file
BIN
Tests/images/fli_oob/06r/others/06r02.fli
Normal file
Binary file not shown.
BIN
Tests/images/fli_oob/06r/others/06r03.fli
Normal file
BIN
Tests/images/fli_oob/06r/others/06r03.fli
Normal file
Binary file not shown.
BIN
Tests/images/fli_oob/06r/others/06r04.fli
Normal file
BIN
Tests/images/fli_oob/06r/others/06r04.fli
Normal file
Binary file not shown.
1
Tests/images/fli_oob/06r/reproducing
Normal file
1
Tests/images/fli_oob/06r/reproducing
Normal file
|
@ -0,0 +1 @@
|
||||||
|
im = Image.open(d); im.seek(0); im.getdata()
|
BIN
Tests/images/fli_oob/patch0/000000
Normal file
BIN
Tests/images/fli_oob/patch0/000000
Normal file
Binary file not shown.
BIN
Tests/images/fli_oob/patch0/000001
Normal file
BIN
Tests/images/fli_oob/patch0/000001
Normal file
Binary file not shown.
BIN
Tests/images/fli_oob/patch0/000002
Normal file
BIN
Tests/images/fli_oob/patch0/000002
Normal file
Binary file not shown.
BIN
Tests/images/fli_oob/patch0/000003
Normal file
BIN
Tests/images/fli_oob/patch0/000003
Normal file
Binary file not shown.
|
@ -24,6 +24,11 @@
|
||||||
#define I32(ptr)\
|
#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, Py_ssize_t bytes)
|
ImagingFliDecode(Imaging im, ImagingCodecState state, UINT8* buf, Py_ssize_t bytes)
|
||||||
|
@ -78,10 +83,12 @@ ImagingFliDecode(Imaging im, ImagingCodecState state, UINT8* buf, Py_ssize_t byt
|
||||||
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) */
|
||||||
|
/* OOB ok, we've got 4 bytes min on entry */
|
||||||
lines = I16(data); data += 2;
|
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;
|
||||||
|
ERR_IF_DATA_OOB(2)
|
||||||
packets = I16(data); data += 2;
|
packets = I16(data); data += 2;
|
||||||
while (packets & 0x8000) {
|
while (packets & 0x8000) {
|
||||||
/* flag word */
|
/* flag word */
|
||||||
|
@ -91,29 +98,33 @@ 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;
|
||||||
}
|
}
|
||||||
|
ERR_IF_DATA_OOB(2)
|
||||||
packets = I16(data); data += 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) {
|
||||||
|
ERR_IF_DATA_OOB(4)
|
||||||
i = 256-data[1]; /* run */
|
i = 256-data[1]; /* run */
|
||||||
if (x + i + i > state->xsize)
|
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;
|
||||||
}
|
}
|
||||||
|
@ -129,22 +140,27 @@ 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) */
|
||||||
|
/* OOB Check ok, we have 4 bytes min here */
|
||||||
y = I16(data); ymax = y + I16(data+2); data += 4;
|
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;
|
||||||
}
|
}
|
||||||
|
@ -165,14 +181,18 @@ ImagingFliDecode(Imaging im, ImagingCodecState state, UINT8* buf, Py_ssize_t byt
|
||||||
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 {
|
||||||
|
@ -192,9 +212,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 +232,10 @@ ImagingFliDecode(Imaging im, ImagingCodecState state, UINT8* buf, Py_ssize_t byt
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
advance = I32(ptr);
|
advance = I32(ptr);
|
||||||
|
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