CVE-2019-12973: Excessive Iteration (CWE-834)
value: In OpenJPEG 2.3.1, there is excessive iteration in the opj_t1_encode_cblks function of openjp2/t1.c. Remote attackers could leverage this vulnerability to cause a denial of service via a crafted bmp file. This issue is similar to CVE-2018-6616.
CWE description: The product performs an iteration or loop without sufficiently limiting the number of times that the loop is executed.
CVSS v3 base score: 5.5
Published: 2019-06-26T18:15Z
Repository: https://github.com/uclouvain/openjpeg
Language: C
Files changed: src/bin/jp2/convertbmp.c
Commit date: 2018-12-14 05:10:35 +0100
Commit message: convertbmp: detect invalid file dimensions early

width/length dimensions read from bmp headers are not necessarily
valid. For instance they may have been maliciously set to very large
values with the intention to cause DoS (large memory allocation, stack
overflow). In these cases we want to detect the invalid size as early
as possible.

This commit introduces a counter which verifies that the number of
written bytes corresponds to the advertized width/length.

Fixes #1059 (CVE-2018-6616).

Diff: diff --git a/src/bin/jp2/convertbmp.c b/src/bin/jp2/convertbmp.c
index 85a47feaf..0af52f816 100644
--- a/src/bin/jp2/convertbmp.c
+++ b/src/bin/jp2/convertbmp.c
@@ -532,18 +532,18 @@ static OPJ_BOOL bmp_read_raw_data(FILE* IN, OPJ_UINT8* pData, OPJ_UINT32 stride,
 }
 
 static OPJ_BOOL bmp_read_rle8_data(FILE* IN, OPJ_UINT8* pData,
                                    OPJ_UINT32 stride, OPJ_UINT32 width, OPJ_UINT32 height)
 {
-    OPJ_UINT32 x, y;
+    OPJ_UINT32 x, y, written;
     OPJ_UINT8 *pix;
     const OPJ_UINT8 *beyond;
 
     beyond = pData + stride * height;
     pix = pData;
 
-    x = y = 0U;
+    x = y = written = 0U;
     while (y < height) {
         int c = getc(IN);
         if (c == EOF) {
             return OPJ_FALSE;
         }
@@ -559,10 +559,11 @@ static OPJ_BOOL bmp_read_rle8_data(FILE* IN, OPJ_UINT8* pData,
             c1 = (OPJ_UINT8)c1_int;
 
             for (j = 0; (j < c) && (x < width) &&
                     ((OPJ_SIZE_T)pix < (OPJ_SIZE_T)beyond); j++, x++, pix++) {
                 *pix = c1;
+                written++;
             }
         } else {
             c = getc(IN);
             if (c == EOF) {
                 return OPJ_FALSE;
@@ -596,20 +597,27 @@ static OPJ_BOOL bmp_read_rle8_data(FILE* IN, OPJ_UINT8* pData,
                     if (c1_int == EOF) {
                         return OPJ_FALSE;
                     }
                     c1 = (OPJ_UINT8)c1_int;
                     *pix = c1;
+                    written++;
                 }
                 if ((OPJ_UINT32)c & 1U) { /* skip padding byte */
                     c = getc(IN);
                     if (c == EOF) {
                         return OPJ_FALSE;
                     }
                 }
             }
         }
     }/* while() */
+
+    if (written != width * height) {
+        fprintf(stderr, "warning, image's actual size does not match advertized one\n");
+        return OPJ_FALSE;
+    }
+
     return OPJ_TRUE;
 }
 
 static OPJ_BOOL bmp_read_rle4_data(FILE* IN, OPJ_UINT8* pData,
                                    OPJ_UINT32 stride, OPJ_UINT32 width, OPJ_UINT32 height)

Vulnerable code:     OPJ_UINT32 x, y;
    x = y = 0U;
Fixed code:     OPJ_UINT32 x, y, written;
    x = y = written = 0U;
                written++;
                    written++;

    if (written != width * height) {
        fprintf(stderr, "warning, image's actual size does not match advertized one\n");
        return OPJ_FALSE;
    }