CVE-2017-14175 (published 2017-09-07T06:29Z)

In coders/xbm.c in ImageMagick 7.0.6-1 Q16, a DoS in ReadXBMImage() due to lack of an EOF (End of File) check might cause huge CPU consumption. When a crafted XBM file, which claims large rows and columns fields in the header but does not contain sufficient backing data, is provided, the loop over the rows would consume huge CPU resources, since there is no EOF check inside the loop.

Severity: HIGH
CVSS v2 base score: 7.1 (AV:N/AC:M/Au:N/C:N/I:N/A:C)
CVSS v3 base score: 6.5, MEDIUM (CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H)

Weakness information:
cwe_id: CWE-834
cwe_name: Excessive Iteration
description: The product performs an iteration or loop without sufficiently limiting the number of times that the loop is executed.
extended_description: If the iteration can be influenced by an attacker, this weakness could allow attackers to consume excessive resources such as CPU or memory. In many cases, a loop does not need to be infinite in order to cause enough resource consumption to adversely affect the product or its host system; it depends on the amount of resources consumed per iteration.
         

Fix information:
repo_url: https://github.com/ImageMagick/ImageMagick
commit_details: repo_url: https://github.com/ImageMagick/ImageMagick
author: Cristy
author_date: 2017-08-31 09:06:56-04:00
msg: https://github.com/ImageMagick/ImageMagick/issues/712
repository: repo_url: https://github.com/ImageMagick/ImageMagick
repo_name: ImageMagick/ImageMagick
description: 🧙‍♂️ ImageMagick 7
repo_language: C
owner: ImageMagick
file_changes: filename: xbm.c
change_type: ModificationType.MODIFY
diff: @@ -131,7 +131,7 @@ static MagickBooleanType IsXBM(const unsigned char *magick,const size_t length)
 %
 */
 
-static unsigned int XBMInteger(Image *image,short int *hex_digits)
+static int XBMInteger(Image *image,short int *hex_digits)
 { 
   int
     c;
@@ -146,7 +146,7 @@ static unsigned int XBMInteger(Image *image,short int *hex_digits)
   { 
     c=ReadBlobByte(image);
     if (c == EOF)
-      return(0);
+      return(-1);
   } while ((c == ' ') || (c == '\t') || (c == '\n') || (c == '\r'));
   /*
     Evaluate number.
@@ -163,9 +163,9 @@ static unsigned int XBMInteger(Image *image,short int *hex_digits)
     value+=hex_digits[c];
     c=ReadBlobByte(image);
     if (c == EOF)
-      return(0);
+      return(-1);
   } while (hex_digits[c] >= 0);
-  return(value);
+  return((int) value);
 }
 
 static Image *ReadXBMImage(const ImageInfo *image_info,ExceptionInfo *exception)
@@ -177,6 +177,9 @@ static Image *ReadXBMImage(const ImageInfo *image_info,ExceptionInfo *exception)
   Image
     *image;
 
+  int
+    c;
+
   MagickBooleanType
     status;
 
@@ -206,7 +209,6 @@ static Image *ReadXBMImage(const ImageInfo *image_info,ExceptionInfo *exception)
     height,
     length,
     padding,
-    value,
     version,
     width;
 
@@ -282,12 +284,12 @@ static Image *ReadXBMImage(const ImageInfo *image_info,ExceptionInfo *exception)
   /*
     Initialize colormap.
   */
-  image->colormap[0].red=QuantumRange;
-  image->colormap[0].green=QuantumRange;
-  image->colormap[0].blue=QuantumRange;
-  image->colormap[1].red=(Quantum) 0;
-  image->colormap[1].green=(Quantum) 0;
-  image->colormap[1].blue=(Quantum) 0;
+  image->colormap[0].red=(MagickRealType) QuantumRange;
+  image->colormap[0].green=(MagickRealType) QuantumRange;
+  image->colormap[0].blue=(MagickRealType) QuantumRange;
+  image->colormap[1].red=0.0;
+  image->colormap[1].green=0.0;
+  image->colormap[1].blue=0.0;
   if (image_info->ping != MagickFalse)
     {
       (void) CloseBlob(image);
@@ -344,16 +346,25 @@ static Image *ReadXBMImage(const ImageInfo *image_info,ExceptionInfo *exception)
   if (version == 10)
     for (i=0; i < (ssize_t) (bytes_per_line*image->rows); (i+=2))
     {
-      value=XBMInteger(image,hex_digits);
-      *p++=(unsigned char) value;
+      c=XBMInteger(image,hex_digits);
+      if (c < 0)
+        break;
+      *p++=(unsigned char) c;
       if ((padding == 0) || (((i+2) % bytes_per_line) != 0))
-        *p++=(unsigned char) (value >> 8);
+        *p++=(unsigned char) (c >> 8);
     }
   else
     for (i=0; i < (ssize_t) (bytes_per_line*image->rows); i++)
     {
-      value=XBMInteger(image,hex_digits);
-      *p++=(unsigned char) value;
+      c=XBMInteger(image,hex_digits);
+      if (c < 0)
+        break;
+      *p++=(unsigned char) c;
+    }
+  if (EOFBlob(image) != MagickFalse)
+    {
+      data=(unsigned char *) RelinquishMagickMemory(data);
+      ThrowReaderException(CorruptImageError,"UnexpectedEndOfFile");
     }
   /*
     Convert X bitmap image to pixel packets.
@@ -369,7 +380,7 @@ static Image *ReadXBMImage(const ImageInfo *image_info,ExceptionInfo *exception)
     for (x=0; x < (ssize_t) image->columns; x++)
     {
       if (bit == 0)
-        byte=(size_t) (*p++);
+        byte=(unsigned int) (*p++);
       SetPixelIndex(image,(Quantum) ((byte & 0x01) != 0 ? 0x01 : 0x00),q);
       bit++;
       byte>>=1;

programming_language: Objective-C