CVE-2016-7514: Out-of-bounds Read (CWE-125)
value: The ReadPSDChannelPixels function in coders/psd.c in ImageMagick allows remote attackers to cause a denial of service (out-of-bounds read) via a crafted PSD file.
CWE description: The product reads data past the end, or before the beginning, of the intended buffer.
CVSS v3 base score: 6.5
Published: 2017-04-20T18:59Z
Repository: https://github.com/ImageMagick/ImageMagick
Language: C
Files changed: coders/psd.c
Commit date: 2016-01-16 00:08:11 +0100
Commit message: Rewrite reading pixel values.

Diff: diff --git a/coders/psd.c b/coders/psd.c
index 976d9076fb..6b393c2a84 100644
--- a/coders/psd.c
+++ b/coders/psd.c
@@ -762,10 +762,76 @@ static inline void ReversePSDString(Image *image,char *p,size_t length)
     *q = *p ^ *q,
     *p = *p ^ *q;
   }
 }
 
+static inline void SetPSDPixel(Image *image,const size_t channels,
+  const ssize_t type,const size_t packet_size,const Quantum pixel,Quantum *q,
+  ExceptionInfo *exception)
+{
+  if (image->storage_class == PseudoClass)
+    {
+      if (packet_size == 1)
+        SetPixelIndex(image,ScaleQuantumToChar(pixel),q);
+      else
+        SetPixelIndex(image,ScaleQuantumToShort(pixel),q);
+      SetPixelViaPixelInfo(image,image->colormap+(ssize_t)
+        ConstrainColormapIndex(image,GetPixelIndex(image,q),exception),q);
+      return;
+    }
+  switch (type)
+  {
+    case -1:
+    {
+      SetPixelAlpha(image, pixel,q);
+      break;
+    }
+    case -2:
+    case 0:
+    {
+      SetPixelRed(image,pixel,q);
+      if (channels == 1 || type == -2)
+        SetPixelGray(image,pixel,q);
+      break;
+    }
+    case 1:
+    {
+      if (image->storage_class == PseudoClass)
+        SetPixelAlpha(image,pixel,q);
+      else
+        SetPixelGreen(image,pixel,q);
+      break;
+    }
+    case 2:
+    {
+      if (image->storage_class == PseudoClass)
+        SetPixelAlpha(image,pixel,q);
+      else
+        SetPixelBlue(image,pixel,q);
+      break;
+    }
+    case 3:
+    {
+      if (image->colorspace == CMYKColorspace)
+        SetPixelBlack(image,pixel,q);
+      else
+        if (image->alpha_trait != UndefinedPixelTrait)
+          SetPixelAlpha(image,pixel,q);
+      break;
+    }
+    case 4:
+    {
+      if ((IssRGBCompatibleColorspace(image->colorspace) != MagickFalse) &&
+          (channels > 3))
+        break;
+      if (image->alpha_trait != UndefinedPixelTrait)
+        SetPixelAlpha(image,pixel,q);
+      break;
+    }
+  }
+}
+
 static MagickBooleanType ReadPSDChannelPixels(Image *image,
   const size_t channels,const size_t row,const ssize_t type,
   const unsigned char *pixels,ExceptionInfo *exception)
 {
   Quantum
@@ -798,94 +864,35 @@ static MagickBooleanType ReadPSDChannelPixels(Image *image,
     else
       {
         p=PushShortPixel(MSBEndian,p,&nibble);
         pixel=ScaleShortToQuantum(nibble);
       }
-    switch (type)
-    {
-      case -1:
+    if (image->depth > 1)
       {
-        SetPixelAlpha(image,pixel,q);
-        break;
+        SetPSDPixel(image,channels,type,packet_size,pixel,q,exception);
+        q+=GetPixelChannels(image);
       }
-      case -2:
-      case 0:
-      {
-        SetPixelRed(image,pixel,q);
-        if (channels == 1 || type == -2)
-          SetPixelGray(image,pixel,q);
-        if (image->storage_class == PseudoClass)
-          {
-            if (packet_size == 1)
-              SetPixelIndex(image,ScaleQuantumToChar(pixel),q);
-            else
-              SetPixelIndex(image,ScaleQuantumToShort(pixel),q);
-            SetPixelViaPixelInfo(image,image->colormap+(ssize_t)
-              ConstrainColormapIndex(image,GetPixelIndex(image,q),exception),q);
-            if (image->depth == 1)
-              {
-                ssize_t
-                  bit,
-                  number_bits;
-  
-                number_bits=image->columns-x;
-                if (number_bits > 8)
-                  number_bits=8;
-                for (bit=0; bit < number_bits; bit++)
-                {
-                  SetPixelIndex(image,(((unsigned char) pixel) &
-                    (0x01 << (7-bit))) != 0 ? 0 : 255,q);
-                  SetPixelViaPixelInfo(image,image->colormap+(ssize_t)
-                    ConstrainColormapIndex(image,GetPixelIndex(image,q),
-                      exception),q);
-                  q+=GetPixelChannels(image);
-                  x++;
-                }
-                x--;
-                continue;
-              }
-          }
-        break;
-      }
-      case 1:
-      {
-        if (image->storage_class == PseudoClass)
-          SetPixelAlpha(image,pixel,q);
-        else
-          SetPixelGreen(image,pixel,q);
-        break;
-      }
-      case 2:
-      {
-        if (image->storage_class == PseudoClass)
-          SetPixelAlpha(image,pixel,q);
-        else
-          SetPixelBlue(image,pixel,q);
-        break;
-      }
-      case 3:
-      {
-        if (image->colorspace == CMYKColorspace)
-          SetPixelBlack(image,pixel,q);
-        else
-          if (image->alpha_trait != UndefinedPixelTrait)
-            SetPixelAlpha(image,pixel,q);
-        break;
-      }
-      case 4:
+    else
       {
-        if ((IssRGBCompatibleColorspace(image->colorspace) != MagickFalse) &&
-            (channels > 3))
-          break;
-        if (image->alpha_trait != UndefinedPixelTrait)
-          SetPixelAlpha(image,pixel,q);
-        break;
+        ssize_t
+          bit,
+          number_bits;
+      
+        number_bits=image->columns-x;
+        if (number_bits > 8)
+          number_bits=8;
+        for (bit = 0; bit < number_bits; bit++)
+        {
+          SetPSDPixel(image,channels,type,packet_size,(((unsigned char) pixel)
+            & (0x01 << (7-bit))) != 0 ? 0 : 255,q,exception);
+          q+=GetPixelChannels(image);
+          x++;
+        }
+        if (x != image->columns)
+          x--;
+        continue;
       }
-      default:
-        break;
-    }
-    q+=GetPixelChannels(image);
   }
   return(SyncAuthenticPixels(image,exception));
 }
 
 static MagickBooleanType ReadPSDChannelRaw(Image *image,const size_t channels,

Vulnerable code:     switch (type)
    {
      case -1:
        SetPixelAlpha(image,pixel,q);
        break;
      case -2:
      case 0:
      {
        SetPixelRed(image,pixel,q);
        if (channels == 1 || type == -2)
          SetPixelGray(image,pixel,q);
        if (image->storage_class == PseudoClass)
          {
            if (packet_size == 1)
              SetPixelIndex(image,ScaleQuantumToChar(pixel),q);
            else
              SetPixelIndex(image,ScaleQuantumToShort(pixel),q);
            SetPixelViaPixelInfo(image,image->colormap+(ssize_t)
              ConstrainColormapIndex(image,GetPixelIndex(image,q),exception),q);
            if (image->depth == 1)
              {
                ssize_t
                  bit,
                  number_bits;
  
                number_bits=image->columns-x;
                if (number_bits > 8)
                  number_bits=8;
                for (bit=0; bit < number_bits; bit++)
                {
                  SetPixelIndex(image,(((unsigned char) pixel) &
                    (0x01 << (7-bit))) != 0 ? 0 : 255,q);
                  SetPixelViaPixelInfo(image,image->colormap+(ssize_t)
                    ConstrainColormapIndex(image,GetPixelIndex(image,q),
                      exception),q);
                  q+=GetPixelChannels(image);
                  x++;
                }
                x--;
                continue;
              }
          }
        break;
      }
      case 1:
      {
        if (image->storage_class == PseudoClass)
          SetPixelAlpha(image,pixel,q);
        else
          SetPixelGreen(image,pixel,q);
        break;
      }
      case 2:
      {
        if (image->storage_class == PseudoClass)
          SetPixelAlpha(image,pixel,q);
        else
          SetPixelBlue(image,pixel,q);
        break;
      }
      case 3:
      {
        if (image->colorspace == CMYKColorspace)
          SetPixelBlack(image,pixel,q);
        else
          if (image->alpha_trait != UndefinedPixelTrait)
            SetPixelAlpha(image,pixel,q);
        break;
      }
      case 4:
        if ((IssRGBCompatibleColorspace(image->colorspace) != MagickFalse) &&
            (channels > 3))
          break;
        if (image->alpha_trait != UndefinedPixelTrait)
          SetPixelAlpha(image,pixel,q);
        break;
      default:
        break;
    }
    q+=GetPixelChannels(image);
Fixed code: static inline void SetPSDPixel(Image *image,const size_t channels,
  const ssize_t type,const size_t packet_size,const Quantum pixel,Quantum *q,
  ExceptionInfo *exception)
{
  if (image->storage_class == PseudoClass)
    {
      if (packet_size == 1)
        SetPixelIndex(image,ScaleQuantumToChar(pixel),q);
      else
        SetPixelIndex(image,ScaleQuantumToShort(pixel),q);
      SetPixelViaPixelInfo(image,image->colormap+(ssize_t)
        ConstrainColormapIndex(image,GetPixelIndex(image,q),exception),q);
      return;
    }
  switch (type)
  {
    case -1:
    {
      SetPixelAlpha(image, pixel,q);
      break;
    }
    case -2:
    case 0:
    {
      SetPixelRed(image,pixel,q);
      if (channels == 1 || type == -2)
        SetPixelGray(image,pixel,q);
      break;
    }
    case 1:
    {
      if (image->storage_class == PseudoClass)
        SetPixelAlpha(image,pixel,q);
      else
        SetPixelGreen(image,pixel,q);
      break;
    }
    case 2:
    {
      if (image->storage_class == PseudoClass)
        SetPixelAlpha(image,pixel,q);
      else
        SetPixelBlue(image,pixel,q);
      break;
    }
    case 3:
    {
      if (image->colorspace == CMYKColorspace)
        SetPixelBlack(image,pixel,q);
      else
        if (image->alpha_trait != UndefinedPixelTrait)
          SetPixelAlpha(image,pixel,q);
      break;
    }
    case 4:
    {
      if ((IssRGBCompatibleColorspace(image->colorspace) != MagickFalse) &&
          (channels > 3))
        break;
      if (image->alpha_trait != UndefinedPixelTrait)
        SetPixelAlpha(image,pixel,q);
      break;
    }
  }
}

    if (image->depth > 1)
        SetPSDPixel(image,channels,type,packet_size,pixel,q,exception);
        q+=GetPixelChannels(image);
    else
        ssize_t
          bit,
          number_bits;
      
        number_bits=image->columns-x;
        if (number_bits > 8)
          number_bits=8;
        for (bit = 0; bit < number_bits; bit++)
        {
          SetPSDPixel(image,channels,type,packet_size,(((unsigned char) pixel)
            & (0x01 << (7-bit))) != 0 ? 0 : 255,q,exception);
          q+=GetPixelChannels(image);
          x++;
        }
        if (x != image->columns)
          x--;
        continue;