CVE-2017-14172: Excessive Iteration (CWE-834)
value: In coders/ps.c in ImageMagick 7.0.7-0 Q16, a DoS in ReadPSImage() due to lack of an EOF (End of File) check might cause huge CPU consumption. When a crafted PSD file, which claims a large "extent" 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/ps.c
Commit date: 2017-08-31 11:06:10 -0400
Commit message: https://github.com/ImageMagick/ImageMagick/issues/715

Diff: diff --git a/coders/ps.c b/coders/ps.c
index 57032275724..abe3a23eaae 100644
--- a/coders/ps.c
+++ b/coders/ps.c
@@ -655,10 +655,12 @@ static Image *ReadPSImage(const ImageInfo *image_info,ExceptionInfo *exception)
         */
         count=(ssize_t) sscanf(command,PhotoshopProfile " %lu",&extent);
         if (count != 1)
           continue;
         length=extent;
+        if (length > GetBlobSize(image))
+          ThrowReaderException(CorruptImageError,"InsufficientImageDataInFile");
         profile=BlobToStringInfo((const void *) NULL,length);
         if (profile != (StringInfo *) NULL)
           {
             q=GetStringInfoDatum(profile);
             for (i=0; i < (ssize_t) length; i++)
@@ -722,12 +724,12 @@ static Image *ReadPSImage(const ImageInfo *image_info,ExceptionInfo *exception)
           *q;
 
         /*
           Note spot names.
         */
-        (void) FormatLocaleString(property,MagickPathExtent,"ps:SpotColor-%.20g",
-          (double) (spotcolor++));
+        (void) FormatLocaleString(property,MagickPathExtent,
+          "ps:SpotColor-%.20g",(double) (spotcolor++));
         for (q=command; *q != '\0'; q++)
           if (isspace((int) (unsigned char) *q) != 0)
             break;
         value=AcquireString(q);
         (void) SubstituteString(&value,"(","");
@@ -893,11 +895,12 @@ static Image *ReadPSImage(const ImageInfo *image_info,ExceptionInfo *exception)
       option=GetImageOption(image_info,"eps:use-cropbox");
       if ((option == (const char *) NULL) ||
           (IsStringTrue(option) != MagickFalse))
         (void) ConcatenateMagickString(options,"-dEPSCrop ",MagickPathExtent);
       if (fitPage != MagickFalse)
-        (void) ConcatenateMagickString(options,"-dEPSFitPage ",MagickPathExtent);
+        (void) ConcatenateMagickString(options,"-dEPSFitPage ",
+          MagickPathExtent);
     }
   (void) CopyMagickString(filename,read_info->filename,MagickPathExtent);
   (void) AcquireUniqueFilename(filename);
   (void) RelinquishUniqueFileResource(filename);
   (void) ConcatenateMagickString(filename,"%d",MagickPathExtent);
@@ -1041,44 +1044,49 @@ ModuleExport size_t RegisterPSImage(void)
   entry=AcquireMagickInfo("PS","EPI",
     "Encapsulated PostScript Interchange format");
   entry->decoder=(DecodeImageHandler *) ReadPSImage;
   entry->encoder=(EncodeImageHandler *) WritePSImage;
   entry->magick=(IsImageFormatHandler *) IsPS;
+  entry->flags|=CoderDecoderSeekableStreamFlag;
   entry->flags^=CoderAdjoinFlag;
   entry->flags^=CoderBlobSupportFlag;
   entry->mime_type=ConstantString("application/postscript");
   (void) RegisterMagickInfo(entry);
   entry=AcquireMagickInfo("PS","EPS","Encapsulated PostScript");
   entry->decoder=(DecodeImageHandler *) ReadPSImage;
   entry->encoder=(EncodeImageHandler *) WritePSImage;
   entry->magick=(IsImageFormatHandler *) IsPS;
+  entry->flags|=CoderDecoderSeekableStreamFlag;
   entry->flags^=CoderAdjoinFlag;
   entry->flags^=CoderBlobSupportFlag;
   entry->mime_type=ConstantString("application/postscript");
   (void) RegisterMagickInfo(entry);
   entry=AcquireMagickInfo("PS","EPSF","Encapsulated PostScript");
   entry->decoder=(DecodeImageHandler *) ReadPSImage;
   entry->encoder=(EncodeImageHandler *) WritePSImage;
   entry->magick=(IsImageFormatHandler *) IsPS;
+  entry->flags|=CoderDecoderSeekableStreamFlag;
   entry->flags^=CoderAdjoinFlag;
   entry->flags^=CoderBlobSupportFlag;
   entry->mime_type=ConstantString("application/postscript");
   (void) RegisterMagickInfo(entry);
   entry=AcquireMagickInfo("PS","EPSI",
     "Encapsulated PostScript Interchange format");
   entry->decoder=(DecodeImageHandler *) ReadPSImage;
   entry->encoder=(EncodeImageHandler *) WritePSImage;
   entry->magick=(IsImageFormatHandler *) IsPS;
+  entry->flags|=CoderDecoderSeekableStreamFlag;
   entry->flags^=CoderAdjoinFlag;
   entry->flags^=CoderBlobSupportFlag;
   entry->mime_type=ConstantString("application/postscript");
   (void) RegisterMagickInfo(entry);
   entry=AcquireMagickInfo("PS","PS","PostScript");
   entry->decoder=(DecodeImageHandler *) ReadPSImage;
   entry->encoder=(EncodeImageHandler *) WritePSImage;
   entry->magick=(IsImageFormatHandler *) IsPS;
   entry->mime_type=ConstantString("application/postscript");
+  entry->flags|=CoderDecoderSeekableStreamFlag;
   entry->flags^=CoderBlobSupportFlag;
   (void) RegisterMagickInfo(entry);
   return(MagickImageCoderSignature);
 }
 

Vulnerable code:         (void) FormatLocaleString(property,MagickPathExtent,"ps:SpotColor-%.20g",
          (double) (spotcolor++));
        (void) ConcatenateMagickString(options,"-dEPSFitPage ",MagickPathExtent);
Fixed code:         if (length > GetBlobSize(image))
          ThrowReaderException(CorruptImageError,"InsufficientImageDataInFile");
        (void) FormatLocaleString(property,MagickPathExtent,
          "ps:SpotColor-%.20g",(double) (spotcolor++));
        (void) ConcatenateMagickString(options,"-dEPSFitPage ",
          MagickPathExtent);
  entry->flags|=CoderDecoderSeekableStreamFlag;
  entry->flags|=CoderDecoderSeekableStreamFlag;
  entry->flags|=CoderDecoderSeekableStreamFlag;
  entry->flags|=CoderDecoderSeekableStreamFlag;
  entry->flags|=CoderDecoderSeekableStreamFlag;