Vulnerability: The XWD image (X Window System window dumping file) parsing component in ImageMagick 7.0.8-41 Q16 allows attackers to cause a denial-of-service (application crash resulting from an out-of-bounds Read) in ReadXWDImage in coders/xwd.c by crafting a corrupted XWD image file, a different vulnerability than CVE-2019-11472.
Vulnerability ID: CVE-2019-15139
CWE: CWE-125
Severity score: 2.9
Project: https://github.com/ImageMagick/ImageMagick
Published: 2019-08-18
File: coders/xwd.c
Commit message: https://github.com/ImageMagick/ImageMagick/issues/1553
Commit author: Cristy

Vulnerable version (before fix):
 static Image *ReadXWDImage(const ImageInfo *image_info,ExceptionInfo *exception)     ThrowReaderException(CorruptImageError,"FileFormatVersionMismatch");   if (header.header_size < sz_XWDheader)     ThrowReaderException(CorruptImageError,"ImproperImageHeader");   switch (header.visual_class)   {     case StaticGray: static Image *ReadXWDImage(const ImageInfo *image_info,ExceptionInfo *exception)     case PseudoColor:     {       if ((header.bits_per_pixel < 1) || (header.bits_per_pixel > 15) ||           (header.ncolors == 0))         ThrowReaderException(CorruptImageError,"ImproperImageHeader");       break;     } static Image *ReadXWDImage(const ImageInfo *image_info,ExceptionInfo *exception)     default:       ThrowReaderException(CorruptImageError,"ImproperImageHeader");   }   if (header.ncolors > 65535)     ThrowReaderException(CorruptImageError,"ImproperImageHeader");   if (((header.bitmap_pad % 8) != 0) || (header.bitmap_pad > 32))     ThrowReaderException(CorruptImageError,"ImproperImageHeader");   length=(size_t) (header.header_size-sz_XWDheader); static Image *ReadXWDImage(const ImageInfo *image_info,ExceptionInfo *exception)       XWDColor         color;        colors=(XColor *) AcquireQuantumMemory((size_t) header.ncolors,         sizeof(*colors));       if (colors == (XColor *) NULL)         {           ximage=(XImage *) RelinquishMagickMemory(ximage); ModuleExport size_t RegisterXWDImage(void)   entry->encoder=(EncodeImageHandler *) WriteXWDImage; #endif   entry->magick=(IsImageFormatHandler *) IsXWD;   entry->flags^=CoderAdjoinFlag;   (void) RegisterMagickInfo(entry);   return(MagickImageCoderSignature);

Fixed version (after fix):
 static Image *ReadXWDImage(const ImageInfo *image_info,ExceptionInfo *exception)     ThrowReaderException(CorruptImageError,"FileFormatVersionMismatch");   if (header.header_size < sz_XWDheader)     ThrowReaderException(CorruptImageError,"ImproperImageHeader");   if ((MagickSizeType) header.xoffset >= GetBlobSize(image))     ThrowReaderException(CorruptImageError,"ImproperImageHeader");   switch (header.visual_class)   {     case StaticGray: static Image *ReadXWDImage(const ImageInfo *image_info,ExceptionInfo *exception)     case PseudoColor:     {       if ((header.bits_per_pixel < 1) || (header.bits_per_pixel > 15) ||           (header.colormap_entries == 0))         ThrowReaderException(CorruptImageError,"ImproperImageHeader");       break;     } static Image *ReadXWDImage(const ImageInfo *image_info,ExceptionInfo *exception)     default:       ThrowReaderException(CorruptImageError,"ImproperImageHeader");   }   if (((header.bitmap_pad % 8) != 0) || (header.bitmap_pad > 32))     ThrowReaderException(CorruptImageError,"ImproperImageHeader");   length=(size_t) (header.header_size-sz_XWDheader); static Image *ReadXWDImage(const ImageInfo *image_info,ExceptionInfo *exception)       XWDColor         color;        length=(size_t) header.ncolors;       if (length > ((~0UL)/sizeof(*colors)))         ThrowReaderException(CorruptImageError,"ImproperImageHeader");       colors=(XColor *) AcquireQuantumMemory(length,sizeof(*colors));       if (colors == (XColor *) NULL)         {           ximage=(XImage *) RelinquishMagickMemory(ximage); ModuleExport size_t RegisterXWDImage(void)   entry->encoder=(EncodeImageHandler *) WriteXWDImage; #endif   entry->magick=(IsImageFormatHandler *) IsXWD;   entry->flags|=CoderDecoderSeekableStreamFlag;   entry->flags^=CoderAdjoinFlag;   (void) RegisterMagickInfo(entry);   return(MagickImageCoderSignature);

Patch:
patch: @@ -238,6 +238,8 @@ static Image *ReadXWDImage(const ImageInfo *image_info,ExceptionInfo *exception)
     ThrowReaderException(CorruptImageError,"FileFormatVersionMismatch");
   if (header.header_size < sz_XWDheader)
     ThrowReaderException(CorruptImageError,"ImproperImageHeader");
+  if ((MagickSizeType) header.xoffset >= GetBlobSize(image))
+    ThrowReaderException(CorruptImageError,"ImproperImageHeader");
   switch (header.visual_class)
   {
     case StaticGray:
@@ -251,7 +253,7 @@ static Image *ReadXWDImage(const ImageInfo *image_info,ExceptionInfo *exception)
     case PseudoColor:
     {
       if ((header.bits_per_pixel < 1) || (header.bits_per_pixel > 15) ||
-          (header.ncolors == 0))
+          (header.colormap_entries == 0))
         ThrowReaderException(CorruptImageError,"ImproperImageHeader");
       break;
     }
@@ -318,8 +320,6 @@ static Image *ReadXWDImage(const ImageInfo *image_info,ExceptionInfo *exception)
     default:
       ThrowReaderException(CorruptImageError,"ImproperImageHeader");
   }
-  if (header.ncolors > 65535)
-    ThrowReaderException(CorruptImageError,"ImproperImageHeader");
   if (((header.bitmap_pad % 8) != 0) || (header.bitmap_pad > 32))
     ThrowReaderException(CorruptImageError,"ImproperImageHeader");
   length=(size_t) (header.header_size-sz_XWDheader);
@@ -387,8 +387,10 @@ static Image *ReadXWDImage(const ImageInfo *image_info,ExceptionInfo *exception)
       XWDColor
         color;
 
-      colors=(XColor *) AcquireQuantumMemory((size_t) header.ncolors,
-        sizeof(*colors));
+      length=(size_t) header.ncolors;
+      if (length > ((~0UL)/sizeof(*colors)))
+        ThrowReaderException(CorruptImageError,"ImproperImageHeader");
+      colors=(XColor *) AcquireQuantumMemory(length,sizeof(*colors));
       if (colors == (XColor *) NULL)
         {
           ximage=(XImage *) RelinquishMagickMemory(ximage);
@@ -689,6 +691,7 @@ ModuleExport size_t RegisterXWDImage(void)
   entry->encoder=(EncodeImageHandler *) WriteXWDImage;
 #endif
   entry->magick=(IsImageFormatHandler *) IsXWD;
+  entry->flags|=CoderDecoderSeekableStreamFlag;
   entry->flags^=CoderAdjoinFlag;
   (void) RegisterMagickInfo(entry);
   return(MagickImageCoderSignature);
path: coders/xwd.c