ed67fe
From 9c781aa2020eef838284dcb348f4528f3c3cc1ab Mon Sep 17 00:00:00 2001
ed67fe
From: Lumir Balhar <lbalhar@redhat.com>
ed67fe
Date: Mon, 14 Jun 2021 09:06:07 +0200
ed67fe
Subject: [PATCH 1/5] CVE-2021-25287_25288
ed67fe
ed67fe
---
ed67fe
 src/libImaging/Jpeg2KDecode.c | 78 +++++++++++++++++++++++++++--------
ed67fe
 1 file changed, 61 insertions(+), 17 deletions(-)
ed67fe
ed67fe
diff --git a/src/libImaging/Jpeg2KDecode.c b/src/libImaging/Jpeg2KDecode.c
ed67fe
index 9140e00..fdbd0c0 100644
ed67fe
--- a/src/libImaging/Jpeg2KDecode.c
ed67fe
+++ b/src/libImaging/Jpeg2KDecode.c
ed67fe
@@ -110,6 +110,7 @@ j2ku_gray_l(opj_image_t *in, const JPEG2KTILEINFO *tileinfo,
ed67fe
     if (shift < 0)
ed67fe
         offset += 1 << (-shift - 1);
ed67fe
 
ed67fe
+    /* csiz*h*w + offset = tileinfo.datasize */
ed67fe
     switch (csiz) {
ed67fe
     case 1:
ed67fe
         for (y = 0; y < h; ++y) {
ed67fe
@@ -557,8 +558,10 @@ j2k_decode_entry(Imaging im, ImagingCodecState state)
ed67fe
     opj_dparameters_t params;
ed67fe
     OPJ_COLOR_SPACE color_space;
ed67fe
     j2k_unpacker_t unpack = NULL;
ed67fe
-    size_t buffer_size = 0;
ed67fe
-    unsigned n;
ed67fe
+    size_t buffer_size = 0, tile_bytes = 0;
ed67fe
+    unsigned n, tile_height, tile_width;
ed67fe
+    int total_component_width = 0;
ed67fe
+
ed67fe
 
ed67fe
     stream = opj_stream_create(BUFFER_SIZE, OPJ_TRUE);
ed67fe
 
ed67fe
@@ -703,8 +706,62 @@ j2k_decode_entry(Imaging im, ImagingCodecState state)
ed67fe
         tile_info.x1 = (tile_info.x1 + correction) >> context->reduce;
ed67fe
         tile_info.y1 = (tile_info.y1 + correction) >> context->reduce;
ed67fe
 
ed67fe
+        /* Check the tile bounds; if the tile is outside the image area,
ed67fe
+           or if it has a negative width or height (i.e. the coordinates are
ed67fe
+           swapped), bail. */
ed67fe
+        if (tile_info.x0 >= tile_info.x1
ed67fe
+            || tile_info.y0 >= tile_info.y1
ed67fe
+            || tile_info.x0 < image->x0
ed67fe
+            || tile_info.y0 < image->y0
ed67fe
+            || tile_info.x1 - image->x0 > im->xsize
ed67fe
+            || tile_info.y1 - image->y0 > im->ysize) {
ed67fe
+            state->errcode = IMAGING_CODEC_BROKEN;
ed67fe
+            state->state = J2K_STATE_FAILED;
ed67fe
+            goto quick_exit;
ed67fe
+        }
ed67fe
+
ed67fe
+        if (tile_info.nb_comps != image->numcomps) {
ed67fe
+            state->errcode = IMAGING_CODEC_BROKEN;
ed67fe
+            state->state = J2K_STATE_FAILED;
ed67fe
+            goto quick_exit;
ed67fe
+        }
ed67fe
+
ed67fe
+        /* Sometimes the tile_info.datasize we get back from openjpeg
ed67fe
+           is less than sum(comp_bytes)*w*h, and we overflow in the
ed67fe
+           shuffle stage */
ed67fe
+
ed67fe
+        tile_width = tile_info.x1 - tile_info.x0;
ed67fe
+        tile_height = tile_info.y1 - tile_info.y0;
ed67fe
+
ed67fe
+        /* Total component width = sum (component_width) e.g, it's
ed67fe
+         legal for an la file to have a 1 byte width for l, and 4 for
ed67fe
+         a. and then a malicious file could have a smaller tile_bytes
ed67fe
+        */
ed67fe
+
ed67fe
+        for (n=0; n < tile_info.nb_comps; n++) {
ed67fe
+            // see csize /acsize calcs
ed67fe
+            int csize = (image->comps[n].prec + 7) >> 3;
ed67fe
+            csize = (csize == 3) ? 4 : csize;
ed67fe
+            total_component_width += csize;
ed67fe
+        }
ed67fe
+        if ((tile_width > UINT_MAX / total_component_width) ||
ed67fe
+            (tile_height > UINT_MAX / total_component_width) ||
ed67fe
+            (tile_width > UINT_MAX / (tile_height * total_component_width)) ||
ed67fe
+            (tile_height > UINT_MAX / (tile_width * total_component_width))) {
ed67fe
+
ed67fe
+            state->errcode = IMAGING_CODEC_BROKEN;
ed67fe
+            state->state = J2K_STATE_FAILED;
ed67fe
+            goto quick_exit;
ed67fe
+        }
ed67fe
+
ed67fe
+        tile_bytes = tile_width * tile_height * total_component_width;
ed67fe
+
ed67fe
+        if (tile_bytes > tile_info.data_size) {
ed67fe
+            tile_info.data_size = tile_bytes;
ed67fe
+        }
ed67fe
+
ed67fe
         if (buffer_size < tile_info.data_size) {
ed67fe
-            /* malloc check ok, tile_info.data_size from openjpeg */
ed67fe
+            /* malloc check ok, overflow and tile size sanity check above */
ed67fe
             UINT8 *new = realloc (state->buffer, tile_info.data_size);
ed67fe
             if (!new) {
ed67fe
                 state->errcode = IMAGING_CODEC_MEMORY;
ed67fe
@@ -715,6 +772,7 @@ j2k_decode_entry(Imaging im, ImagingCodecState state)
ed67fe
             buffer_size = tile_info.data_size;
ed67fe
         }
ed67fe
 
ed67fe
+
ed67fe
         if (!opj_decode_tile_data(codec,
ed67fe
                                   tile_info.tile_index,
ed67fe
                                   (OPJ_BYTE *)state->buffer,
ed67fe
@@ -725,20 +783,6 @@ j2k_decode_entry(Imaging im, ImagingCodecState state)
ed67fe
             goto quick_exit;
ed67fe
         }
ed67fe
 
ed67fe
-        /* Check the tile bounds; if the tile is outside the image area,
ed67fe
-           or if it has a negative width or height (i.e. the coordinates are
ed67fe
-           swapped), bail. */
ed67fe
-        if (tile_info.x0 >= tile_info.x1
ed67fe
-            || tile_info.y0 >= tile_info.y1
ed67fe
-            || tile_info.x0 < image->x0
ed67fe
-            || tile_info.y0 < image->y0
ed67fe
-            || tile_info.x1 - image->x0 > im->xsize
ed67fe
-            || tile_info.y1 - image->y0 > im->ysize) {
ed67fe
-            state->errcode = IMAGING_CODEC_BROKEN;
ed67fe
-            state->state = J2K_STATE_FAILED;
ed67fe
-            goto quick_exit;
ed67fe
-        }
ed67fe
-
ed67fe
         unpack(image, &tile_info, state->buffer, im);
ed67fe
     }
ed67fe
 
ed67fe
-- 
ed67fe
2.31.1
ed67fe