Vulnerability: OpenJPEG before 2.3.1 has a heap buffer overflow in color_apply_icc_profile in bin/common/color.c.
Vulnerability ID: CVE-2018-21010
CWE: CWE-787
Severity score: 6.4
Project: https://github.com/uclouvain/openjpeg
Published: 2019-09-05
File: src/bin/common/color.c
Commit message: color_apply_icc_profile: avoid potential heap buffer overflow

Derived from a patch by Thuan Pham
Commit author: Even Rouault

Vulnerable version (before fix):
 void color_apply_icc_profile(opj_image_t *image)     }      if (image->numcomps > 2) { /* RGB, RGBA */         if (prec <= 8) {             unsigned char *inbuf, *outbuf, *in, *out;              max = max_w * max_h;             nr_samples = (size_t)(max * 3U * sizeof(unsigned char));             in = inbuf = (unsigned char*)opj_image_data_alloc(nr_samples);             out = outbuf = (unsigned char*)opj_image_data_alloc(nr_samples);              if (inbuf == NULL || outbuf == NULL) {                 goto fails0;             }              r = image->comps[0].data;             g = image->comps[1].data;             b = image->comps[2].data;              for (i = 0U; i < max; ++i) {                 *in++ = (unsigned char) * r++;                 *in++ = (unsigned char) * g++;                 *in++ = (unsigned char) * b++;             }              cmsDoTransform(transform, inbuf, outbuf, (cmsUInt32Number)max);              r = image->comps[0].data;             g = image->comps[1].data;             b = image->comps[2].data;              for (i = 0U; i < max; ++i) {                 *r++ = (int) * out++;                 *g++ = (int) * out++;                 *b++ = (int) * out++;             }             ok = 1;  fails0:             opj_image_data_free(inbuf);             opj_image_data_free(outbuf);         } else { /* prec > 8 */             unsigned short *inbuf, *outbuf, *in, *out;              max = max_w * max_h;             nr_samples = (size_t)(max * 3U * sizeof(unsigned short));             in = inbuf = (unsigned short*)opj_image_data_alloc(nr_samples);             out = outbuf = (unsigned short*)opj_image_data_alloc(nr_samples);              if (inbuf == NULL || outbuf == NULL) {                 goto fails1;             }              r = image->comps[0].data;             g = image->comps[1].data;             b = image->comps[2].data;              for (i = 0U  ; i < max; ++i) {                 *in++ = (unsigned short) * r++;                 *in++ = (unsigned short) * g++;                 *in++ = (unsigned short) * b++;             }              cmsDoTransform(transform, inbuf, outbuf, (cmsUInt32Number)max);              r = image->comps[0].data;             g = image->comps[1].data;             b = image->comps[2].data;              for (i = 0; i < max; ++i) {                 *r++ = (int) * out++;                 *g++ = (int) * out++;                 *b++ = (int) * out++;             }             ok = 1;  fails1:             opj_image_data_free(inbuf);             opj_image_data_free(outbuf);         }     } else { /* image->numcomps <= 2 : GRAY, GRAYA */         if (prec <= 8) {

Fixed version (after fix):
 void color_apply_icc_profile(opj_image_t *image)     }      if (image->numcomps > 2) { /* RGB, RGBA */         if ((image->comps[0].w == image->comps[1].w &&                 image->comps[0].w == image->comps[2].w) &&                 (image->comps[0].h == image->comps[1].h &&                  image->comps[0].h == image->comps[2].h)) {             if (prec <= 8) {                 unsigned char *inbuf, *outbuf, *in, *out;                  max = max_w * max_h;                 nr_samples = (size_t)(max * 3U * sizeof(unsigned char));                 in = inbuf = (unsigned char*)opj_image_data_alloc(nr_samples);                 out = outbuf = (unsigned char*)opj_image_data_alloc(nr_samples);                  if (inbuf == NULL || outbuf == NULL) {                     goto fails0;                 }                  r = image->comps[0].data;                 g = image->comps[1].data;                 b = image->comps[2].data;                  for (i = 0U; i < max; ++i) {                     *in++ = (unsigned char) * r++;                     *in++ = (unsigned char) * g++;                     *in++ = (unsigned char) * b++;                 }                  cmsDoTransform(transform, inbuf, outbuf, (cmsUInt32Number)max);                  r = image->comps[0].data;                 g = image->comps[1].data;                 b = image->comps[2].data;                  for (i = 0U; i < max; ++i) {                     *r++ = (int) * out++;                     *g++ = (int) * out++;                     *b++ = (int) * out++;                 }                 ok = 1;  fails0:                 opj_image_data_free(inbuf);                 opj_image_data_free(outbuf);             } else { /* prec > 8 */                 unsigned short *inbuf, *outbuf, *in, *out;                  max = max_w * max_h;                 nr_samples = (size_t)(max * 3U * sizeof(unsigned short));                 in = inbuf = (unsigned short*)opj_image_data_alloc(nr_samples);                 out = outbuf = (unsigned short*)opj_image_data_alloc(nr_samples);                  if (inbuf == NULL || outbuf == NULL) {                     goto fails1;                 }                  r = image->comps[0].data;                 g = image->comps[1].data;                 b = image->comps[2].data;                  for (i = 0U  ; i < max; ++i) {                     *in++ = (unsigned short) * r++;                     *in++ = (unsigned short) * g++;                     *in++ = (unsigned short) * b++;                 }                  cmsDoTransform(transform, inbuf, outbuf, (cmsUInt32Number)max);                  r = image->comps[0].data;                 g = image->comps[1].data;                 b = image->comps[2].data;                  for (i = 0; i < max; ++i) {                     *r++ = (int) * out++;                     *g++ = (int) * out++;                     *b++ = (int) * out++;                 }                 ok = 1;  fails1:                 opj_image_data_free(inbuf);                 opj_image_data_free(outbuf);             }         } else {             fprintf(stderr,                     "[ERROR] Image components should have the same width and height\n");             cmsDeleteTransform(transform);             return;         }     } else { /* image->numcomps <= 2 : GRAY, GRAYA */         if (prec <= 8) {

Patch:
patch: @@ -597,82 +597,92 @@ void color_apply_icc_profile(opj_image_t *image)
     }
 
     if (image->numcomps > 2) { /* RGB, RGBA */
-        if (prec <= 8) {
-            unsigned char *inbuf, *outbuf, *in, *out;
-
-            max = max_w * max_h;
-            nr_samples = (size_t)(max * 3U * sizeof(unsigned char));
-            in = inbuf = (unsigned char*)opj_image_data_alloc(nr_samples);
-            out = outbuf = (unsigned char*)opj_image_data_alloc(nr_samples);
-
-            if (inbuf == NULL || outbuf == NULL) {
-                goto fails0;
-            }
-
-            r = image->comps[0].data;
-            g = image->comps[1].data;
-            b = image->comps[2].data;
-
-            for (i = 0U; i < max; ++i) {
-                *in++ = (unsigned char) * r++;
-                *in++ = (unsigned char) * g++;
-                *in++ = (unsigned char) * b++;
-            }
-
-            cmsDoTransform(transform, inbuf, outbuf, (cmsUInt32Number)max);
-
-            r = image->comps[0].data;
-            g = image->comps[1].data;
-            b = image->comps[2].data;
-
-            for (i = 0U; i < max; ++i) {
-                *r++ = (int) * out++;
-                *g++ = (int) * out++;
-                *b++ = (int) * out++;
-            }
-            ok = 1;
+        if ((image->comps[0].w == image->comps[1].w &&
+                image->comps[0].w == image->comps[2].w) &&
+                (image->comps[0].h == image->comps[1].h &&
+                 image->comps[0].h == image->comps[2].h)) {
+            if (prec <= 8) {
+                unsigned char *inbuf, *outbuf, *in, *out;
+
+                max = max_w * max_h;
+                nr_samples = (size_t)(max * 3U * sizeof(unsigned char));
+                in = inbuf = (unsigned char*)opj_image_data_alloc(nr_samples);
+                out = outbuf = (unsigned char*)opj_image_data_alloc(nr_samples);
+
+                if (inbuf == NULL || outbuf == NULL) {
+                    goto fails0;
+                }
+
+                r = image->comps[0].data;
+                g = image->comps[1].data;
+                b = image->comps[2].data;
+
+                for (i = 0U; i < max; ++i) {
+                    *in++ = (unsigned char) * r++;
+                    *in++ = (unsigned char) * g++;
+                    *in++ = (unsigned char) * b++;
+                }
+
+                cmsDoTransform(transform, inbuf, outbuf, (cmsUInt32Number)max);
+
+                r = image->comps[0].data;
+                g = image->comps[1].data;
+                b = image->comps[2].data;
+
+                for (i = 0U; i < max; ++i) {
+                    *r++ = (int) * out++;
+                    *g++ = (int) * out++;
+                    *b++ = (int) * out++;
+                }
+                ok = 1;
 
 fails0:
-            opj_image_data_free(inbuf);
-            opj_image_data_free(outbuf);
-        } else { /* prec > 8 */
-            unsigned short *inbuf, *outbuf, *in, *out;
-
-            max = max_w * max_h;
-            nr_samples = (size_t)(max * 3U * sizeof(unsigned short));
-            in = inbuf = (unsigned short*)opj_image_data_alloc(nr_samples);
-            out = outbuf = (unsigned short*)opj_image_data_alloc(nr_samples);
-
-            if (inbuf == NULL || outbuf == NULL) {
-                goto fails1;
-            }
-
-            r = image->comps[0].data;
-            g = image->comps[1].data;
-            b = image->comps[2].data;
-
-            for (i = 0U  ; i < max; ++i) {
-                *in++ = (unsigned short) * r++;
-                *in++ = (unsigned short) * g++;
-                *in++ = (unsigned short) * b++;
-            }
-
-            cmsDoTransform(transform, inbuf, outbuf, (cmsUInt32Number)max);
-
-            r = image->comps[0].data;
-            g = image->comps[1].data;
-            b = image->comps[2].data;
-
-            for (i = 0; i < max; ++i) {
-                *r++ = (int) * out++;
-                *g++ = (int) * out++;
-                *b++ = (int) * out++;
-            }
-            ok = 1;
+                opj_image_data_free(inbuf);
+                opj_image_data_free(outbuf);
+            } else { /* prec > 8 */
+                unsigned short *inbuf, *outbuf, *in, *out;
+
+                max = max_w * max_h;
+                nr_samples = (size_t)(max * 3U * sizeof(unsigned short));
+                in = inbuf = (unsigned short*)opj_image_data_alloc(nr_samples);
+                out = outbuf = (unsigned short*)opj_image_data_alloc(nr_samples);
+
+                if (inbuf == NULL || outbuf == NULL) {
+                    goto fails1;
+                }
+
+                r = image->comps[0].data;
+                g = image->comps[1].data;
+                b = image->comps[2].data;
+
+                for (i = 0U  ; i < max; ++i) {
+                    *in++ = (unsigned short) * r++;
+                    *in++ = (unsigned short) * g++;
+                    *in++ = (unsigned short) * b++;
+                }
+
+                cmsDoTransform(transform, inbuf, outbuf, (cmsUInt32Number)max);
+
+                r = image->comps[0].data;
+                g = image->comps[1].data;
+                b = image->comps[2].data;
+
+                for (i = 0; i < max; ++i) {
+                    *r++ = (int) * out++;
+                    *g++ = (int) * out++;
+                    *b++ = (int) * out++;
+                }
+                ok = 1;
 
 fails1:
-            opj_image_data_free(inbuf);
-            opj_image_data_free(outbuf);
+                opj_image_data_free(inbuf);
+                opj_image_data_free(outbuf);
+            }
+        } else {
+            fprintf(stderr,
+                    "[ERROR] Image components should have the same width and height\n");
+            cmsDeleteTransform(transform);
+            return;
         }
     } else { /* image->numcomps <= 2 : GRAY, GRAYA */
         if (prec <= 8) {
path: src/bin/common/color.c