Commit 59071d53a for imagemagick.org
commit 59071d53ae13542174f99f81e59cca076bd5d70e
Author: Cristy <urban-warrior@imagemagick.org>
Date: Wed Sep 30 20:20:18 2026 -0400
https://github.com/ImageMagick/ImageMagick/security/advisories/GHSA-qq8x-fq3x-43h4
diff --git a/coders/svg.c b/coders/svg.c
index 5caf22445..c01f05925 100644
--- a/coders/svg.c
+++ b/coders/svg.c
@@ -708,6 +708,72 @@ static SVGInfo *DestroySVGInfo(SVGInfo *svg_info)
return((SVGInfo *) RelinquishMagickMemory(svg_info));
}
+static char *EscapeSVGAttributeValue(const char *string)
+{
+ char
+ *destination;
+
+ const unsigned char
+ *p;
+
+ size_t
+ length;
+
+ /*
+ XML encode text written into SVG attribute/style value contexts.
+ */
+ if (string == (const char *) NULL)
+ return(AcquireString(""));
+ length=strlen(string);
+ destination=(char *) AcquireQuantumMemory(6UL*length+1UL,
+ sizeof(*destination));
+ if (destination == (char *) NULL)
+ return(AcquireString(""));
+ *destination='\0';
+ for (p=(const unsigned char *) string; *p != '\0'; p++)
+ {
+ switch (*p)
+ {
+ case '&':
+ {
+ (void) ConcatenateMagickString(destination,"&",6UL*length+1UL);
+ break;
+ }
+ case '<':
+ {
+ (void) ConcatenateMagickString(destination,"<",6UL*length+1UL);
+ break;
+ }
+ case '>':
+ {
+ (void) ConcatenateMagickString(destination,">",6UL*length+1UL);
+ break;
+ }
+ case '"':
+ {
+ (void) ConcatenateMagickString(destination,""",6UL*length+1UL);
+ break;
+ }
+ case '\'':
+ {
+ (void) ConcatenateMagickString(destination,"'",6UL*length+1UL);
+ break;
+ }
+ default:
+ {
+ char
+ c[2];
+
+ c[0]=(char) *p;
+ c[1]='\0';
+ (void) ConcatenateMagickString(destination,c,6UL*length+1UL);
+ break;
+ }
+ }
+ }
+ return(destination);
+}
+
static double GetUserSpaceCoordinateValue(const SVGInfo *svg_info,int type,
const char *string)
{
@@ -3783,6 +3849,7 @@ static MagickBooleanType WriteSVGImage(const ImageInfo *image_info,Image *image,
affine;
char
+ *escaped_token,
keyword[MagickPathExtent],
message[MagickPathExtent],
name[MagickPathExtent],
@@ -3973,24 +4040,30 @@ static MagickBooleanType WriteSVGImage(const ImageInfo *image_info,Image *image,
if (LocaleCompare("clip-path",keyword) == 0)
{
(void) GetNextToken(q,&q,extent,token);
+ escaped_token=EscapeSVGAttributeValue(token);
(void) FormatLocaleString(message,MagickPathExtent,
- "clip-path:url(#%s);",token);
+ "clip-path:url(#%s);",escaped_token);
+ escaped_token=DestroyString(escaped_token);
(void) WriteBlobString(image,message);
break;
}
if (LocaleCompare("clip-rule",keyword) == 0)
{
(void) GetNextToken(q,&q,extent,token);
+ escaped_token=EscapeSVGAttributeValue(token);
(void) FormatLocaleString(message,MagickPathExtent,"clip-rule:%s;",
- token);
+ escaped_token);
+ escaped_token=DestroyString(escaped_token);
(void) WriteBlobString(image,message);
break;
}
if (LocaleCompare("clip-units",keyword) == 0)
{
(void) GetNextToken(q,&q,extent,token);
+ escaped_token=EscapeSVGAttributeValue(token);
(void) FormatLocaleString(message,MagickPathExtent,
- "clipPathUnits=%s;",token);
+ "clipPathUnits=%s;",escaped_token);
+ escaped_token=DestroyString(escaped_token);
(void) WriteBlobString(image,message);
break;
}
@@ -4018,8 +4091,10 @@ static MagickBooleanType WriteSVGImage(const ImageInfo *image_info,Image *image,
if (LocaleCompare("decorate",keyword) == 0)
{
(void) GetNextToken(q,&q,extent,token);
+ escaped_token=EscapeSVGAttributeValue(token);
(void) FormatLocaleString(message,MagickPathExtent,
- "text-decoration:%s;",token);
+ "text-decoration:%s;",escaped_token);
+ escaped_token=DestroyString(escaped_token);
(void) WriteBlobString(image,message);
break;
}
@@ -4043,64 +4118,80 @@ static MagickBooleanType WriteSVGImage(const ImageInfo *image_info,Image *image,
if (LocaleCompare("fill",keyword) == 0)
{
(void) GetNextToken(q,&q,extent,token);
+ escaped_token=EscapeSVGAttributeValue(token);
(void) FormatLocaleString(message,MagickPathExtent,"fill:%s;",
- token);
+ escaped_token);
+ escaped_token=DestroyString(escaped_token);
(void) WriteBlobString(image,message);
break;
}
if (LocaleCompare("fill-rule",keyword) == 0)
{
(void) GetNextToken(q,&q,extent,token);
+ escaped_token=EscapeSVGAttributeValue(token);
(void) FormatLocaleString(message,MagickPathExtent,
- "fill-rule:%s;",token);
+ "fill-rule:%s;",escaped_token);
+ escaped_token=DestroyString(escaped_token);
(void) WriteBlobString(image,message);
break;
}
if (LocaleCompare("fill-opacity",keyword) == 0)
{
(void) GetNextToken(q,&q,extent,token);
+ escaped_token=EscapeSVGAttributeValue(token);
(void) FormatLocaleString(message,MagickPathExtent,
- "fill-opacity:%s;",token);
+ "fill-opacity:%s;",escaped_token);
+ escaped_token=DestroyString(escaped_token);
(void) WriteBlobString(image,message);
break;
}
if (LocaleCompare("font-family",keyword) == 0)
{
(void) GetNextToken(q,&q,extent,token);
+ escaped_token=EscapeSVGAttributeValue(token);
(void) FormatLocaleString(message,MagickPathExtent,
- "font-family:%s;",token);
+ "font-family:%s;",escaped_token);
+ escaped_token=DestroyString(escaped_token);
(void) WriteBlobString(image,message);
break;
}
if (LocaleCompare("font-stretch",keyword) == 0)
{
(void) GetNextToken(q,&q,extent,token);
+ escaped_token=EscapeSVGAttributeValue(token);
(void) FormatLocaleString(message,MagickPathExtent,
- "font-stretch:%s;",token);
+ "font-stretch:%s;",escaped_token);
+ escaped_token=DestroyString(escaped_token);
(void) WriteBlobString(image,message);
break;
}
if (LocaleCompare("font-style",keyword) == 0)
{
(void) GetNextToken(q,&q,extent,token);
+ escaped_token=EscapeSVGAttributeValue(token);
(void) FormatLocaleString(message,MagickPathExtent,
- "font-style:%s;",token);
+ "font-style:%s;",escaped_token);
+ escaped_token=DestroyString(escaped_token);
(void) WriteBlobString(image,message);
break;
}
if (LocaleCompare("font-size",keyword) == 0)
{
(void) GetNextToken(q,&q,extent,token);
+ escaped_token=EscapeSVGAttributeValue(token);
(void) FormatLocaleString(message,MagickPathExtent,
- "font-size:%s;",token);
+ "font-size:%s;",escaped_token);
+ escaped_token=DestroyString(escaped_token);
(void) WriteBlobString(image,message);
break;
}
if (LocaleCompare("font-weight",keyword) == 0)
{
(void) GetNextToken(q,&q,extent,token);
+ escaped_token=EscapeSVGAttributeValue(token);
(void) FormatLocaleString(message,MagickPathExtent,
- "font-weight:%s;",token);
+ "font-weight:%s;",escaped_token);
+ escaped_token=DestroyString(escaped_token);
(void) WriteBlobString(image,message);
break;
}
@@ -4118,16 +4209,20 @@ static MagickBooleanType WriteSVGImage(const ImageInfo *image_info,Image *image,
if (LocaleCompare("text-align",keyword) == 0)
{
(void) GetNextToken(q,&q,extent,token);
+ escaped_token=EscapeSVGAttributeValue(token);
(void) FormatLocaleString(message,MagickPathExtent,
- "text-align %s ",token);
+ "text-align %s ",escaped_token);
+ escaped_token=DestroyString(escaped_token);
(void) WriteBlobString(image,message);
break;
}
if (LocaleCompare("text-anchor",keyword) == 0)
{
(void) GetNextToken(q,&q,extent,token);
+ escaped_token=EscapeSVGAttributeValue(token);
(void) FormatLocaleString(message,MagickPathExtent,
- "text-anchor %s ",token);
+ "text-anchor %s ",escaped_token);
+ escaped_token=DestroyString(escaped_token);
(void) WriteBlobString(image,message);
break;
}
@@ -4152,8 +4247,10 @@ static MagickBooleanType WriteSVGImage(const ImageInfo *image_info,Image *image,
if (LocaleCompare("kerning",keyword) == 0)
{
(void) GetNextToken(q,&q,extent,token);
+ escaped_token=EscapeSVGAttributeValue(token);
(void) FormatLocaleString(message,MagickPathExtent,"kerning:%s;",
- token);
+ escaped_token);
+ escaped_token=DestroyString(escaped_token);
(void) WriteBlobString(image,message);
}
break;
@@ -4164,8 +4261,10 @@ static MagickBooleanType WriteSVGImage(const ImageInfo *image_info,Image *image,
if (LocaleCompare("letter-spacing",keyword) == 0)
{
(void) GetNextToken(q,&q,extent,token);
+ escaped_token=EscapeSVGAttributeValue(token);
(void) FormatLocaleString(message,MagickPathExtent,
- "letter-spacing:%s;",token);
+ "letter-spacing:%s;",escaped_token);
+ escaped_token=DestroyString(escaped_token);
(void) WriteBlobString(image,message);
break;
}
@@ -4183,8 +4282,10 @@ static MagickBooleanType WriteSVGImage(const ImageInfo *image_info,Image *image,
if (LocaleCompare("opacity",keyword) == 0)
{
(void) GetNextToken(q,&q,extent,token);
+ escaped_token=EscapeSVGAttributeValue(token);
(void) FormatLocaleString(message,MagickPathExtent,"opacity %s ",
- token);
+ escaped_token);
+ escaped_token=DestroyString(escaped_token);
(void) WriteBlobString(image,message);
break;
}
@@ -4241,7 +4342,8 @@ static MagickBooleanType WriteSVGImage(const ImageInfo *image_info,Image *image,
{
token=DestroyString(token);
if (primitive_info != (PrimitiveInfo *) NULL)
- primitive_info=(PrimitiveInfo *) RelinquishMagickMemory(primitive_info);
+ primitive_info=(PrimitiveInfo *)
+ RelinquishMagickMemory(primitive_info);
ThrowWriterException(DrawError,
"UnbalancedGraphicContextPushPop");
}
@@ -4271,8 +4373,10 @@ static MagickBooleanType WriteSVGImage(const ImageInfo *image_info,Image *image,
if (LocaleCompare("clip-path",token) == 0)
{
(void) GetNextToken(q,&q,extent,token);
+ escaped_token=EscapeSVGAttributeValue(token);
(void) FormatLocaleString(message,MagickPathExtent,
- "<clipPath id=\"%s\">\n",token);
+ "<clipPath id=\"%s\">\n",escaped_token);
+ escaped_token=DestroyString(escaped_token);
(void) WriteBlobString(image,message);
break;
}
@@ -4335,7 +4439,8 @@ static MagickBooleanType WriteSVGImage(const ImageInfo *image_info,Image *image,
{
token=DestroyString(token);
if (primitive_info != (PrimitiveInfo *) NULL)
- primitive_info=(PrimitiveInfo *) RelinquishMagickMemory(primitive_info);
+ primitive_info=(PrimitiveInfo *)
+ RelinquishMagickMemory(primitive_info);
ThrowWriterException(DrawError,
"VectorGraphicsNestedTooDeeply");
}
@@ -4399,8 +4504,10 @@ static MagickBooleanType WriteSVGImage(const ImageInfo *image_info,Image *image,
if (LocaleCompare("rotate",keyword) == 0)
{
(void) GetNextToken(q,&q,extent,token);
+ escaped_token=EscapeSVGAttributeValue(token);
(void) FormatLocaleString(message,MagickPathExtent,"rotate(%s) ",
- token);
+ escaped_token);
+ escaped_token=DestroyString(escaped_token);
(void) WriteBlobString(image,message);
break;
}
@@ -4423,16 +4530,20 @@ static MagickBooleanType WriteSVGImage(const ImageInfo *image_info,Image *image,
if (LocaleCompare("skewX",keyword) == 0)
{
(void) GetNextToken(q,&q,extent,token);
+ escaped_token=EscapeSVGAttributeValue(token);
(void) FormatLocaleString(message,MagickPathExtent,"skewX(%s) ",
- token);
+ escaped_token);
+ escaped_token=DestroyString(escaped_token);
(void) WriteBlobString(image,message);
break;
}
if (LocaleCompare("skewY",keyword) == 0)
{
(void) GetNextToken(q,&q,extent,token);
+ escaped_token=EscapeSVGAttributeValue(token);
(void) FormatLocaleString(message,MagickPathExtent,"skewY(%s) ",
- token);
+ escaped_token);
+ escaped_token=DestroyString(escaped_token);
(void) WriteBlobString(image,message);
break;
}
@@ -4444,24 +4555,31 @@ static MagickBooleanType WriteSVGImage(const ImageInfo *image_info,Image *image,
(void) GetNextToken(q,&q,extent,token);
(void) CopyMagickString(color,token,MagickPathExtent);
(void) GetNextToken(q,&q,extent,token);
+ escaped_token=EscapeSVGAttributeValue(token);
(void) FormatLocaleString(message,MagickPathExtent,
- " <stop offset=\"%s\" stop-color=\"%s\" />\n",token,color);
+ " <stop offset=\"%s\" stop-color=\"%s\" />\n",escaped_token,
+ color);
+ escaped_token=DestroyString(escaped_token);
(void) WriteBlobString(image,message);
break;
}
if (LocaleCompare("stroke",keyword) == 0)
{
(void) GetNextToken(q,&q,extent,token);
+ escaped_token=EscapeSVGAttributeValue(token);
(void) FormatLocaleString(message,MagickPathExtent,"stroke:%s;",
- token);
+ escaped_token);
+ escaped_token=DestroyString(escaped_token);
(void) WriteBlobString(image,message);
break;
}
if (LocaleCompare("stroke-antialias",keyword) == 0)
{
(void) GetNextToken(q,&q,extent,token);
+ escaped_token=EscapeSVGAttributeValue(token);
(void) FormatLocaleString(message,MagickPathExtent,
- "stroke-antialias:%s;",token);
+ "stroke-antialias:%s;",escaped_token);
+ escaped_token=DestroyString(escaped_token);
(void) WriteBlobString(image,message);
break;
}
@@ -4480,64 +4598,80 @@ static MagickBooleanType WriteSVGImage(const ImageInfo *image_info,Image *image,
for (j=0; j < k; j++)
{
(void) GetNextToken(q,&q,extent,token);
+ escaped_token=EscapeSVGAttributeValue(token);
(void) FormatLocaleString(message,MagickPathExtent,"%s ",
- token);
+ escaped_token);
+ escaped_token=DestroyString(escaped_token);
(void) WriteBlobString(image,message);
}
(void) WriteBlobString(image,";");
break;
}
(void) GetNextToken(q,&q,extent,token);
+ escaped_token=EscapeSVGAttributeValue(token);
(void) FormatLocaleString(message,MagickPathExtent,
- "stroke-dasharray:%s;",token);
+ "stroke-dasharray:%s;",escaped_token);
+ escaped_token=DestroyString(escaped_token);
(void) WriteBlobString(image,message);
break;
}
if (LocaleCompare("stroke-dashoffset",keyword) == 0)
{
(void) GetNextToken(q,&q,extent,token);
+ escaped_token=EscapeSVGAttributeValue(token);
(void) FormatLocaleString(message,MagickPathExtent,
"stroke-dashoffset:%s;",token);
+ escaped_token=DestroyString(escaped_token);
(void) WriteBlobString(image,message);
break;
}
if (LocaleCompare("stroke-linecap",keyword) == 0)
{
(void) GetNextToken(q,&q,extent,token);
+ escaped_token=EscapeSVGAttributeValue(token);
(void) FormatLocaleString(message,MagickPathExtent,
- "stroke-linecap:%s;",token);
+ "stroke-linecap:%s;",escaped_token);
+ escaped_token=DestroyString(escaped_token);
(void) WriteBlobString(image,message);
break;
}
if (LocaleCompare("stroke-linejoin",keyword) == 0)
{
(void) GetNextToken(q,&q,extent,token);
+ escaped_token=EscapeSVGAttributeValue(token);
(void) FormatLocaleString(message,MagickPathExtent,
- "stroke-linejoin:%s;",token);
+ "stroke-linejoin:%s;",escaped_token);
+ escaped_token=DestroyString(escaped_token);
(void) WriteBlobString(image,message);
break;
}
if (LocaleCompare("stroke-miterlimit",keyword) == 0)
{
(void) GetNextToken(q,&q,extent,token);
+ escaped_token=EscapeSVGAttributeValue(token);
(void) FormatLocaleString(message,MagickPathExtent,
- "stroke-miterlimit:%s;",token);
+ "stroke-miterlimit:%s;",escaped_token);
+ escaped_token=DestroyString(escaped_token);
(void) WriteBlobString(image,message);
break;
}
if (LocaleCompare("stroke-opacity",keyword) == 0)
{
(void) GetNextToken(q,&q,extent,token);
+ escaped_token=EscapeSVGAttributeValue(token);
(void) FormatLocaleString(message,MagickPathExtent,
- "stroke-opacity:%s;",token);
+ "stroke-opacity:%s;",escaped_token);
+ escaped_token=DestroyString(escaped_token);
(void) WriteBlobString(image,message);
break;
}
if (LocaleCompare("stroke-width",keyword) == 0)
{
(void) GetNextToken(q,&q,extent,token);
+ escaped_token=EscapeSVGAttributeValue(token);
(void) FormatLocaleString(message,MagickPathExtent,
- "stroke-width:%s;",token);
+ "stroke-width:%s;",escaped_token);
+ escaped_token=DestroyString(escaped_token);
(void) WriteBlobString(image,message);
continue;
}
@@ -4555,8 +4689,10 @@ static MagickBooleanType WriteSVGImage(const ImageInfo *image_info,Image *image,
if (LocaleCompare("text-antialias",keyword) == 0)
{
(void) GetNextToken(q,&q,extent,token);
+ escaped_token=EscapeSVGAttributeValue(token);
(void) FormatLocaleString(message,MagickPathExtent,
- "text-antialias:%s;",token);
+ "text-antialias:%s;",escaped_token);
+ escaped_token=DestroyString(escaped_token);
(void) WriteBlobString(image,message);
break;
}
@@ -4918,11 +5054,13 @@ static MagickBooleanType WriteSVGImage(const ImageInfo *image_info,Image *image,
break;
}
(void) GetNextToken(q,&q,extent,token);
+ escaped_token=EscapeSVGAttributeValue(token);
(void) FormatLocaleString(message,MagickPathExtent,
" <image x=\"%g\" y=\"%g\" width=\"%g\" height=\"%g\" "
"href=\"%s\"/>\n",primitive_info[j].point.x,
primitive_info[j].point.y,primitive_info[j+1].point.x,
- primitive_info[j+1].point.y,token);
+ primitive_info[j+1].point.y,escaped_token);
+ escaped_token=DestroyString(escaped_token);
(void) WriteBlobString(image,message);
break;
}