Removed popen() support from OpenBlob().
authorBob Friesenhahn <bfriesen@GraphicsMagick.org>
Sun, 29 May 2016 15:30:27 -0500
changeset 14851 ae3928faa858
parent 14850 c37414f6aee5
child 14852 0e90314bf56b
Removed popen() support from OpenBlob().
ChangeLog
NEWS.txt
magick/blob.c
www/Changelog.html
www/NEWS.html
--- a/ChangeLog	Sun May 29 09:23:57 2016 -0500
+++ b/ChangeLog	Sun May 29 15:30:27 2016 -0500
@@ -1,5 +1,12 @@
 2016-05-29  Bob Friesenhahn  <bfriesen@simple.dallas.tx.us>
 
+	* NEWS.txt: Updated with latest news.
+
+	* magick/blob.c (OpenBlob): Remove support for reading input from
+	a shell command, or writing output to a shell command, by
+	prefixing the specified filename (containing the command) with a
+	'|'.  This feature provided a remote shell execution opportunity.
+
 	* coders/mat.c (ReadMATImage): Validate that MAT frames is not
 	zero.
 
--- a/NEWS.txt	Sun May 29 09:23:57 2016 -0500
+++ b/NEWS.txt	Sun May 29 15:30:27 2016 -0500
@@ -6,7 +6,7 @@
 GraphicsMagick News
 ===================
 
-This file was last updated on May 22, 2016
+This file was last updated on May 29, 2016
 
 Please note that this file records news for the associated development
 branch and that each development branch has its own NEWS file. See the
@@ -42,6 +42,11 @@
 
 Security Fixes:
 
+* BLOB: Remove support for reading input from a shell command, or
+  writing output to a shell command, by prefixing the specified
+  filename (containing the command) with a '|'.  This feature provided
+  a remote shell execution opportunity.
+
 * DIB: Fixed out of bounds reads.  Added more header validations.
 
 * JNG: File size limits are enforced.
@@ -57,6 +62,8 @@
 
 * MVG: No longer assume that files ending with extension ".mvg" are
   MVG files.  MVG parsing does more validity checking on its input.
+  Assure that enough PrimitiveInfo structures are allocated in advance
+  to support a given vector path (heap overflow problem).
 
 * PCX: Fixed unreasonable memory allocation due to intentionally
   corrupt file.
@@ -114,6 +121,8 @@
 
 * JP2: It is now possible to write lossless JPEG 2000 "JP2" format.
 
+* SVG: Support font-size "medium".
+
 New Features:
 
 * Blob I/O C APIs: Added signed versions of short and long Read/Write
@@ -156,6 +165,9 @@
 * Files ending with ".mvg" and ".msl" are not assumed to be image
   files by default.
 
+* File names starting with '|' are no longer treated as shell
+  commands.
+
 1.3.23 (November 7, 2015)
 ==========================
 
--- a/magick/blob.c	Sun May 29 09:23:57 2016 -0500
+++ b/magick/blob.c	Sun May 29 15:30:27 2016 -0500
@@ -2433,8 +2433,7 @@
 %  OpenBlob() opens a file associated with the image.  A file name of '-' sets
 %  the file to stdin for type 'r' and stdout for type 'w'.  If the filename
 %  suffix is '.gz' or '.Z', the image is decompressed for type 'r' and
-%  compressed for type 'w'.  If the filename prefix is '|', it is piped to or
-%  from a system command.
+%  compressed for type 'w'.
 %
 %  The format of the OpenBlob method is:
 %
@@ -2478,7 +2477,7 @@
 }
 
 MagickExport MagickPassFail OpenBlob(const ImageInfo *image_info,Image *image,
-  const BlobMode mode,ExceptionInfo *exception)
+                                     const BlobMode mode,ExceptionInfo *exception)
 {
   char
     filename[MaxTextExtent],
@@ -2562,296 +2561,265 @@
       image->blob->exempt=True;
     }
   else
-#if defined(HAVE_POPEN)
-    if (*filename == '|')
-      {
-        char
-          mode_string[MaxTextExtent];
-
-        /*
-          Pipe image to ("w") or from ("r") a system command.
-        */
-#if !defined(MSWINDOWS)
-        if (*type == 'w')
-          (void) signal(SIGPIPE,SIG_IGN);
+    {
+      if (*type == 'w')
+        {
+          /*
+            Form filename for multi-part images.
+          */
+          if (!image_info->adjoin)
+            FormMultiPartFilename(image,image_info);
+          (void) strcpy(filename,image->filename);
+        }
+#if defined(HasZLIB)
+      if (((strlen(filename) > 2) &&
+           (LocaleCompare(filename+strlen(filename)-2,".Z") == 0)) ||
+          ((strlen(filename) > 3) &&
+           (LocaleCompare(filename+strlen(filename)-3,".gz") == 0)) ||
+          ((strlen(filename) > 5) &&
+           (LocaleCompare(filename+strlen(filename)-5,".svgz") == 0)))
+        {
+          image->blob->handle.gz=(gzFile) NULL;
+          if (MagickConfirmAccess((type[0] == 'r' ? FileReadConfirmAccessMode :
+                                   FileWriteConfirmAccessMode),filename,
+                                  exception) != MagickFail)
+            image->blob->handle.gz=gzopen(filename,type);
+          if (image->blob->handle.gz != (gzFile) NULL)
+            {
+              image->blob->type=ZipStream;
+              if (image->logging)
+                (void) LogMagickEvent(BlobEvent,GetMagickModule(),
+                                      "  opened file %s as ZipStream image"
+                                      " %p, blob %p",
+                                      filename,image,image->blob);
+            }
+        }
+      else
 #endif
-        (void) strlcpy(mode_string,type,sizeof(mode_string));
-        mode_string[1]='\0';
-	image->blob->handle.std=(FILE *) NULL;
-	if (MagickConfirmAccess(FileExecuteConfirmAccessMode,filename+1,
-				exception) != MagickFail)
-	  image->blob->handle.std=(FILE *) popen(filename+1,mode_string);
-        if (image->blob->handle.std != (FILE *) NULL)
+#if defined(HasBZLIB)
+        if ((strlen(filename) > 4) &&
+            (LocaleCompare(filename+strlen(filename)-4,".bz2") == 0))
           {
-            image->blob->type=PipeStream;
-            if (image->logging)
-              (void) LogMagickEvent(BlobEvent,GetMagickModule(),
-                                    "  popened \"%s\" as PipeStream image"
-                                    " %p, blob %p",
-                                    filename+1,image,image->blob);
-          }
-      }
-    else
-#endif /* defined(HAVE_POPEN) */
-      {
-        if (*type == 'w')
-          {
-            /*
-              Form filename for multi-part images.
-            */
-	    if (!image_info->adjoin)
-	      FormMultiPartFilename(image,image_info);
-            (void) strcpy(filename,image->filename);
-          }
-#if defined(HasZLIB)
-        if (((strlen(filename) > 2) &&
-             (LocaleCompare(filename+strlen(filename)-2,".Z") == 0)) ||
-            ((strlen(filename) > 3) &&
-             (LocaleCompare(filename+strlen(filename)-3,".gz") == 0)) ||
-            ((strlen(filename) > 5) &&
-             (LocaleCompare(filename+strlen(filename)-5,".svgz") == 0)))
-          {
-	    image->blob->handle.gz=(gzFile) NULL;
-	    if (MagickConfirmAccess((type[0] == 'r' ? FileReadConfirmAccessMode :
-				     FileWriteConfirmAccessMode),filename,
-				    exception) != MagickFail)
-	      image->blob->handle.gz=gzopen(filename,type);
-            if (image->blob->handle.gz != (gzFile) NULL)
+            image->blob->handle.bz=(BZFILE *) NULL;
+            if (MagickConfirmAccess((type[0] == 'r' ? FileReadConfirmAccessMode :
+                                     FileWriteConfirmAccessMode),filename,
+                                    exception) != MagickFail)
+              image->blob->handle.bz=(BZFILE *) BZ2_bzopen(filename,type);
+            if (image->blob->handle.bz != (BZFILE *) NULL)
               {
-                image->blob->type=ZipStream;
+                image->blob->type=BZipStream;
                 if (image->logging)
                   (void) LogMagickEvent(BlobEvent,GetMagickModule(),
-                                        "  opened file %s as ZipStream image"
+                                        "  opened file %s as BZipStream image"
                                         " %p, blob %p",
                                         filename,image,image->blob);
               }
           }
         else
 #endif
-#if defined(HasBZLIB)
-          if ((strlen(filename) > 4) &&
-              (LocaleCompare(filename+strlen(filename)-4,".bz2") == 0))
+          if (image_info->file != (FILE *) NULL)
             {
-	      image->blob->handle.bz=(BZFILE *) NULL;
-	      if (MagickConfirmAccess((type[0] == 'r' ? FileReadConfirmAccessMode :
-				       FileWriteConfirmAccessMode),filename,
-				      exception) != MagickFail)
-		image->blob->handle.bz=(BZFILE *) BZ2_bzopen(filename,type);
-              if (image->blob->handle.bz != (BZFILE *) NULL)
-                {
-                  image->blob->type=BZipStream;
-                  if (image->logging)
-                    (void) LogMagickEvent(BlobEvent,GetMagickModule(),
-                                          "  opened file %s as BZipStream image"
-                                          " %p, blob %p",
-                                          filename,image,image->blob);
-                }
+              image->blob->handle.std=image_info->file;
+              image->blob->type=FileStream;
+              image->blob->exempt=MagickTrue;
+              if (image->logging)
+                (void) LogMagickEvent(BlobEvent,GetMagickModule(),
+                                      "  opened image_info->file (%d) as"
+                                      " FileStream image %p, blob %p",
+                                      fileno(image_info->file),image,image->blob);
             }
           else
-#endif
-            if (image_info->file != (FILE *) NULL)
-              {
-                image->blob->handle.std=image_info->file;
-                image->blob->type=FileStream;
-                image->blob->exempt=MagickTrue;
-                if (image->logging)
-                  (void) LogMagickEvent(BlobEvent,GetMagickModule(),
-                                        "  opened image_info->file (%d) as"
-                                        " FileStream image %p, blob %p",
-                                        fileno(image_info->file),image,image->blob);
-              }
-            else
-              {
-		image->blob->handle.std=(FILE *) NULL;
-		if (MagickConfirmAccess((type[0] == 'r' ? FileReadConfirmAccessMode :
-					 FileWriteConfirmAccessMode),filename,
-					exception) != MagickFail)
-		  image->blob->handle.std=(FILE *) fopen(filename,type);
-                if (image->blob->handle.std != (FILE *) NULL)
-                  {
-                    char
-                      *env = NULL;
-
-                    unsigned char
-                      magick[MaxTextExtent];
-
-                    size_t
-                      count;
-
-                    size_t
-                      vbuf_size;
-
-		    vbuf_size=image->blob->block_size;
-                    if (0 != vbuf_size)
-                      {
-                        if (setvbuf(image->blob->handle.std,NULL,_IOFBF,vbuf_size) != 0)
-                          {
-                            if (image->logging)
-                              (void) LogMagickEvent(BlobEvent,GetMagickModule(),
-                                                    "  setvbuf of %" MAGICK_SIZE_T_F
-                                                    "u bytes returns failure!",
-                                                    (MAGICK_SIZE_T) vbuf_size);
-                          }
-                        else
-                          {
-                            if (image->logging)
-                              (void) LogMagickEvent(BlobEvent,GetMagickModule(),
-                                                    "  I/O buffer set to %"
-                                                    MAGICK_SIZE_T_F "u bytes",
-                                                    (MAGICK_SIZE_T) vbuf_size);
-                          }
-                      }
-                    /*
-                      Enable fsync-on-close mode if requested.
-                    */
-                    if (((WriteBlobMode == mode) || (WriteBinaryBlobMode == mode)) &&
-                        (env = getenv("MAGICK_IO_FSYNC")))
-                      {
-                        if (LocaleCompare(env,"TRUE") == 0)
-                          {
-                            image->blob->fsync=MagickTrue;
-                            if (image->logging)
-                              (void) LogMagickEvent(BlobEvent,GetMagickModule(),
-                                                    "  fsync() on close requested");
-                          }
-                      }
-                    image->blob->type=FileStream;
-                    if (image->logging)
-                      (void) LogMagickEvent(BlobEvent,GetMagickModule(),
-                                            "  opened file \"%s\" as FileStream image %p, blob %p",
-                                            filename,image,image->blob);
-
-		    if ((ReadBlobMode == mode) || (ReadBinaryBlobMode == mode))
-		      {
-			/*
-			  Read file header and check magick bytes.
-			*/
-			(void) memset((void *) magick,0,MaxTextExtent);
-                        count=fread(magick,1,MaxTextExtent,image->blob->handle.std);
-                        (void) MagickFseek(image->blob->handle.std,
-                                           -(magick_off_t) count,SEEK_CUR);
+            {
+              image->blob->handle.std=(FILE *) NULL;
+              if (MagickConfirmAccess((type[0] == 'r' ? FileReadConfirmAccessMode :
+                                       FileWriteConfirmAccessMode),filename,
+                                      exception) != MagickFail)
+                image->blob->handle.std=(FILE *) fopen(filename,type);
+              if (image->blob->handle.std != (FILE *) NULL)
+                {
+                  char
+                    *env = NULL;
+
+                  unsigned char
+                    magick[MaxTextExtent];
+
+                  size_t
+                    count;
+
+                  size_t
+                    vbuf_size;
+
+                  vbuf_size=image->blob->block_size;
+                  if (0 != vbuf_size)
+                    {
+                      if (setvbuf(image->blob->handle.std,NULL,_IOFBF,vbuf_size) != 0)
+                        {
+                          if (image->logging)
+                            (void) LogMagickEvent(BlobEvent,GetMagickModule(),
+                                                  "  setvbuf of %" MAGICK_SIZE_T_F
+                                                  "u bytes returns failure!",
+                                                  (MAGICK_SIZE_T) vbuf_size);
+                        }
+                      else
+                        {
+                          if (image->logging)
+                            (void) LogMagickEvent(BlobEvent,GetMagickModule(),
+                                                  "  I/O buffer set to %"
+                                                  MAGICK_SIZE_T_F "u bytes",
+                                                  (MAGICK_SIZE_T) vbuf_size);
+                        }
+                    }
+                  /*
+                    Enable fsync-on-close mode if requested.
+                  */
+                  if (((WriteBlobMode == mode) || (WriteBinaryBlobMode == mode)) &&
+                      (env = getenv("MAGICK_IO_FSYNC")))
+                    {
+                      if (LocaleCompare(env,"TRUE") == 0)
+                        {
+                          image->blob->fsync=MagickTrue;
+                          if (image->logging)
+                            (void) LogMagickEvent(BlobEvent,GetMagickModule(),
+                                                  "  fsync() on close requested");
+                        }
+                    }
+                  image->blob->type=FileStream;
+                  if (image->logging)
+                    (void) LogMagickEvent(BlobEvent,GetMagickModule(),
+                                          "  opened file \"%s\" as FileStream image %p, blob %p",
+                                          filename,image,image->blob);
+
+                  if ((ReadBlobMode == mode) || (ReadBinaryBlobMode == mode))
+                    {
+                      /*
+                        Read file header and check magick bytes.
+                      */
+                      (void) memset((void *) magick,0,MaxTextExtent);
+                      count=fread(magick,1,MaxTextExtent,image->blob->handle.std);
+                      (void) MagickFseek(image->blob->handle.std,
+                                         -(magick_off_t) count,SEEK_CUR);
 #if defined(POSIX)
-                        /*
-                          Discard any buffered input and adjust the
-                          file pointer such that the next input
-                          operation accesses the byte after the last
-                          one read. This avoids possible problems if
-                          the fseek()/rewind() implementations do not
-                          implicitly empty the stdio input buffer.
-                         */
-                        (void) fflush(image->blob->handle.std);
+                      /*
+                        Discard any buffered input and adjust the
+                        file pointer such that the next input
+                        operation accesses the byte after the last
+                        one read. This avoids possible problems if
+                        the fseek()/rewind() implementations do not
+                        implicitly empty the stdio input buffer.
+                      */
+                      (void) fflush(image->blob->handle.std);
 #endif /* defined(POSIX) */
-			if (image->logging)
-			  (void) LogMagickEvent(BlobEvent,GetMagickModule(),
-						"  read %" MAGICK_SIZE_T_F
-                                                "u magic header bytes",
-						(MAGICK_SIZE_T) count);
+                      if (image->logging)
+                        (void) LogMagickEvent(BlobEvent,GetMagickModule(),
+                                              "  read %" MAGICK_SIZE_T_F
+                                              "u magic header bytes",
+                                              (MAGICK_SIZE_T) count);
 #if defined(HasZLIB)
-			if ((magick[0] == 0x1FU) && (magick[1] == 0x8BU) &&
-			    (magick[2] == 0x08U))
-			  {
-			    (void) fclose(image->blob->handle.std);
-			    image->blob->handle.gz=gzopen(filename,type);
-			    if (image->blob->handle.gz != (gzFile) NULL)
-			      {
-				image->blob->type=ZipStream;
-				if (image->logging)
-				  (void) LogMagickEvent(BlobEvent,GetMagickModule(),
-							"  reopened file \"%s\""
-                                                        "as ZipStream image %p, blob %p",
-							filename,image,image->blob);
-			      }
-			  }
+                      if ((magick[0] == 0x1FU) && (magick[1] == 0x8BU) &&
+                          (magick[2] == 0x08U))
+                        {
+                          (void) fclose(image->blob->handle.std);
+                          image->blob->handle.gz=gzopen(filename,type);
+                          if (image->blob->handle.gz != (gzFile) NULL)
+                            {
+                              image->blob->type=ZipStream;
+                              if (image->logging)
+                                (void) LogMagickEvent(BlobEvent,GetMagickModule(),
+                                                      "  reopened file \"%s\""
+                                                      "as ZipStream image %p, blob %p",
+                                                      filename,image,image->blob);
+                            }
+                        }
 #endif
 #if defined(HasBZLIB)
-			if (strncmp((char *) magick,"BZh",3) == 0)
-			  {
-			    (void) fclose(image->blob->handle.std);
-			    image->blob->handle.bz=BZ2_bzopen(filename,type);
-			    if (image->blob->handle.bz != (BZFILE *) NULL)
-			      {
-				image->blob->type=BZipStream;
-				if (image->logging)
-				  (void) LogMagickEvent(BlobEvent,GetMagickModule(),
-							"  reopened file %s as"
-                                                        " BZipStream image %p, blob %p",
-							filename,image,image->blob);
-			      }
-			  }
+                      if (strncmp((char *) magick,"BZh",3) == 0)
+                        {
+                          (void) fclose(image->blob->handle.std);
+                          image->blob->handle.bz=BZ2_bzopen(filename,type);
+                          if (image->blob->handle.bz != (BZFILE *) NULL)
+                            {
+                              image->blob->type=BZipStream;
+                              if (image->logging)
+                                (void) LogMagickEvent(BlobEvent,GetMagickModule(),
+                                                      "  reopened file %s as"
+                                                      " BZipStream image %p, blob %p",
+                                                      filename,image,image->blob);
+                            }
+                        }
 #endif
-		      }
-                  }
-              }
-        if (image->blob->type == FileStream)
-          {
-            const char* env_val;
-
-            if (*type == 'r')
-              {
-                /*
-                  Support reading from a file using memory mapping.
+                    }
+                }
+            }
+      if (image->blob->type == FileStream)
+        {
+          const char* env_val;
+
+          if (*type == 'r')
+            {
+              /*
+                Support reading from a file using memory mapping.
                   
-                  This code was used for years and definitely speeds
-                  re-reading of the same file, but it has been
-                  discovered that some operating systems (e.g. FreeBSD
-                  and Apple's OS-X) fail to perform automatic
-                  read-ahead for network files.  It will be disabled
-                  by default until we add a way to force read-ahead.
-                */
-                if (((env_val = getenv("MAGICK_MMAP_READ")) != NULL) &&
-                    (LocaleCompare(env_val,"TRUE") == 0))
-                  {
-                    const MagickInfo
-                      *magick_info;
+                This code was used for years and definitely speeds
+                re-reading of the same file, but it has been
+                discovered that some operating systems (e.g. FreeBSD
+                and Apple's OS-X) fail to perform automatic
+                read-ahead for network files.  It will be disabled
+                by default until we add a way to force read-ahead.
+              */
+              if (((env_val = getenv("MAGICK_MMAP_READ")) != NULL) &&
+                  (LocaleCompare(env_val,"TRUE") == 0))
+                {
+                  const MagickInfo
+                    *magick_info;
                 
-                    MagickStatStruct_t
-                      attributes;
-
-                    magick_info=GetMagickInfo(image_info->magick,&image->exception);
-                    if ((magick_info != (const MagickInfo *) NULL) &&
-                        magick_info->blob_support)
-                      {
-                        if ((MagickFstat(fileno(image->blob->handle.std),&attributes) >= 0) &&
-                            (attributes.st_size > MinBlobExtent) &&
-                            (attributes.st_size == (off_t) ((size_t) attributes.st_size)))
-                          {
-                            size_t
-                              length;
+                  MagickStatStruct_t
+                    attributes;
+
+                  magick_info=GetMagickInfo(image_info->magick,&image->exception);
+                  if ((magick_info != (const MagickInfo *) NULL) &&
+                      magick_info->blob_support)
+                    {
+                      if ((MagickFstat(fileno(image->blob->handle.std),&attributes) >= 0) &&
+                          (attributes.st_size > MinBlobExtent) &&
+                          (attributes.st_size == (off_t) ((size_t) attributes.st_size)))
+                        {
+                          size_t
+                            length;
                       
-                            void
-                              *blob;
+                          void
+                            *blob;
                       
-                            length=(size_t) attributes.st_size;
-
-                            if (AcquireMagickResource(MapResource,length))
-                              {
-                                blob=MapBlob(fileno(image->blob->handle.std),ReadMode,0,length);
-                                if (blob != (void *) NULL)
-                                  {
-                                    /*
-                                      Format supports blobs-- use memory-mapped I/O.
-                                    */
-                                    if (image_info->file != (FILE *) NULL)
-                                      image->blob->exempt=MagickFalse;
-                                    else
-                                      {
-                                        (void) fclose(image->blob->handle.std);
-                                        image->blob->handle.std=(FILE *) NULL;
-                                      }
-                                    AttachBlob(image->blob,blob,length);
-                                    image->blob->mapped=True;
-                                  }
-                                else
-                                  {
-                                    LiberateMagickResource(MapResource,length);
-                                  }
-                              }
-                          }
-                      }
-                  }
-              }
-          }
-      }
+                          length=(size_t) attributes.st_size;
+
+                          if (AcquireMagickResource(MapResource,length))
+                            {
+                              blob=MapBlob(fileno(image->blob->handle.std),ReadMode,0,length);
+                              if (blob != (void *) NULL)
+                                {
+                                  /*
+                                    Format supports blobs-- use memory-mapped I/O.
+                                  */
+                                  if (image_info->file != (FILE *) NULL)
+                                    image->blob->exempt=MagickFalse;
+                                  else
+                                    {
+                                      (void) fclose(image->blob->handle.std);
+                                      image->blob->handle.std=(FILE *) NULL;
+                                    }
+                                  AttachBlob(image->blob,blob,length);
+                                  image->blob->mapped=True;
+                                }
+                              else
+                                {
+                                  LiberateMagickResource(MapResource,length);
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
   image->blob->status=MagickFalse;
   if (image->blob->type != UndefinedStream)
     image->blob->size=GetBlobSize(image);
--- a/www/Changelog.html	Sun May 29 09:23:57 2016 -0500
+++ b/www/Changelog.html	Sun May 29 15:30:27 2016 -0500
@@ -38,6 +38,11 @@
 <p>2016-05-29  Bob Friesenhahn  &lt;<a class="reference external" href="mailto:bfriesen&#37;&#52;&#48;simple&#46;dallas&#46;tx&#46;us">bfriesen<span>&#64;</span>simple<span>&#46;</span>dallas<span>&#46;</span>tx<span>&#46;</span>us</a>&gt;</p>
 <blockquote>
 <ul class="simple">
+<li>NEWS.txt: Updated with latest news.</li>
+<li>magick/blob.c (OpenBlob): Remove support for reading input from
+a shell command, or writing output to a shell command, by
+prefixing the specified filename (containing the command) with a
+'|'.  This feature provided a remote shell execution opportunity.</li>
 <li>coders/mat.c (ReadMATImage): Validate that MAT frames is not
 zero.</li>
 </ul>
--- a/www/NEWS.html	Sun May 29 09:23:57 2016 -0500
+++ b/www/NEWS.html	Sun May 29 15:30:27 2016 -0500
@@ -38,7 +38,7 @@
 <!-- -*- mode: rst -*- -->
 <!-- This text is in reStucturedText format, so it may look a bit odd. -->
 <!-- See http://docutils.sourceforge.net/rst.html for details. -->
-<p>This file was last updated on May 22, 2016</p>
+<p>This file was last updated on May 29, 2016</p>
 <p>Please note that this file records news for the associated development
 branch and that each development branch has its own NEWS file. See the
 ChangeLog file for full details.</p>
@@ -97,6 +97,10 @@
 </ul>
 <p>Security Fixes:</p>
 <ul class="simple">
+<li>BLOB: Remove support for reading input from a shell command, or
+writing output to a shell command, by prefixing the specified
+filename (containing the command) with a '|'.  This feature provided
+a remote shell execution opportunity.</li>
 <li>DIB: Fixed out of bounds reads.  Added more header validations.</li>
 <li>JNG: File size limits are enforced.</li>
 <li>MAT: Fixed denial of service opportunity.  Fix hang on corrupt deflate stream.</li>
@@ -105,7 +109,9 @@
 <li>MSL: Ignore the file extension on MSL files.  It is necessary to add
 a &quot;msl:&quot; prefix to MSL files to read the as an image.</li>
 <li>MVG: No longer assume that files ending with extension &quot;.mvg&quot; are
-MVG files.  MVG parsing does more validity checking on its input.</li>
+MVG files.  MVG parsing does more validity checking on its input.
+Assure that enough PrimitiveInfo structures are allocated in advance
+to support a given vector path (heap overflow problem).</li>
 <li>PCX: Fixed unreasonable memory allocation due to intentionally
 corrupt file.</li>
 <li>PDB: Fixed a heap buffer overflow and out of bounds read.</li>
@@ -141,6 +147,7 @@
 <li>FILE: <cite>file://</cite> URLs are properly supported now (they never worked
 before).</li>
 <li>JP2: It is now possible to write lossless JPEG 2000 &quot;JP2&quot; format.</li>
+<li>SVG: Support font-size &quot;medium&quot;.</li>
 </ul>
 <p>New Features:</p>
 <ul class="simple">
@@ -174,6 +181,8 @@
 <li>PSD format is not included in the build by default.</li>
 <li>Files ending with &quot;.mvg&quot; and &quot;.msl&quot; are not assumed to be image
 files by default.</li>
+<li>File names starting with '|' are no longer treated as shell
+commands.</li>
 </ul>
 </div>
 <div class="section" id="november-7-2015">