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

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.

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: Dirk Lemstra
author_date: 2017-08-31 20:49:19+02:00
msg: Slightly different fix for #714
repository: repo_url: https://github.com/ImageMagick/ImageMagick
repo_name: ImageMagick/ImageMagick
description: 🧙‍♂️ ImageMagick 7
repo_language: C
owner: ImageMagick
file_changes: filename: psd.c
change_type: ModificationType.MODIFY
diff: @@ -1323,10 +1323,10 @@ static MagickBooleanType ReadPSDChannel(Image *image,
       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)
@@ -1701,24 +1701,12 @@ static MagickBooleanType ReadPSDLayersInternal(Image *image,
                   (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.

programming_language: Objective-C