CVE-2017-14175: Excessive Iteration (CWE-834)
value: 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.
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: 6.5
Published: 2017-09-07T06:29Z
Repository: https://github.com/ImageMagick/ImageMagick
Language: C
Files changed: coders/xbm.c
Commit date: 2017-08-31 09:06:56 -0400
Commit message: https://github.com/ImageMagick/ImageMagick/issues/712

Diff: diff --git a/coders/xbm.c b/coders/xbm.c
index ce73160e338..ea2f76bf962 100644
--- a/coders/xbm.c
+++ b/coders/xbm.c
@@ -129,11 +129,11 @@ static MagickBooleanType IsXBM(const unsigned char *magick,const size_t length)
 %
 %    o exception: return any errors or warnings in this structure.
 %
 */
 
-static unsigned int XBMInteger(Image *image,short int *hex_digits)
+static int XBMInteger(Image *image,short int *hex_digits)
 { 
   int
     c;
   
   unsigned int
@@ -144,11 +144,11 @@ static unsigned int XBMInteger(Image *image,short int *hex_digits)
   */
   do
   { 
     c=ReadBlobByte(image);
     if (c == EOF)
-      return(0);
+      return(-1);
   } while ((c == ' ') || (c == '\t') || (c == '\n') || (c == '\r'));
   /*
     Evaluate number.
   */
   value=0;
@@ -161,13 +161,13 @@ static unsigned int XBMInteger(Image *image,short int *hex_digits)
     if (value > (unsigned int) (INT_MAX-hex_digits[c]))
       break;
     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)
 {
   char
@@ -175,10 +175,13 @@ static Image *ReadXBMImage(const ImageInfo *image_info,ExceptionInfo *exception)
     name[MagickPathExtent];
 
   Image
     *image;
 
+  int
+    c;
+
   MagickBooleanType
     status;
 
   register ssize_t
     i,
@@ -204,11 +207,10 @@ static Image *ReadXBMImage(const ImageInfo *image_info,ExceptionInfo *exception)
     byte,
     bytes_per_line,
     height,
     length,
     padding,
-    value,
     version,
     width;
 
   /*
     Open image file.
@@ -280,16 +282,16 @@ static Image *ReadXBMImage(const ImageInfo *image_info,ExceptionInfo *exception)
   if (AcquireImageColormap(image,image->colors,exception) == MagickFalse)
     ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
   /*
     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);
       return(GetFirstImageInList(image));
     }
@@ -342,20 +344,29 @@ static Image *ReadXBMImage(const ImageInfo *image_info,ExceptionInfo *exception)
     ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
   p=data;
   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.
   */
   p=data;
@@ -367,11 +378,11 @@ static Image *ReadXBMImage(const ImageInfo *image_info,ExceptionInfo *exception)
     bit=0;
     byte=0;
     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;
       if (bit == 8)
         bit=0;

Vulnerable code: static unsigned int XBMInteger(Image *image,short int *hex_digits)
      return(0);
      return(0);
  return(value);
    value,
  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;
      value=XBMInteger(image,hex_digits);
      *p++=(unsigned char) value;
        *p++=(unsigned char) (value >> 8);
      value=XBMInteger(image,hex_digits);
      *p++=(unsigned char) value;
        byte=(size_t) (*p++);
Fixed code: static int XBMInteger(Image *image,short int *hex_digits)
      return(-1);
      return(-1);
  return((int) value);
  int
    c;

  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;
      c=XBMInteger(image,hex_digits);
      if (c < 0)
        break;
      *p++=(unsigned char) c;
        *p++=(unsigned char) (c >> 8);
      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");
        byte=(unsigned int) (*p++);