CVE-2017-12664: Missing Release of Resource after Effective Lifetime (CWE-772)
value: ImageMagick 7.0.6-2 has a memory leak vulnerability in WritePALMImage in coders/palm.c.
CWE description: The product does not release a resource after its effective lifetime has ended, i.e., after the resource is no longer needed.
CVSS v3 base score: 8.8
Published: 2017-08-07T21:29Z
Repository: https://github.com/ImageMagick/ImageMagick
Language: C
Files changed: MagickCore/quantize.c, coders/palm.c
Commit date: 2017-07-17 13:47:41 -0400
Commit message: https://github.com/ImageMagick/ImageMagick/issues/574

Diff: diff --git a/MagickCore/quantize.c b/MagickCore/quantize.c
index 073ae7f14c7..851a240153e 100644
--- a/MagickCore/quantize.c
+++ b/MagickCore/quantize.c
@@ -3327,12 +3327,15 @@ static MagickBooleanType SetGrayscaleImage(Image *image,
   if (image->storage_class != PseudoClass)
     {
       (void) ResetMagickMemory(colormap_index,(-1),MaxColormapSize*
         sizeof(*colormap_index));
       if (AcquireImageColormap(image,MaxColormapSize,exception) == MagickFalse)
-        ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
-          image->filename);
+        {
+          colormap_index=(ssize_t *) RelinquishMagickMemory(colormap_index);
+          ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
+            image->filename);
+        }
       image->colors=0;
       status=MagickTrue;
       image_view=AcquireAuthenticCacheView(image,exception);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
       #pragma omp parallel for schedule(static,4) shared(status) \
diff --git a/coders/palm.c b/coders/palm.c
index 8b1152b3033..6283f3f945e 100644
--- a/coders/palm.c
+++ b/coders/palm.c
@@ -276,11 +276,11 @@ static Image *ReadPALMImage(const ImageInfo *image_info,
   ssize_t
     count,
     y;
 
   unsigned char
-    *lastrow,
+    *last_row,
     *one_row,
     *ptr;
 
   unsigned short
     color16;
@@ -406,16 +406,16 @@ static Image *ReadPALMImage(const ImageInfo *image_info,
       return(DestroyImageList(image));
     one_row=(unsigned char *) AcquireQuantumMemory(MagickMax(bytes_per_row,
       2*image->columns),sizeof(*one_row));
     if (one_row == (unsigned char *) NULL)
       ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
-    lastrow=(unsigned char *) NULL;
+    last_row=(unsigned char *) NULL;
     if (compressionType == PALM_COMPRESSION_SCANLINE)
       {
-        lastrow=(unsigned char *) AcquireQuantumMemory(MagickMax(bytes_per_row,
-          2*image->columns),sizeof(*lastrow));
-        if (lastrow == (unsigned char *) NULL)
+        last_row=(unsigned char *) AcquireQuantumMemory(MagickMax(bytes_per_row,
+          2*image->columns),sizeof(*last_row));
+        if (last_row == (unsigned char *) NULL)
           ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
       }
     mask=(size_t) (1U << bits_per_pixel)-1;
     for (y=0; y < (ssize_t) image->rows; y++)
     {
@@ -462,14 +462,14 @@ static Image *ReadPALMImage(const ImageInfo *image_info,
                 for (bit=0; bit < byte; bit++)
                 {
                   if ((y == 0) || (count & (one << (7 - bit))))
                     one_row[i+bit]=(unsigned char) ReadBlobByte(image);
                   else
-                    one_row[i+bit]=lastrow[i+bit];
+                    one_row[i+bit]=last_row[i+bit];
                 }
               }
-              (void) CopyMagickMemory(lastrow, one_row, bytes_per_row);
+              (void) CopyMagickMemory(last_row, one_row, bytes_per_row);
             }
         }
       ptr=one_row;
       q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
       if (q == (Quantum *) NULL)
@@ -478,11 +478,11 @@ static Image *ReadPALMImage(const ImageInfo *image_info,
         {
           if (image->columns > (2*bytes_per_row))
             {
               one_row=(unsigned char *) RelinquishMagickMemory(one_row);
               if (compressionType == PALM_COMPRESSION_SCANLINE)
-                lastrow=(unsigned char *) RelinquishMagickMemory(lastrow);
+                last_row=(unsigned char *) RelinquishMagickMemory(last_row);
               ThrowReaderException(CorruptImageError,"CorruptImage");
             }
           for (x=0; x < (ssize_t) image->columns; x++)
           {
             color16=(*ptr++ << 8);
@@ -504,11 +504,11 @@ static Image *ReadPALMImage(const ImageInfo *image_info,
           {
             if ((size_t) (ptr-one_row) >= bytes_per_row)
               {
                 one_row=(unsigned char *) RelinquishMagickMemory(one_row);
                 if (compressionType == PALM_COMPRESSION_SCANLINE)
-                  lastrow=(unsigned char *) RelinquishMagickMemory(lastrow);
+                  last_row=(unsigned char *) RelinquishMagickMemory(last_row);
                 ThrowReaderException(CorruptImageError,"CorruptImage");
               }
             index=(Quantum) (mask-(((*ptr) & (mask << bit)) >> bit));
             SetPixelIndex(image,index,q);
             SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
@@ -541,11 +541,11 @@ static Image *ReadPALMImage(const ImageInfo *image_info,
         (void) TransparentPaintImage(image,&transpix,(Quantum) TransparentAlpha,
           MagickFalse,exception);
       }
     one_row=(unsigned char *) RelinquishMagickMemory(one_row);
     if (compressionType == PALM_COMPRESSION_SCANLINE)
-      lastrow=(unsigned char *) RelinquishMagickMemory(lastrow);
+      last_row=(unsigned char *) RelinquishMagickMemory(last_row);
     if (EOFBlob(image) != MagickFalse)
       {
         ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
           image->filename);
         break;
@@ -716,11 +716,11 @@ static MagickBooleanType WritePALMImage(const ImageInfo *image_info,
 
   unsigned char
     bit,
     byte,
     color,
-    *lastrow,
+    *last_row,
     *one_row,
     *ptr,
     version;
 
   unsigned int
@@ -859,19 +859,28 @@ static MagickBooleanType WritePALMImage(const ImageInfo *image_info,
           affinity_image=DestroyImage(affinity_image);
         }
       }
     if (flags & PALM_IS_COMPRESSED_FLAG)
       (void) WriteBlobMSBShort(image,0);  /* fill in size later */
-    lastrow=(unsigned char *) NULL;
+    last_row=(unsigned char *) NULL;
     if (image_info->compression == FaxCompression)
-      lastrow=(unsigned char *) AcquireQuantumMemory(bytes_per_row,
-        sizeof(*lastrow));
-      /* TODO check whether memory really was acquired? */
+      {
+        last_row=(unsigned char *) AcquireQuantumMemory(bytes_per_row,
+          sizeof(*last_row));
+        if (last_row == (unsigned char *) NULL)
+          {
+            quantize_info=DestroyQuantizeInfo(quantize_info);
+            ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
+          }
+      }
     one_row=(unsigned char *) AcquireQuantumMemory(bytes_per_row,
       sizeof(*one_row));
     if (one_row == (unsigned char *) NULL)
-      ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
+      {
+        quantize_info=DestroyQuantizeInfo(quantize_info);
+        ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
+      }
     for (y=0; y < (ssize_t) image->rows; y++)
     {
       ptr=one_row;
       (void) ResetMagickMemory(ptr,0,bytes_per_row);
       p=GetVirtualPixels(image,0,y,image->columns,1,exception);
@@ -947,20 +956,20 @@ static MagickBooleanType WritePALMImage(const ImageInfo *image_info,
             for (x = 0;  x < (ssize_t) bytes_per_row;  x += 8)
             {
               tptr = tmpbuf;
               for (bit=0, byte=0; bit < (unsigned char) MagickMin(8,(ssize_t) bytes_per_row-x); bit++)
               {
-                if ((y == 0) || (lastrow[x + bit] != one_row[x + bit]))
+                if ((y == 0) || (last_row[x + bit] != one_row[x + bit]))
                   {
                     byte |= (1 << (7 - bit));
                     *tptr++ = (char) one_row[x + bit];
                   }
               }
               (void) WriteBlobByte(image, byte);
               (void) WriteBlob(image,tptr-tmpbuf,(unsigned char *) tmpbuf);
             }
-            (void) CopyMagickMemory(lastrow,one_row,bytes_per_row);
+            (void) CopyMagickMemory(last_row,one_row,bytes_per_row);
           }
         else
           (void) WriteBlob(image,bytes_per_row,one_row);
       }
     if (flags & PALM_HAS_TRANSPARENCY_FLAG)
@@ -972,24 +981,27 @@ static MagickBooleanType WritePALMImage(const ImageInfo *image_info,
       }
     if (bits_per_pixel == 16)
       {
         offset=SeekBlob(image,currentOffset+20,SEEK_SET);
         (void) WriteBlobByte(image,0);  /* reserved by Palm */
-        (void) WriteBlobByte(image,(unsigned char) ((31*transpix.red)/QuantumRange));
-        (void) WriteBlobByte(image,(unsigned char) ((63*transpix.green)/QuantumRange));
-        (void) WriteBlobByte(image,(unsigned char) ((31*transpix.blue)/QuantumRange));
+        (void) WriteBlobByte(image,(unsigned char) ((31*transpix.red)/
+          QuantumRange));
+        (void) WriteBlobByte(image,(unsigned char) ((63*transpix.green)/
+          QuantumRange));
+        (void) WriteBlobByte(image,(unsigned char) ((31*transpix.blue)/
+          QuantumRange));
       }
     if (flags & PALM_IS_COMPRESSED_FLAG)  /* fill in size now */
       {
         offset=SeekBlob(image,currentOffset+offset,SEEK_SET);
         (void) WriteBlobMSBShort(image,(unsigned short) (GetBlobSize(image)-
           currentOffset-offset));
       }
     if (one_row != (unsigned char *) NULL) 
       one_row=(unsigned char *) RelinquishMagickMemory(one_row);
-    if (lastrow != (unsigned char *) NULL) 
-      lastrow=(unsigned char *) RelinquishMagickMemory(lastrow);
+    if (last_row != (unsigned char *) NULL) 
+      last_row=(unsigned char *) RelinquishMagickMemory(last_row);
     if (GetNextImageInList(image) == (Image *) NULL)
       break;
     /* padding to 4 byte word */
     for (cc=(GetBlobSize(image)) % 4; cc > 0; cc--)
       (void) WriteBlobByte(image,0);

Vulnerable code:         ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
          image->filename);
    *lastrow,
    lastrow=(unsigned char *) NULL;
        lastrow=(unsigned char *) AcquireQuantumMemory(MagickMax(bytes_per_row,
          2*image->columns),sizeof(*lastrow));
        if (lastrow == (unsigned char *) NULL)
                    one_row[i+bit]=lastrow[i+bit];
              (void) CopyMagickMemory(lastrow, one_row, bytes_per_row);
                lastrow=(unsigned char *) RelinquishMagickMemory(lastrow);
                  lastrow=(unsigned char *) RelinquishMagickMemory(lastrow);
      lastrow=(unsigned char *) RelinquishMagickMemory(lastrow);
    *lastrow,
    lastrow=(unsigned char *) NULL;
      lastrow=(unsigned char *) AcquireQuantumMemory(bytes_per_row,
        sizeof(*lastrow));
      /* TODO check whether memory really was acquired? */
      ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
                if ((y == 0) || (lastrow[x + bit] != one_row[x + bit]))
            (void) CopyMagickMemory(lastrow,one_row,bytes_per_row);
        (void) WriteBlobByte(image,(unsigned char) ((31*transpix.red)/QuantumRange));
        (void) WriteBlobByte(image,(unsigned char) ((63*transpix.green)/QuantumRange));
        (void) WriteBlobByte(image,(unsigned char) ((31*transpix.blue)/QuantumRange));
    if (lastrow != (unsigned char *) NULL) 
      lastrow=(unsigned char *) RelinquishMagickMemory(lastrow);
Fixed code:         {
          colormap_index=(ssize_t *) RelinquishMagickMemory(colormap_index);
          ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
            image->filename);
        }
    *last_row,
    last_row=(unsigned char *) NULL;
        last_row=(unsigned char *) AcquireQuantumMemory(MagickMax(bytes_per_row,
          2*image->columns),sizeof(*last_row));
        if (last_row == (unsigned char *) NULL)
                    one_row[i+bit]=last_row[i+bit];
              (void) CopyMagickMemory(last_row, one_row, bytes_per_row);
                last_row=(unsigned char *) RelinquishMagickMemory(last_row);
                  last_row=(unsigned char *) RelinquishMagickMemory(last_row);
      last_row=(unsigned char *) RelinquishMagickMemory(last_row);
    *last_row,
    last_row=(unsigned char *) NULL;
      {
        last_row=(unsigned char *) AcquireQuantumMemory(bytes_per_row,
          sizeof(*last_row));
        if (last_row == (unsigned char *) NULL)
          {
            quantize_info=DestroyQuantizeInfo(quantize_info);
            ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
          }
      }
      {
        quantize_info=DestroyQuantizeInfo(quantize_info);
        ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
      }
                if ((y == 0) || (last_row[x + bit] != one_row[x + bit]))
            (void) CopyMagickMemory(last_row,one_row,bytes_per_row);
        (void) WriteBlobByte(image,(unsigned char) ((31*transpix.red)/
          QuantumRange));
        (void) WriteBlobByte(image,(unsigned char) ((63*transpix.green)/
          QuantumRange));
        (void) WriteBlobByte(image,(unsigned char) ((31*transpix.blue)/
          QuantumRange));
    if (last_row != (unsigned char *) NULL) 
      last_row=(unsigned char *) RelinquishMagickMemory(last_row);