CVE-2021-25287,CVE-2021-25288: Fix OOB Read in Jpeg2KDecode

This commit is contained in:
Emilie Yu 2022-02-11 12:12:45 -08:00
parent 414de92fe3
commit 4b207548e0
9 changed files with 93 additions and 2 deletions

View File

@ -2,6 +2,14 @@
Changelog (Pillow) 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) 6.2.2.1 (2021-10-08)
------------------ ------------------

View File

@ -4,6 +4,8 @@ from PIL import Image, Jpeg2KImagePlugin
from .helper import PillowTestCase from .helper import PillowTestCase
import pytest
codecs = dir(Image.core) codecs = dir(Image.core)
test_card = Image.open("Tests/images/test-card.png") test_card = Image.open("Tests/images/test-card.png")
@ -210,3 +212,19 @@ class TestFileJpeg2k(PillowTestCase):
# Assert # Assert
self.assertEqual(p.image.size, (640, 480)) 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:: .. toctree::
:maxdepth: 2 :maxdepth: 2
6.2.2.2
6.2.2.1 6.2.2.1
6.2.2 6.2.2
6.2.1 6.2.1

View File

@ -557,8 +557,9 @@ j2k_decode_entry(Imaging im, ImagingCodecState state)
opj_dparameters_t params; opj_dparameters_t params;
OPJ_COLOR_SPACE color_space; OPJ_COLOR_SPACE color_space;
j2k_unpacker_t unpack = NULL; j2k_unpacker_t unpack = NULL;
size_t buffer_size = 0; size_t buffer_size = 0, tile_bytes = 0;
unsigned n; unsigned n, tile_height, tile_width;
int total_component_width = 0;
stream = opj_stream_create(BUFFER_SIZE, OPJ_TRUE); 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.x1 = (tile_info.x1 + correction) >> context->reduce;
tile_info.y1 = (tile_info.y1 + 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) { if (buffer_size < tile_info.data_size) {
/* malloc check ok, tile_info.data_size from openjpeg */ /* malloc check ok, tile_info.data_size from openjpeg */
UINT8 *new = realloc (state->buffer, tile_info.data_size); UINT8 *new = realloc (state->buffer, tile_info.data_size);