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