Merge pull request #4 from ActiveState/BE-133-cve-2021-25287

BE-133 CVE-2021-25287, BE-134 CVE-2021-25288: Fix OOB Read in Jpeg2KDecode
This commit is contained in:
Rick Price 2022-02-14 13:08:29 -05:00 committed by GitHub
commit 04db0b815b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 93 additions and 2 deletions

View File

@ -2,6 +2,14 @@
Changelog (Pillow)
==================
6.2.2.2 (date TBD)
------------------
- This is the second Pillow release to support Python 2.7 from ActiveState
- Fix OOB Read in Jpeg2KDecode. CVE 2021-25287, CVE 2021-25288
[emilieyyu]
6.2.2.1 (2021-10-08)
------------------

View File

@ -4,6 +4,8 @@ from PIL import Image, Jpeg2KImagePlugin
from .helper import PillowTestCase
import pytest
codecs = dir(Image.core)
test_card = Image.open("Tests/images/test-card.png")
@ -210,3 +212,19 @@ class TestFileJpeg2k(PillowTestCase):
# Assert
self.assertEqual(p.image.size, (640, 480))
@pytest.mark.parametrize(
"test_file",
[
"Tests/images/crash-4fb027452e6988530aa5dabee76eecacb3b79f8a.j2k",
"Tests/images/crash-7d4c83eb92150fb8f1653a697703ae06ae7c4998.j2k",
"Tests/images/crash-ccca68ff40171fdae983d924e127a721cab2bd50.j2k",
"Tests/images/crash-d2c93af851d3ab9a19e34503626368b2ecde9c03.j2k",
],
)
def test_crashes(test_file):
with open(test_file, "rb") as f:
with Image.open(f) as im:
# Valgrind should not complain here
im.load()

View File

@ -0,0 +1,10 @@
6.2.2.2
-------
Security
========
This release addresses several critical CVEs.
CVE 2021-25287, CVE 2021-25288 has out-of-bounds read in J2kDecode, in
j2ku_graya_la.

View File

@ -6,6 +6,7 @@ Release Notes
.. toctree::
:maxdepth: 2
6.2.2.2
6.2.2.1
6.2.2
6.2.1

View File

@ -557,8 +557,9 @@ j2k_decode_entry(Imaging im, ImagingCodecState state)
opj_dparameters_t params;
OPJ_COLOR_SPACE color_space;
j2k_unpacker_t unpack = NULL;
size_t buffer_size = 0;
unsigned n;
size_t buffer_size = 0, tile_bytes = 0;
unsigned n, tile_height, tile_width;
int total_component_width = 0;
stream = opj_stream_create(BUFFER_SIZE, OPJ_TRUE);
@ -703,6 +704,59 @@ j2k_decode_entry(Imaging im, ImagingCodecState state)
tile_info.x1 = (tile_info.x1 + correction) >> context->reduce;
tile_info.y1 = (tile_info.y1 + correction) >> context->reduce;
/* Check the tile bounds; if the tile is outside the image area,
or if it has a negative width or height (i.e. the coordinates are
swapped), bail. */
if (tile_info.x0 >= tile_info.x1 || tile_info.y0 >= tile_info.y1 ||
tile_info.x0 < 0 || tile_info.y0 < 0 ||
(OPJ_UINT32)tile_info.x0 < image->x0 ||
(OPJ_UINT32)tile_info.y0 < image->y0 ||
(OPJ_INT32)(tile_info.x1 - image->x0) > im->xsize ||
(OPJ_INT32)(tile_info.y1 - image->y0) > im->ysize) {
state->errcode = IMAGING_CODEC_BROKEN;
state->state = J2K_STATE_FAILED;
goto quick_exit;
}
if (tile_info.nb_comps != image->numcomps) {
state->errcode = IMAGING_CODEC_BROKEN;
state->state = J2K_STATE_FAILED;
goto quick_exit;
}
/* Sometimes the tile_info.datasize we get back from openjpeg
is less than sum(comp_bytes)*w*h, and we overflow in the
shuffle stage */
tile_width = tile_info.x1 - tile_info.x0;
tile_height = tile_info.y1 - tile_info.y0;
/* Total component width = sum (component_width) e.g, it's
legal for an la file to have a 1 byte width for l, and 4 for
a. and then a malicious file could have a smaller tile_bytes
*/
for (n=0; n < tile_info.nb_comps; n++) {
// see csize /acsize calcs
int csize = (image->comps[n].prec + 7) >> 3;
csize = (csize == 3) ? 4 : csize;
total_component_width += csize;
}
if ((tile_width > UINT_MAX / total_component_width) ||
(tile_height > UINT_MAX / total_component_width) ||
(tile_width > UINT_MAX / (tile_height * total_component_width)) ||
(tile_height > UINT_MAX / (tile_width * total_component_width))) {
state->errcode = IMAGING_CODEC_BROKEN;
state->state = J2K_STATE_FAILED;
goto quick_exit;
}
tile_bytes = tile_width * tile_height * total_component_width;
if (tile_bytes > tile_info.data_size) {
tile_info.data_size = tile_bytes;
}
if (buffer_size < tile_info.data_size) {
/* malloc check ok, tile_info.data_size from openjpeg */
UINT8 *new = realloc (state->buffer, tile_info.data_size);