convertbmp: fix issues with zero bitmasks 1148/head
authorHugo Lefeuvre <hle@debian.org>
Sat, 22 Sep 2018 18:33:19 +0000 (14:33 -0400)
committerHugo Lefeuvre <hle@debian.org>
Sat, 22 Sep 2018 18:51:50 +0000 (14:51 -0400)
In the case where a BMP file declares compression 3 (BI_BITFIELDS)
with header size <= 56, all bitmask values keep their initialization
value 0. This may lead to various undefined behavior later e.g. when
doing 1 << (l_comp->prec - 1).

This issue does not affect files with bit count 16 because of a check
added in 16240e2 which sets default values to the color masks if they
are all 0.

This commit adds similar checks for the 32 bit case.

Also, if a BMP file declares compression 3 with header size >= 56 and
intentional 0 bitmasks, the same issue will be triggered in both the
16 and 32 bit count case.

This commit adds checks to bmp_read_info_header() rejecting BMP files
with "intentional" 0 bitmasks. These checks might be removed in the
future when proper handling of zero bitmasks will be available in
openjpeg2.

fixes #1057 (CVE-2018-5785)

src/bin/jp2/convertbmp.c

index 084f70bb75f86ad6ff52bacba10cbe50264b9cdc..7fde99ab3ef21f6a043ba1d8ada85d5030a943fe 100644 (file)
@@ -435,16 +435,31 @@ static OPJ_BOOL bmp_read_info_header(FILE* IN, OPJ_BITMAPINFOHEADER* header)
         header->biRedMask |= (OPJ_UINT32)getc(IN) << 16;
         header->biRedMask |= (OPJ_UINT32)getc(IN) << 24;
 
+        if (!header->biRedMask) {
+            fprintf(stderr, "Error, invalid red mask value %d\n", header->biRedMask);
+            return OPJ_FALSE;
+        }
+
         header->biGreenMask  = (OPJ_UINT32)getc(IN);
         header->biGreenMask |= (OPJ_UINT32)getc(IN) << 8;
         header->biGreenMask |= (OPJ_UINT32)getc(IN) << 16;
         header->biGreenMask |= (OPJ_UINT32)getc(IN) << 24;
 
+        if (!header->biGreenMask) {
+            fprintf(stderr, "Error, invalid green mask value %d\n", header->biGreenMask);
+            return OPJ_FALSE;
+        }
+
         header->biBlueMask  = (OPJ_UINT32)getc(IN);
         header->biBlueMask |= (OPJ_UINT32)getc(IN) << 8;
         header->biBlueMask |= (OPJ_UINT32)getc(IN) << 16;
         header->biBlueMask |= (OPJ_UINT32)getc(IN) << 24;
 
+        if (!header->biBlueMask) {
+            fprintf(stderr, "Error, invalid blue mask value %d\n", header->biBlueMask);
+            return OPJ_FALSE;
+        }
+
         header->biAlphaMask  = (OPJ_UINT32)getc(IN);
         header->biAlphaMask |= (OPJ_UINT32)getc(IN) << 8;
         header->biAlphaMask |= (OPJ_UINT32)getc(IN) << 16;
@@ -831,6 +846,12 @@ opj_image_t* bmptoimage(const char *filename, opj_cparameters_t *parameters)
         bmpmask32toimage(pData, stride, image, 0x00FF0000U, 0x0000FF00U, 0x000000FFU,
                          0x00000000U);
     } else if (Info_h.biBitCount == 32 && Info_h.biCompression == 3) { /* bitmask */
+        if ((Info_h.biRedMask == 0U) && (Info_h.biGreenMask == 0U) &&
+                (Info_h.biBlueMask == 0U)) {
+            Info_h.biRedMask   = 0x00FF0000U;
+            Info_h.biGreenMask = 0x0000FF00U;
+            Info_h.biBlueMask  = 0x000000FFU;
+        }
         bmpmask32toimage(pData, stride, image, Info_h.biRedMask, Info_h.biGreenMask,
                          Info_h.biBlueMask, Info_h.biAlphaMask);
     } else if (Info_h.biBitCount == 16 && Info_h.biCompression == 0) { /* RGBX */