Commit 8309dc92a for imagemagick.org

commit 8309dc92a18722a9ccc4bb9c848ac2d01426cfe5
Author: Dirk Lemstra <dirk@lemstra.org>
Date:   Thu Sep 3 21:32:06 2026 +0200

    Trim labels to prevent code injection (GHSA-p6j5-2qwh-6486)

diff --git a/MagickCore/annotate.c b/MagickCore/annotate.c
index 5624a72e4..2773f415f 100644
--- a/MagickCore/annotate.c
+++ b/MagickCore/annotate.c
@@ -2292,7 +2292,7 @@ static MagickBooleanType RenderPostscript(Image *image,
   (void) FormatLocaleFile(file,"[%g %g %g %g 0 0] concat\n",
     draw_info->affine.sx,-draw_info->affine.rx,-draw_info->affine.ry,
     draw_info->affine.sy);
-  text=EscapeParenthesis(draw_info->text);
+  text=EscapeParenthesis(draw_info->text,MAGICK_SIZE_MAX,exception);
   if (identity == MagickFalse)
     (void) FormatLocaleFile(file,"(%s) stringwidth pop -0.5 mul -0.5 rmoveto\n",
       text);
diff --git a/coders/ghostscript-private.h b/coders/ghostscript-private.h
index d1d38f3cb..ee64ab13c 100644
--- a/coders/ghostscript-private.h
+++ b/coders/ghostscript-private.h
@@ -278,7 +278,8 @@ static inline void ReadGhostScriptXMPProfile(MagickByteBuffer *buffer,
   SetStringInfoLength(*profile,(size_t) count);
 }

-static inline char *EscapeParenthesis(const char *source)
+static inline char *EscapeParenthesis(const char *source,
+  const size_t max_length,ExceptionInfo *exception)
 {
   char
     *destination;
@@ -287,6 +288,7 @@ static inline char *EscapeParenthesis(const char *source)
     *q;

   const char
+    *end,
     *p;

   size_t
@@ -294,16 +296,21 @@ static inline char *EscapeParenthesis(const char *source)

   assert(source != (const char *) NULL);
   length=0;
+  end=source;
   for (p=source; *p != '\0'; p++)
   {
-    if ((*p == '\\') || (*p == '(') || (*p == ')'))
-      {
-        if (~length < 1)
-          ThrowFatalException(ResourceLimitFatalError,"UnableToEscapeString");
-        length++;
-      }
-    length++;
+    size_t
+      count;
+
+    count=((*p == '\\') || (*p == '(') || (*p == ')')) ? 2 : 1;
+    if ((~length < count) || ((length+count) > max_length))
+      break;
+    length+=count;
+    end=p+1;
   }
+  if (*end != '\0')
+    (void) ThrowMagickException(exception,GetMagickModule(),CoderWarning,
+      "LabelTruncated","`%g'",(double) max_length);
   destination=(char *) NULL;
   if (~length >= (MagickPathExtent-1))
     destination=(char *) AcquireQuantumMemory(length+MagickPathExtent,
@@ -312,7 +319,7 @@ static inline char *EscapeParenthesis(const char *source)
     ThrowFatalException(ResourceLimitFatalError,"UnableToEscapeString");
   *destination='\0';
   q=destination;
-  for (p=source; *p != '\0'; p++)
+  for (p=source; p < end; p++)
   {
     if ((*p == '\\') || (*p == '(') || (*p == ')'))
       *q++='\\';
diff --git a/coders/pdf.c b/coders/pdf.c
index f16069e86..11440d37a 100644
--- a/coders/pdf.c
+++ b/coders/pdf.c
@@ -1256,7 +1256,7 @@ static const char *GetPDFKeywords(const ImageInfo *image_info)
 }

 static void WritePDFValue(Image* image,const char *keyword,
-  const char *value,const MagickBooleanType is_pdfa)
+  const char *value,const MagickBooleanType is_pdfa,ExceptionInfo *exception)
 {
   char
     *escaped;
@@ -1274,7 +1274,7 @@ static void WritePDFValue(Image* image,const char *keyword,
     return;
   if (is_pdfa != MagickFalse)
     {
-      escaped=EscapeParenthesis(value);
+      escaped=EscapeParenthesis(value,MAGICK_SIZE_MAX,exception);
       (void) WriteBlobString(image,"/");
       (void) WriteBlobString(image,keyword);
       (void) WriteBlobString(image," (");
@@ -1912,7 +1912,7 @@ static MagickBooleanType WritePDFImage(const ImageInfo *image_info,Image *image,
           (double) geometry.x,(double) (geometry.y+(ssize_t) geometry.height+
           i*pointsize+12));
         (void) WriteBlobString(image,buffer);
-        escape=EscapeParenthesis(labels[i]);
+        escape=EscapeParenthesis(labels[i],MAGICK_SIZE_MAX,exception);
         (void) FormatLocaleString(buffer,MagickPathExtent,"(%s) Tj\n",escape);
         escape=DestroyString(escape);
         (void) WriteBlobString(image,buffer);
@@ -3168,12 +3168,12 @@ static MagickBooleanType WritePDFImage(const ImageInfo *image_info,Image *image,
     object);
   (void) WriteBlobString(image,buffer);
   (void) WriteBlobString(image,"<<\n");
-  WritePDFValue(image,"Title",GetPDFTitle(image_info,basename),is_pdfa);
-  WritePDFValue(image,"Author",GetPDFAuthor(image_info),is_pdfa);
-  WritePDFValue(image,"Creator",GetPDFCreator(image_info),is_pdfa);
-  WritePDFValue(image,"Producer",GetPDFProducer(image_info),is_pdfa);
-  WritePDFValue(image,"Subject",GetPDFSubject(image_info),is_pdfa);
-  WritePDFValue(image,"Keywords",GetPDFKeywords(image_info),is_pdfa);
+  WritePDFValue(image,"Title",GetPDFTitle(image_info,basename),is_pdfa,exception);
+  WritePDFValue(image,"Author",GetPDFAuthor(image_info),is_pdfa,exception);
+  WritePDFValue(image,"Creator",GetPDFCreator(image_info),is_pdfa,exception);
+  WritePDFValue(image,"Producer",GetPDFProducer(image_info),is_pdfa,exception);
+  WritePDFValue(image,"Subject",GetPDFSubject(image_info),is_pdfa,exception);
+  WritePDFValue(image,"Keywords",GetPDFKeywords(image_info),is_pdfa,exception);
   seconds=GetPdfCreationDate(image_info,image);
   GetMagickUTCTime(&seconds,&utc_time);
   (void) FormatLocaleString(temp,MagickPathExtent,"D:%04d%02d%02d%02d%02d%02d",
diff --git a/coders/ps.c b/coders/ps.c
index 02a90746c..5fe273cad 100644
--- a/coders/ps.c
+++ b/coders/ps.c
@@ -1857,7 +1857,7 @@ static MagickBooleanType WritePSImage(const ImageInfo *image_info,Image *image,
           char
             *escape;

-          escape=EscapeParenthesis(labels[i]);
+          escape=EscapeParenthesis(labels[i],510,exception);
           (void) FormatLocaleString(buffer,MagickPathExtent,"%s \n",escape);
           escape=DestroyString(escape);
           (void) WriteBlobString(image,buffer);
diff --git a/coders/ps2.c b/coders/ps2.c
index 2d03d72d8..82822cedd 100644
--- a/coders/ps2.c
+++ b/coders/ps2.c
@@ -793,7 +793,7 @@ static MagickBooleanType WritePS2Image(const ImageInfo *image_info,Image *image,
           char
             *escape;

-          escape=EscapeParenthesis(labels[i]);
+          escape=EscapeParenthesis(labels[i],510,exception);
           (void) FormatLocaleString(buffer,MagickPathExtent,"%s \n",escape);
           escape=DestroyString(escape);
           (void) WriteBlobString(image,buffer);
diff --git a/coders/ps3.c b/coders/ps3.c
index acc814f6e..d3be0cfa9 100644
--- a/coders/ps3.c
+++ b/coders/ps3.c
@@ -1296,7 +1296,7 @@ static MagickBooleanType WritePS3Image(const ImageInfo *image_info,Image *image,
           char
             *escape;

-          escape=EscapeParenthesis(labels[i]);
+          escape=EscapeParenthesis(labels[i],510,exception);
           if (compression != NoCompression)
             {
               for (j=0; escape[j] != '\0'; j++)