CVE-2019-13308: Out-of-bounds Write (CWE-787)
value: ImageMagick 7.0.8-50 Q16 has a heap-based buffer overflow in MagickCore/fourier.c in ComplexImage.
CWE description: The product writes data past the end, or before the beginning, of the intended buffer.
CVSS v3 base score: 8.8
Published: 2019-07-05T01:15Z
Repository: https://github.com/ImageMagick/ImageMagick
Language: C
Files changed: MagickCore/fourier.c, coders/gif.c
Commit date: 2019-06-17 08:48:14 -0400
Commit message: https://github.com/ImageMagick/ImageMagick/issues/1595

Diff: diff --git a/MagickCore/fourier.c b/MagickCore/fourier.c
index 9f6f19d3e18..24b3824201f 100644
--- a/MagickCore/fourier.c
+++ b/MagickCore/fourier.c
@@ -224,13 +224,13 @@ MagickExport Image *ComplexImages(const Image *images,const ComplexOperator op,
   Ci_view=AcquireAuthenticCacheView(Ci_image,exception);
   status=MagickTrue;
   progress=0;
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
   #pragma omp parallel for schedule(static) shared(progress,status) \
-    magick_number_threads(images,complex_images,images->rows,1L)
+    magick_number_threads(Cr_image,complex_images,Cr_image->rows,1L)
 #endif
-  for (y=0; y < (ssize_t) images->rows; y++)
+  for (y=0; y < (ssize_t) Cr_image->rows; y++)
   {
     register const Quantum
       *magick_restrict Ai,
       *magick_restrict Ar,
       *magick_restrict Bi,
@@ -243,33 +243,29 @@ MagickExport Image *ComplexImages(const Image *images,const ComplexOperator op,
     register ssize_t
       x;
 
     if (status == MagickFalse)
       continue;
-    Ar=GetCacheViewVirtualPixels(Ar_view,0,y,
-      MagickMax(Ar_image->columns,Cr_image->columns),1,exception);
-    Ai=GetCacheViewVirtualPixels(Ai_view,0,y,
-      MagickMax(Ai_image->columns,Ci_image->columns),1,exception);
-    Br=GetCacheViewVirtualPixels(Br_view,0,y,
-      MagickMax(Br_image->columns,Cr_image->columns),1,exception);
-    Bi=GetCacheViewVirtualPixels(Bi_view,0,y,
-      MagickMax(Bi_image->columns,Ci_image->columns),1,exception);
+    Ar=GetCacheViewVirtualPixels(Ar_view,0,y,Cr_image->columns,1,exception);
+    Ai=GetCacheViewVirtualPixels(Ai_view,0,y,Cr_image->columns,1,exception);
+    Br=GetCacheViewVirtualPixels(Br_view,0,y,Cr_image->columns,1,exception);
+    Bi=GetCacheViewVirtualPixels(Bi_view,0,y,Cr_image->columns,1,exception);
     Cr=QueueCacheViewAuthenticPixels(Cr_view,0,y,Cr_image->columns,1,exception);
     Ci=QueueCacheViewAuthenticPixels(Ci_view,0,y,Ci_image->columns,1,exception);
     if ((Ar == (const Quantum *) NULL) || (Ai == (const Quantum *) NULL) || 
         (Br == (const Quantum *) NULL) || (Bi == (const Quantum *) NULL) ||
         (Cr == (Quantum *) NULL) || (Ci == (Quantum *) NULL))
       {
         status=MagickFalse;
         continue;
       }
-    for (x=0; x < (ssize_t) images->columns; x++)
+    for (x=0; x < (ssize_t) Cr_image->columns; x++)
     {
       register ssize_t
         i;
 
-      for (i=0; i < (ssize_t) GetPixelChannels(images); i++)
+      for (i=0; i < (ssize_t) GetPixelChannels(Cr_image); i++)
       {
         switch (op)
         {
           case AddComplexOperator:
           {
@@ -287,25 +283,25 @@ MagickExport Image *ComplexImages(const Image *images,const ComplexOperator op,
           case DivideComplexOperator:
           {
             double
               gamma;
 
-            gamma=PerceptibleReciprocal(Br[i]*Br[i]+Bi[i]*Bi[i]+snr);
-            Cr[i]=gamma*(Ar[i]*Br[i]+Ai[i]*Bi[i]);
-            Ci[i]=gamma*(Ai[i]*Br[i]-Ar[i]*Bi[i]);
+            gamma=PerceptibleReciprocal((double) Br[i]*Br[i]+Bi[i]*Bi[i]+snr);
+            Cr[i]=gamma*((double) Ar[i]*Br[i]+(double) Ai[i]*Bi[i]);
+            Ci[i]=gamma*((double) Ai[i]*Br[i]-(double) Ar[i]*Bi[i]);
             break;
           }
           case MagnitudePhaseComplexOperator:
           {
-            Cr[i]=sqrt(Ar[i]*Ar[i]+Ai[i]*Ai[i]);
-            Ci[i]=atan2(Ai[i],Ar[i])/(2.0*MagickPI)+0.5;
+            Cr[i]=sqrt((double) Ar[i]*Ar[i]+(double) Ai[i]*Ai[i]);
+            Ci[i]=atan2((double) Ai[i],(double) Ar[i])/(2.0*MagickPI)+0.5;
             break;
           }
           case MultiplyComplexOperator:
           {
-            Cr[i]=QuantumScale*(Ar[i]*Br[i]-Ai[i]*Bi[i]);
-            Ci[i]=QuantumScale*(Ai[i]*Br[i]+Ar[i]*Bi[i]);
+            Cr[i]=QuantumScale*((double) Ar[i]*Br[i]-(double) Ai[i]*Bi[i]);
+            Ci[i]=QuantumScale*((double) Ai[i]*Br[i]+(double) Ar[i]*Bi[i]);
             break;
           }
           case RealImaginaryComplexOperator:
           {
             Cr[i]=Ar[i]*cos(2.0*MagickPI*(Ai[i]-0.5));
diff --git a/coders/gif.c b/coders/gif.c
index 028890ec52c..056c4d2fcf5 100644
--- a/coders/gif.c
+++ b/coders/gif.c
@@ -671,17 +671,19 @@ static MagickBooleanType EncodeImage(const ImageInfo *image_info,Image *image,
     for (x=(ssize_t) (y == 0 ? 1 : 0); x < (ssize_t) image->columns; x++)
     {
       /*
         Probe hash table.
       */
+      next_pixel=MagickFalse;
+      displacement=1;
       index=(Quantum) ((size_t) GetPixelIndex(image,p) & 0xff);
       p+=GetPixelChannels(image);
       k=(ssize_t) (((size_t) index << (MaxGIFBits-8))+waiting_code);
       if (k >= MaxHashTable)
         k-=MaxHashTable;
-      next_pixel=MagickFalse;
-      displacement=1;
+      if (k < 0)
+        continue;
       if (hash_code[k] > 0)
         {
           if ((hash_prefix[k] == waiting_code) &&
               (hash_suffix[k] == (unsigned char) index))
             {

Vulnerable code:     magick_number_threads(images,complex_images,images->rows,1L)
  for (y=0; y < (ssize_t) images->rows; y++)
    Ar=GetCacheViewVirtualPixels(Ar_view,0,y,
      MagickMax(Ar_image->columns,Cr_image->columns),1,exception);
    Ai=GetCacheViewVirtualPixels(Ai_view,0,y,
      MagickMax(Ai_image->columns,Ci_image->columns),1,exception);
    Br=GetCacheViewVirtualPixels(Br_view,0,y,
      MagickMax(Br_image->columns,Cr_image->columns),1,exception);
    Bi=GetCacheViewVirtualPixels(Bi_view,0,y,
      MagickMax(Bi_image->columns,Ci_image->columns),1,exception);
    for (x=0; x < (ssize_t) images->columns; x++)
      for (i=0; i < (ssize_t) GetPixelChannels(images); i++)
            gamma=PerceptibleReciprocal(Br[i]*Br[i]+Bi[i]*Bi[i]+snr);
            Cr[i]=gamma*(Ar[i]*Br[i]+Ai[i]*Bi[i]);
            Ci[i]=gamma*(Ai[i]*Br[i]-Ar[i]*Bi[i]);
            Cr[i]=sqrt(Ar[i]*Ar[i]+Ai[i]*Ai[i]);
            Ci[i]=atan2(Ai[i],Ar[i])/(2.0*MagickPI)+0.5;
            Cr[i]=QuantumScale*(Ar[i]*Br[i]-Ai[i]*Bi[i]);
            Ci[i]=QuantumScale*(Ai[i]*Br[i]+Ar[i]*Bi[i]);
      next_pixel=MagickFalse;
      displacement=1;
Fixed code:     magick_number_threads(Cr_image,complex_images,Cr_image->rows,1L)
  for (y=0; y < (ssize_t) Cr_image->rows; y++)
    Ar=GetCacheViewVirtualPixels(Ar_view,0,y,Cr_image->columns,1,exception);
    Ai=GetCacheViewVirtualPixels(Ai_view,0,y,Cr_image->columns,1,exception);
    Br=GetCacheViewVirtualPixels(Br_view,0,y,Cr_image->columns,1,exception);
    Bi=GetCacheViewVirtualPixels(Bi_view,0,y,Cr_image->columns,1,exception);
    for (x=0; x < (ssize_t) Cr_image->columns; x++)
      for (i=0; i < (ssize_t) GetPixelChannels(Cr_image); i++)
            gamma=PerceptibleReciprocal((double) Br[i]*Br[i]+Bi[i]*Bi[i]+snr);
            Cr[i]=gamma*((double) Ar[i]*Br[i]+(double) Ai[i]*Bi[i]);
            Ci[i]=gamma*((double) Ai[i]*Br[i]-(double) Ar[i]*Bi[i]);
            Cr[i]=sqrt((double) Ar[i]*Ar[i]+(double) Ai[i]*Ai[i]);
            Ci[i]=atan2((double) Ai[i],(double) Ar[i])/(2.0*MagickPI)+0.5;
            Cr[i]=QuantumScale*((double) Ar[i]*Br[i]-(double) Ai[i]*Bi[i]);
            Ci[i]=QuantumScale*((double) Ai[i]*Br[i]+(double) Ar[i]*Bi[i]);
      next_pixel=MagickFalse;
      displacement=1;
      if (k < 0)
        continue;