CVE-2017-14174: Excessive Iteration (CWE-834)
value: In coders/psd.c in ImageMagick 7.0.7-0 Q16, a DoS in ReadPSDLayersInternal() due to lack of an EOF (End of File) check might cause huge CPU consumption. When a crafted PSD file, which claims a large "length" field in the header but does not contain sufficient backing data, is provided, the loop over "length" 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/psd.c
Commit date: 2017-08-31 20:49:19 +0200
Commit message: Slightly different fix for #714

Diff: diff --git a/coders/psd.c b/coders/psd.c
index a29f6ac3ee1..88a63e577ee 100644
--- a/coders/psd.c
+++ b/coders/psd.c
@@ -1321,14 +1321,14 @@ static MagickBooleanType ReadPSDChannel(Image *image,
       */
       option=GetImageOption(image_info,"psd:preserve-opacity-mask");
       if ((layer_info->channel_info[channel].type != -2) ||
           (layer_info->mask.flags > 2) || ((layer_info->mask.flags & 0x02) &&
            (IsStringTrue(option) == MagickFalse)))
-      {
-        SeekBlob(image,layer_info->channel_info[channel].size-2,SEEK_CUR);
-        return(MagickTrue);
-      }
+        {
+          SeekBlob(image,layer_info->channel_info[channel].size-2,SEEK_CUR);
+          return(MagickTrue);
+        }
       mask=CloneImage(image,layer_info->mask.page.width,
         layer_info->mask.page.height,MagickFalse,exception);
       if (mask != (Image *) NULL)
         {
           SetImageType(mask,GrayscaleType,exception);
@@ -1699,28 +1699,16 @@ static MagickBooleanType ReadPSDLayersInternal(Image *image,
                 */
                 if (image->debug != MagickFalse)
                   (void) LogMagickEvent(CoderEvent,GetMagickModule(),
                     "      layer blending ranges: length=%.20g",(double)
                     ((MagickOffsetType) length));
-                /*
-                  We read it, but don't use it...
-                */
-                for (j=0; j < (ssize_t) length; j+=8)
-                {
-                  size_t blend_source=ReadBlobLong(image);
-                  size_t blend_dest=ReadBlobLong(image);
-                  if (EOFBlob(image) != MagickFalse)
-                    {
-                      layer_info=DestroyLayerInfo(layer_info,number_layers);
-                      ThrowBinaryException(CorruptImageError,
-                        "InsufficientImageDataInFile",image->filename);
-                    }
-                  if (image->debug != MagickFalse)
-                    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-                      "        source(%x), dest(%x)",(unsigned int)
-                      blend_source,(unsigned int) blend_dest);
-                }
+                if (DiscardBlobBytes(image,length) == MagickFalse)
+                  {
+                    layer_info=DestroyLayerInfo(layer_info,number_layers);
+                    ThrowBinaryException(CorruptImageError,
+                      "UnexpectedEndOfFile",image->filename);
+                  }
               }
             /*
               Layer name.
             */
             length=(MagickSizeType) (unsigned char) ReadBlobByte(image);

Vulnerable code:       {
        SeekBlob(image,layer_info->channel_info[channel].size-2,SEEK_CUR);
        return(MagickTrue);
      }
                /*
                  We read it, but don't use it...
                */
                for (j=0; j < (ssize_t) length; j+=8)
                {
                  size_t blend_source=ReadBlobLong(image);
                  size_t blend_dest=ReadBlobLong(image);
                  if (EOFBlob(image) != MagickFalse)
                    {
                      layer_info=DestroyLayerInfo(layer_info,number_layers);
                      ThrowBinaryException(CorruptImageError,
                        "InsufficientImageDataInFile",image->filename);
                    }
                  if (image->debug != MagickFalse)
                    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
                      "        source(%x), dest(%x)",(unsigned int)
                      blend_source,(unsigned int) blend_dest);
                }
Fixed code:         {
          SeekBlob(image,layer_info->channel_info[channel].size-2,SEEK_CUR);
          return(MagickTrue);
        }
                if (DiscardBlobBytes(image,length) == MagickFalse)
                  {
                    layer_info=DestroyLayerInfo(layer_info,number_layers);
                    ThrowBinaryException(CorruptImageError,
                      "UnexpectedEndOfFile",image->filename);
                  }