Commit 9db96365e for imagemagick.org

commit 9db96365ecab5de69cdec81b9359672b3a827aaa
Author: Dirk Lemstra <dirk@lemstra.org>
Date:   Sun Feb 15 16:52:24 2026 +0100

    Escape more strings when creating an MVG file in the internal SVG decoder (GHSA-xpg8-7m6m-jf56)

diff --git a/coders/svg.c b/coders/svg.c
index e3d3a4c41..52220081e 100644
--- a/coders/svg.c
+++ b/coders/svg.c
@@ -880,6 +880,19 @@ static char **SVGKeyValuePairs(SVGInfo *svg_info,const int key_sentinel,
   return(tokens);
 }

+static inline char *SVGEscapeString(const char* value)
+{
+  char
+    *escaped_value,
+    *p;
+
+  escaped_value=EscapeString(value,'\"');
+  for (p=escaped_value; *p != '\0'; p++)
+    if (*p == '\n')
+      *p=' ';
+  return(escaped_value);
+}
+
 static void SVGProcessStyleElement(SVGInfo *svg_info,const xmlChar *name,
   const char *style)
 {
@@ -888,8 +901,7 @@ static void SVGProcessStyleElement(SVGInfo *svg_info,const xmlChar *name,
     *color,
     *keyword,
     **tokens,
-    *units,
-    *value;
+    *units;

   size_t
     number_tokens;
@@ -904,10 +916,10 @@ static void SVGProcessStyleElement(SVGInfo *svg_info,const xmlChar *name,
   for (i=0; i < ((ssize_t) number_tokens-1); i+=2)
   {
     keyword=(char *) tokens[i];
-    value=(char *) tokens[i+1];
     if (LocaleCompare(keyword,"font-size") != 0)
       continue;
-    svg_info->pointsize=GetUserSpaceCoordinateValue(svg_info,0,value);
+    svg_info->pointsize=GetUserSpaceCoordinateValue(svg_info,0,
+      (char *) tokens[i+1]);
     (void) FormatLocaleFile(svg_info->file,"font-size %g\n",
       svg_info->pointsize);
   }
@@ -915,8 +927,11 @@ static void SVGProcessStyleElement(SVGInfo *svg_info,const xmlChar *name,
   units=AcquireString("userSpaceOnUse");
   for (i=0; i < ((ssize_t) number_tokens-1); i+=2)
   {
+    char
+      *value;
+
     keyword=(char *) tokens[i];
-    value=(char *) tokens[i+1];
+    value=SVGEscapeString((const char *) tokens[i+1]);
     (void) LogMagickEvent(CoderEvent,GetMagickModule(),"    %s: %s",keyword,
       value);
     switch (*keyword)
@@ -1201,6 +1216,7 @@ static void SVGProcessStyleElement(SVGInfo *svg_info,const xmlChar *name,
       default:
         break;
     }
+    value=DestroyString(value);
   }
   if (units != (char *) NULL)
     units=DestroyString(units);
@@ -1234,8 +1250,7 @@ static void SVGStartElement(void *context,const xmlChar *name,

   const char
     *keyword,
-    *p,
-    *value;
+    *p;

   size_t
     number_tokens;
@@ -1279,7 +1294,6 @@ static void SVGStartElement(void *context,const xmlChar *name,
   *id='\0';
   *token='\0';
   *background='\0';
-  value=(const char *) NULL;
   if ((LocaleCompare((char *) name,"image") == 0) ||
       (LocaleCompare((char *) name,"pattern") == 0) ||
       (LocaleCompare((char *) name,"rect") == 0) ||
@@ -1292,8 +1306,11 @@ static void SVGStartElement(void *context,const xmlChar *name,
   if (attributes != (const xmlChar **) NULL)
     for (i=0; (attributes[i] != (const xmlChar *) NULL); i+=2)
     {
+      char
+        *value;
+
       keyword=(const char *) attributes[i];
-      value=(const char *) attributes[i+1];
+      value=SVGEscapeString((const char *) attributes[i+1]);
       switch (*keyword)
       {
         case 'C':
@@ -1420,6 +1437,7 @@ static void SVGStartElement(void *context,const xmlChar *name,
         default:
           break;
       }
+      value=DestroyString(value);
     }
   if (strchr((char *) name,':') != (char *) NULL)
     {
@@ -1644,8 +1662,11 @@ static void SVGStartElement(void *context,const xmlChar *name,
   if (attributes != (const xmlChar **) NULL)
     for (i=0; (attributes[i] != (const xmlChar *) NULL); i+=2)
     {
+      char
+        *value;
+
       keyword=(const char *) attributes[i];
-      value=(const char *) attributes[i+1];
+      value=SVGEscapeString((const char *) attributes[i+1]);
       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
         "    %s = %s",keyword,value);
       switch (*keyword)
@@ -2495,6 +2516,7 @@ static void SVGStartElement(void *context,const xmlChar *name,
         default:
           break;
       }
+      value=DestroyString(value);
     }
   if (LocaleCompare((const char *) name,"svg") == 0)
     {
@@ -2599,19 +2621,9 @@ static void SVGEndElement(void *context,const xmlChar *name)
         }
       if (LocaleCompare((const char *) name,"desc") == 0)
         {
-          char
-            *p;
-
           if (*svg_info->text == '\0')
             break;
-          (void) fputc('#',svg_info->file);
-          for (p=svg_info->text; *p != '\0'; p++)
-          {
-            (void) fputc(*p,svg_info->file);
-            if (*p == '\n')
-              (void) fputc('#',svg_info->file);
-          }
-          (void) fputc('\n',svg_info->file);
+          (void) FormatLocaleFile(svg_info->file,"# %s\n",svg_info->text);
           *svg_info->text='\0';
           break;
         }
@@ -2661,7 +2673,6 @@ static void SVGEndElement(void *context,const xmlChar *name)
       if (LocaleCompare((const char *) name,"image") == 0)
         {
           char
-            *text,
             thread_filename[MagickPathExtent];

           Image
@@ -2693,12 +2704,10 @@ static void SVGEndElement(void *context,const xmlChar *name)
           if (image != (Image *) NULL)
             image=DestroyImage(image);
           (void) DeleteNodeFromSplayTree(svg_tree,thread_filename);
-          text=EscapeString(svg_info->url,'\"');
           (void) FormatLocaleFile(svg_info->file,
             "image Over %g,%g %g,%g \"%s\"\n",svg_info->bounds.x,
             svg_info->bounds.y,svg_info->bounds.width,svg_info->bounds.height,
-            text);
-          text=DestroyString(text);
+            svg_info->url);
           (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
           break;
         }
@@ -2911,15 +2920,11 @@ static void SVGEndElement(void *context,const xmlChar *name)
     {
       if (LocaleCompare((char *) name,"use") == 0)
         {
-          char
-            *text;
-
           if ((svg_info->bounds.x != 0.0) || (svg_info->bounds.y != 0.0))
             (void) FormatLocaleFile(svg_info->file,"translate %g,%g\n",
               svg_info->bounds.x,svg_info->bounds.y);
-          text=EscapeString(svg_info->url,'\"');
-          (void) FormatLocaleFile(svg_info->file,"use \"url(%s)\"\n",text);
-          text=DestroyString(text);
+          (void) FormatLocaleFile(svg_info->file,"use \"url(%s)\"\n",
+            svg_info->url);
           (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
           break;
         }
@@ -2937,12 +2942,8 @@ static void SVGEndElement(void *context,const xmlChar *name)
 static void SVGCharacters(void *context,const xmlChar *c,int length)
 {
   char
-    *p,
     *text;

-  ssize_t
-    i;
-
   SVGInfo
     *svg_info;

@@ -2959,10 +2960,8 @@ static void SVGCharacters(void *context,const xmlChar *c,int length)
   text=(char *) AcquireQuantumMemory((size_t) length+1,sizeof(*text));
   if (text == (char *) NULL)
     return;
-  p=text;
-  for (i=0; i < (ssize_t) length; i++)
-    *p++=(char) c[i];
-  *p='\0';
+  memcpy(text,c,length);
+  text[length] = '\0';
   SVGStripString(MagickFalse,text);
   if (svg_info->text == (char *) NULL)
     svg_info->text=text;