Subject: [PATCH] gnu: graphicsmagick: Fix CVE-2017-14649.

From: Kei Kebreau <[email-masked]>
Date: Sat, 30 Sep 2017 09:13:45 -0400

* gnu/packages/imagemagick.scm (graphicsmagick)[source]: Add patch.
* gnu/packages/patches/graphicsmagick-CVE-2017-14649.patch:
New file.
* gnu/local.mk (dist_patch_DATA): Register it.
---
 gnu/local.mk                                       |   1 +
 gnu/packages/imagemagick.scm                       |   3 +-
 .../patches/graphicsmagick-CVE-2017-14649.patch    | 211 +++++++++++++++++++++
 3 files changed, 214 insertions(+), 1 deletion(-)
 create mode 100644 gnu/packages/patches/graphicsmagick-CVE-2017-14649.patch

diff --git a/gnu/local.mk b/gnu/local.mk
index edd6d8237..8f0e0a3d2 100644
--- a/gnu/local.mk
+++ b/gnu/local.mk
@@ -688,6 +688,7 @@ dist_patch_DATA =						\
   %D%/packages/patches/graphicsmagick-CVE-2017-13776+CVE-2017-13777.patch	\
   %D%/packages/patches/graphicsmagick-CVE-2017-14042.patch	\
   %D%/packages/patches/graphicsmagick-CVE-2017-14165.patch	\
+  %D%/packages/patches/graphicsmagick-CVE-2017-14649.patch	\
   %D%/packages/patches/graphite2-ffloat-store.patch		\
   %D%/packages/patches/grep-gnulib-lock.patch                   \
   %D%/packages/patches/grep-timing-sensitive-test.patch		\
diff --git a/gnu/packages/imagemagick.scm b/gnu/packages/imagemagick.scm
index 7599f8731..b22799eea 100644
--- a/gnu/packages/imagemagick.scm
+++ b/gnu/packages/imagemagick.scm
@@ -185,7 +185,8 @@ script.")
                                "graphicsmagick-CVE-2017-13775.patch"
                                "graphicsmagick-CVE-2017-13776+CVE-2017-13777.patch"
                                "graphicsmagick-CVE-2017-14042.patch"
-                               "graphicsmagick-CVE-2017-14165.patch"))))
+                               "graphicsmagick-CVE-2017-14165.patch"
+                               "graphicsmagick-CVE-2017-14649.patch"))))
     (build-system gnu-build-system)
     (arguments
      `(#:configure-flags
diff --git a/gnu/packages/patches/graphicsmagick-CVE-2017-14649.patch b/gnu/packages/patches/graphicsmagick-CVE-2017-14649.patch
new file mode 100644
index 000000000..d7e6cd7ad
--- /dev/null
+++ b/gnu/packages/patches/graphicsmagick-CVE-2017-14649.patch
@@ -0,0 +1,211 @@
+http://hg.code.sf.net/p/graphicsmagick/code/rev/358608a46f0a
+http://www.openwall.com/lists/oss-security/2017/09/22/2
+
+Some changes were made to make the patch apply.
+
+Notably, the DestroyJNG() function in the upstream diff has been replaced by
+its equivalent, a series of calls to MagickFreeMemory(), DestroyImageInfo(),
+and DestroyImage(). See
+http://hg.code.sf.net/p/graphicsmagick/code/rev/d445af60a8d5.
+
+# HG changeset patch
+# User Glenn Randers-Pehrson <[email-masked]>
+# Date 1504014487 14400
+# Node ID 358608a46f0a9c55e9bb8b37d09bf1ac9bc87f06
+# Parent  38c362f0ae5e7a914c3fe822284c6953f8e6eee2
+Fix Issue 439
+
+diff -ru a/coders/png.c b/coders/png.c
+--- a/coders/png.c	1969-12-31 19:00:00.000000000 -0500
++++ b/coders/png.c	2017-09-30 08:20:16.218944991 -0400
+@@ -1176,15 +1176,15 @@
+   /* allocate space */
+   if (length == 0)
+     {
+-      (void) ThrowException2(&image->exception,CoderWarning,
+-                             "invalid profile length",(char *) NULL);
++      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
++          "invalid profile length");
+       return (MagickFail);
+     }
+   info=MagickAllocateMemory(unsigned char *,length);
+   if (info == (unsigned char *) NULL)
+     {
+-      (void) ThrowException2(&image->exception,CoderWarning,
+-                             "unable to copy profile",(char *) NULL);
++      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
++          "Unable to copy profile");
+       return (MagickFail);
+     }
+   /* copy profile, skipping white space and column 1 "=" signs */
+@@ -1197,8 +1197,8 @@
+           if (*sp == '\0')
+             {
+               MagickFreeMemory(info);
+-              (void) ThrowException2(&image->exception,CoderWarning,
+-                                     "ran out of profile data",(char *) NULL);
++              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
++                  "ran out of profile data");
+               return (MagickFail);
+             }
+           sp++;
+@@ -1234,8 +1234,9 @@
+   if(SetImageProfile(image,profile_name,info,length) == MagickFail)
+     {
+       MagickFreeMemory(info);
+-      (void) ThrowException(&image->exception,ResourceLimitError,
+-                            MemoryAllocationFailed,"unable to copy profile");
++      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
++           "unable to copy profile");
++      return MagickFail;
+     }
+   MagickFreeMemory(info);
+   return MagickTrue;
+@@ -3285,7 +3286,6 @@
+               if (status == MagickFalse)
+                 {
+                   DestroyJNGInfo(color_image_info,alpha_image_info);
+-                  DestroyImage(alpha_image);
+                   (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                       "    could not allocate alpha_image blob");
+                   return ((Image *)NULL);
+@@ -3534,7 +3534,7 @@
+       CloseBlob(color_image);
+       if (logging)
+         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+-                              "    Reading jng_image from color_blob.");
++            "    Reading jng_image from color_blob.");
+ 
+       FormatString(color_image_info->filename,"%.1024s",color_image->filename);
+ 
+@@ -3558,13 +3558,18 @@
+ 
+       if (logging)
+         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+-                              "    Copying jng_image pixels to main image.");
++            "    Copying jng_image pixels to main image.");
+       image->rows=jng_height;
+       image->columns=jng_width;
+       length=image->columns*sizeof(PixelPacket);
++      if ((jng_height == 0 || jng_width == 0) && logging)
++        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
++            "    jng_width=%lu jng_height=%lu",
++            (unsigned long)jng_width,(unsigned long)jng_height);
+       for (y=0; y < (long) image->rows; y++)
+         {
+-          s=AcquireImagePixels(jng_image,0,y,image->columns,1,&image->exception);
++          s=AcquireImagePixels(jng_image,0,y,image->columns,1,
++             &image->exception);
+           q=SetImagePixels(image,0,y,image->columns,1);
+           (void) memcpy(q,s,length);
+           if (!SyncImagePixels(image))
+@@ -3589,45 +3594,79 @@
+               CloseBlob(alpha_image);
+               if (logging)
+                 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+-                                      "    Reading opacity from alpha_blob.");
++                     "    Reading opacity from alpha_blob.");
+ 
+               FormatString(alpha_image_info->filename,"%.1024s",
+                            alpha_image->filename);
+ 
+               jng_image=ReadImage(alpha_image_info,exception);
+ 
+-              for (y=0; y < (long) image->rows; y++)
++              if (jng_image == (Image *)NULL)
+                 {
+-                  s=AcquireImagePixels(jng_image,0,y,image->columns,1,
+-                                       &image->exception);
+-                  if (image->matte)
+-                    {
+-                      q=SetImagePixels(image,0,y,image->columns,1);
+-                      for (x=(long) image->columns; x > 0; x--,q++,s++)
+-                        q->opacity=(Quantum) MaxRGB-s->red;
+-                    }
+-                  else
++                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
++                       "    jng_image is NULL.");
++                  if (color_image_info)
++                    DestroyImageInfo(color_image_info);
++                  if (alpha_image_info)
++                    DestroyImageInfo(alpha_image_info);
++                  if (color_image)
++                    DestroyImage(color_image);
++                  if (alpha_image)
++                    DestroyImage(alpha_image);
++                }
++              else
++                {
++
++                  if (logging)
+                     {
+-                      q=SetImagePixels(image,0,y,image->columns,1);
+-                      for (x=(long) image->columns; x > 0; x--,q++,s++)
+-                        {
+-                          q->opacity=(Quantum) MaxRGB-s->red;
+-                          if (q->opacity != OpaqueOpacity)
+-                            image->matte=MagickTrue;
+-                        }
++                      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
++                          "    Read jng_image.");
++                      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
++                          "      jng_image->width=%lu, jng_image->height=%lu",
++                          (unsigned long)jng_width,(unsigned long)jng_height);
++                      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
++                          "      image->rows=%lu, image->columns=%lu",
++                         (unsigned long)image->rows,
++                         (unsigned long)image->columns);
+                     }
+-                  if (!SyncImagePixels(image))
+-                    break;
+-                }
+-              (void) LiberateUniqueFileResource(alpha_image->filename);
+-              DestroyImage(alpha_image);
+-              alpha_image = (Image *)NULL;
+-              DestroyImageInfo(alpha_image_info);
+-              alpha_image_info = (ImageInfo *)NULL;
+-              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+-                  " Destroy the JNG image");
+-              DestroyImage(jng_image);
+-              jng_image = (Image *)NULL;
++
++                  for (y=0; y < (long) image->rows; y++)
++                   {
++                     s=AcquireImagePixels(jng_image,0,y,image->columns,1,
++                                          &image->exception);
++                     if (image->matte)
++                       {
++                         q=SetImagePixels(image,0,y,image->columns,1);
++                         for (x=(long) image->columns; x > 0; x--,q++,s++)
++                           q->opacity=(Quantum) MaxRGB-s->red;
++                       }
++                     else
++                       {
++                         q=SetImagePixels(image,0,y,image->columns,1);
++                         for (x=(long) image->columns; x > 0; x--,q++,s++)
++                           {
++                             q->opacity=(Quantum) MaxRGB-s->red;
++                             if (q->opacity != OpaqueOpacity)
++                               image->matte=MagickTrue;
++                           }
++                       }
++                     if (!SyncImagePixels(image))
++                       break;
++                   }
++                 (void) LiberateUniqueFileResource(alpha_image->filename);
++                 if (color_image_info)
++                   DestroyImageInfo(color_image_info);
++                 if (alpha_image_info)
++                   DestroyImageInfo(alpha_image_info);
++                 if (color_image)
++                   DestroyImage(color_image);
++                 if (alpha_image)
++                   DestroyImage(alpha_image);
++                 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
++                     " Destroy the JNG image");
++                 DestroyImage(jng_image);
++                 jng_image = (Image *)NULL;
++               }
+             }
+         }
+ 
-- 
2.14.2