File ImageMagick-CVE-2026-25797.patch of Package ImageMagick.42998
From 81129f79ad622ff4c1d729828a34ab0f49ec89f6 Mon Sep 17 00:00:00 2001
From: Dirk Lemstra <dirk@lemstra.org>
Date: Fri, 20 Feb 2026 14:08:15 +0100
Subject: [PATCH] Properly escape the strings that are written as raw html
(GHSA-rw6c-xp26-225v)
---
coders/html.c | 65 ++++++++++++++++++++++++++++++---------------------
1 file changed, 39 insertions(+), 26 deletions(-)
Index: ImageMagick-7.1.0-9/coders/html.c
===================================================================
--- ImageMagick-7.1.0-9.orig/coders/html.c
+++ ImageMagick-7.1.0-9/coders/html.c
@@ -203,6 +203,21 @@ ModuleExport void UnregisterHTMLImage(vo
% o exception: return any errors or warnings in this structure.
%
*/
+static void WriteHtmlEncodedString(Image *image,const char* value)
+{
+ char
+ *encoded_value;
+
+ encoded_value=AcquireString(value);
+ (void) SubstituteString(&encoded_value,"<","<");
+ (void) SubstituteString(&encoded_value,">",">");
+ (void) SubstituteString(&encoded_value,"&","&");
+ (void) SubstituteString(&encoded_value,"\"",""");
+ (void) SubstituteString(&encoded_value,"'","'");
+ WriteBlobString(image,encoded_value);
+ encoded_value=DestroyString(encoded_value);
+}
+
static MagickBooleanType WriteHTMLImage(const ImageInfo *image_info,
Image *image,ExceptionInfo *exception)
{
@@ -301,29 +316,29 @@ static MagickBooleanType WriteHTMLImage(
"\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n");
(void) WriteBlobString(image,"<html>\n");
(void) WriteBlobString(image,"<head>\n");
+ (void) WriteBlobString(image,"<title>");
value=GetImageProperty(image,"label",exception);
if (value != (const char *) NULL)
- (void) FormatLocaleString(buffer,MagickPathExtent,"<title>%s</title>\n",
- value);
+ WriteHtmlEncodedString(image,value);
else
{
GetPathComponent(filename,BasePath,basename);
- (void) FormatLocaleString(buffer,MagickPathExtent,
- "<title>%s</title>\n",basename);
+ WriteHtmlEncodedString(image,basename);
}
- (void) WriteBlobString(image,buffer);
+ (void) WriteBlobString(image,"</title>\n");
(void) WriteBlobString(image,"</head>\n");
(void) WriteBlobString(image,"<body style=\"text-align: center;\">\n");
- (void) FormatLocaleString(buffer,MagickPathExtent,"<h1>%s</h1>\n",
- image->filename);
- (void) WriteBlobString(image,buffer);
+ (void) WriteBlobString(image,"<h1>");
+ WriteHtmlEncodedString(image,image->filename);
+ (void) WriteBlobString(image,"</h1>");
(void) WriteBlobString(image,"<div>\n");
(void) CopyMagickString(filename,image->filename,MagickPathExtent);
AppendImageFormat("png",filename);
- (void) FormatLocaleString(buffer,MagickPathExtent,"<img usemap=\"#%s\" "
- "src=\"%s\" style=\"border: 0;\" alt=\"Image map\" />\n",mapname,
- filename);
- (void) WriteBlobString(image,buffer);
+ (void) WriteBlobString(image,"<img usemap=\"#");
+ WriteHtmlEncodedString(image,mapname);
+ (void) WriteBlobString(image,"\" src=\"");
+ WriteHtmlEncodedString(image,filename);
+ (void) WriteBlobString(image,"\" style=\"border: 0;\" alt=\"Image map\" />\n");
/*
Determine the size and location of each image tile.
*/
@@ -333,18 +348,18 @@ static MagickBooleanType WriteHTMLImage(
/*
Write an image map.
*/
- (void) FormatLocaleString(buffer,MagickPathExtent,
- "<map id=\"%s\" name=\"%s\">\n",mapname,mapname);
- (void) WriteBlobString(image,buffer);
- (void) FormatLocaleString(buffer,MagickPathExtent," <area href=\"%s",
- url);
- (void) WriteBlobString(image,buffer);
+ (void) WriteBlobString(image,"<map id=\"");
+ WriteHtmlEncodedString(image,mapname);
+ (void) WriteBlobString(image,"\" name=\"");
+ WriteHtmlEncodedString(image,mapname);
+ (void) WriteBlobString(image,"\">\n<area href=\"");
+ WriteHtmlEncodedString(image,url);
if (image->directory == (char *) NULL)
{
+ WriteHtmlEncodedString(image,image->filename);
(void) FormatLocaleString(buffer,MagickPathExtent,
- "%s\" shape=\"rect\" coords=\"0,0,%.20g,%.20g\" alt=\"\" />\n",
- image->filename,(double) geometry.width-1,(double) geometry.height-
- 1);
+ "\" shape=\"rect\" coords=\"0,0,%.20g,%.20g\" alt=\"\" />\n",
+ (double) geometry.width-1,(double) geometry.height-1);
(void) WriteBlobString(image,buffer);
}
else
@@ -360,9 +375,9 @@ static MagickBooleanType WriteHTMLImage(
(void) WriteBlobString(image,buffer);
if (*(p+1) != '\0')
{
- (void) FormatLocaleString(buffer,MagickPathExtent,
- " <area href=%s\"",url);
- (void) WriteBlobString(image,buffer);
+ (void) WriteBlobString(image," <area href=\"");
+ WriteHtmlEncodedString(image,url);
+ (void) WriteBlobString(image,"\"");
}
geometry.x+=(ssize_t) geometry.width;
if ((geometry.x+4) >= (ssize_t) image->columns)
@@ -372,7 +387,6 @@ static MagickBooleanType WriteHTMLImage(
}
}
(void) WriteBlobString(image,"</map>\n");
- (void) CopyMagickString(filename,image->filename,MagickPathExtent);
(void) WriteBlobString(image,"</div>\n");
(void) WriteBlobString(image,"</body>\n");
(void) WriteBlobString(image,"</html>\n");
@@ -380,7 +394,6 @@ static MagickBooleanType WriteHTMLImage(
/*
Write the image as PNG.
*/
- (void) CopyMagickString(image->filename,filename,MagickPathExtent);
AppendImageFormat("png",image->filename);
next=GetNextImageInList(image);
image->next=NewImageList();
Index: ImageMagick-7.1.0-9/coders/ps.c
===================================================================
--- ImageMagick-7.1.0-9.orig/coders/ps.c
+++ ImageMagick-7.1.0-9/coders/ps.c
@@ -1072,6 +1072,82 @@ static inline unsigned char *PopHexPixel
return(pixels);
}
+static inline void FilenameToTitle(const char *filename,char *title,
+ const size_t extent)
+{
+ int
+ depth = 0;
+
+ ssize_t
+ i,
+ offset = 0;
+
+ if (extent == 0)
+ return;
+ for (i=0; (filename[i] != '\0') && ((offset+1) < (ssize_t) extent); i++)
+ {
+ unsigned char
+ c = filename[i];
+
+ /*
+ Only allow printable ASCII.
+ */
+ if ((c < 32) || (c > 126))
+ {
+ title[offset++]='_';
+ continue;
+ }
+ /*
+ Percent signs break DSC parsing.
+ */
+ if (c == '%')
+ {
+ title[offset++]='_';
+ continue;
+ }
+ /*
+ Parentheses must remain balanced.
+ */
+ if (c == '(')
+ {
+ depth++;
+ title[offset++] = '(';
+ continue;
+ }
+ if (c == ')')
+ {
+ if (depth <= 0)
+ title[offset++]='_';
+ else
+ {
+ depth--;
+ title[offset++]=')';
+ }
+ continue;
+ }
+ /*
+ Everything else is allowed.
+ */
+ title[offset++]=c;
+ }
+ /*
+ If parentheses remain unbalanced, close them.
+ */
+ while ((depth > 0) && ((offset+1) < (ssize_t) extent)) {
+ title[offset++]=')';
+ depth--;
+ }
+ title[offset]='\0';
+ /*
+ Ensure non-empty result.
+ */
+ if (offset == 0)
+ {
+ (void) CopyMagickString(title,"Untitled",extent-1);
+ title[extent-1]='\0';
+ }
+}
+
static MagickBooleanType WritePSImage(const ImageInfo *image_info,Image *image,
ExceptionInfo *exception)
{
@@ -1538,6 +1614,9 @@ static MagickBooleanType WritePSImage(co
text_size=(size_t) (MultilineCensus(value)*pointsize+12);
if (page == 1)
{
+ char
+ title[MagickPathExtent];
+
/*
Output Postscript header.
*/
@@ -1548,8 +1627,9 @@ static MagickBooleanType WritePSImage(co
MagickPathExtent);
(void) WriteBlobString(image,buffer);
(void) WriteBlobString(image,"%%Creator: (ImageMagick)\n");
+ FilenameToTitle(image->filename,title,MagickPathExtent);
(void) FormatLocaleString(buffer,MagickPathExtent,"%%%%Title: (%s)\n",
- image->filename);
+ title);
(void) WriteBlobString(image,buffer);
timer=GetMagickTime();
(void) FormatMagickTime(timer,sizeof(date),date);
Index: ImageMagick-7.1.0-9/coders/ps2.c
===================================================================
--- ImageMagick-7.1.0-9.orig/coders/ps2.c
+++ ImageMagick-7.1.0-9/coders/ps2.c
@@ -225,6 +225,82 @@ static MagickBooleanType Huffman2DEncode
return(status);
}
+static inline void FilenameToTitle(const char *filename,char *title,
+ const size_t extent)
+{
+ int
+ depth = 0;
+
+ ssize_t
+ i,
+ offset = 0;
+
+ if (extent == 0)
+ return;
+ for (i=0; (filename[i] != '\0') && ((offset+1) < (ssize_t) extent); i++)
+ {
+ unsigned char
+ c = filename[i];
+
+ /*
+ Only allow printable ASCII.
+ */
+ if ((c < 32) || (c > 126))
+ {
+ title[offset++]='_';
+ continue;
+ }
+ /*
+ Percent signs break DSC parsing.
+ */
+ if (c == '%')
+ {
+ title[offset++]='_';
+ continue;
+ }
+ /*
+ Parentheses must remain balanced.
+ */
+ if (c == '(')
+ {
+ depth++;
+ title[offset++] = '(';
+ continue;
+ }
+ if (c == ')')
+ {
+ if (depth <= 0)
+ title[offset++]='_';
+ else
+ {
+ depth--;
+ title[offset++]=')';
+ }
+ continue;
+ }
+ /*
+ Everything else is allowed.
+ */
+ title[offset++]=c;
+ }
+ /*
+ If parentheses remain unbalanced, close them.
+ */
+ while ((depth > 0) && ((offset+1) < (ssize_t) extent)) {
+ title[offset++]=')';
+ depth--;
+ }
+ title[offset]='\0';
+ /*
+ Ensure non-empty result.
+ */
+ if (offset == 0)
+ {
+ (void) CopyMagickString(title,"Untitled",extent-1);
+ title[extent-1]='\0';
+ }
+}
+
static MagickBooleanType WritePS2Image(const ImageInfo *image_info,Image *image,
ExceptionInfo *exception)
{
@@ -557,6 +633,9 @@ static MagickBooleanType WritePS2Image(c
text_size=(size_t) (MultilineCensus(value)*pointsize+12);
if (page == 1)
{
+ char
+ title[MagickPathExtent];
+
/*
Output Postscript header.
*/
@@ -567,8 +646,9 @@ static MagickBooleanType WritePS2Image(c
MagickPathExtent);
(void) WriteBlobString(image,buffer);
(void) WriteBlobString(image,"%%Creator: (ImageMagick)\n");
+ FilenameToTitle(image->filename,title,MagickPathExtent);
(void) FormatLocaleString(buffer,MagickPathExtent,"%%%%Title: (%s)\n",
- image->filename);
+ title);
(void) WriteBlobString(image,buffer);
timer=GetMagickTime();
(void) FormatMagickTime(timer,sizeof(date),date);
Index: ImageMagick-7.1.0-9/coders/ps3.c
===================================================================
--- ImageMagick-7.1.0-9.orig/coders/ps3.c
+++ ImageMagick-7.1.0-9/coders/ps3.c
@@ -203,6 +203,82 @@ ModuleExport void UnregisterPS3Image(voi
%
*/
+static inline void FilenameToTitle(const char *filename,char *title,
+ const size_t extent)
+{
+ int
+ depth = 0;
+
+ ssize_t
+ i,
+ offset = 0;
+
+ if (extent == 0)
+ return;
+ for (i=0; (filename[i] != '\0') && ((offset+1) < (ssize_t) extent); i++)
+ {
+ unsigned char
+ c = filename[i];
+
+ /*
+ Only allow printable ASCII.
+ */
+ if ((c < 32) || (c > 126))
+ {
+ title[offset++]='_';
+ continue;
+ }
+ /*
+ Percent signs break DSC parsing.
+ */
+ if (c == '%')
+ {
+ title[offset++]='_';
+ continue;
+ }
+ /*
+ Parentheses must remain balanced.
+ */
+ if (c == '(')
+ {
+ depth++;
+ title[offset++] = '(';
+ continue;
+ }
+ if (c == ')')
+ {
+ if (depth <= 0)
+ title[offset++]='_';
+ else
+ {
+ depth--;
+ title[offset++]=')';
+ }
+ continue;
+ }
+ /*
+ Everything else is allowed.
+ */
+ title[offset++]=c;
+ }
+ /*
+ If parentheses remain unbalanced, close them.
+ */
+ while ((depth > 0) && ((offset+1) < (ssize_t) extent)) {
+ title[offset++]=')';
+ depth--;
+ }
+ title[offset]='\0';
+ /*
+ Ensure non-empty result.
+ */
+ if (offset == 0)
+ {
+ (void) CopyMagickString(title,"Untitled",extent-1);
+ title[extent-1]='\0';
+ }
+}
+
static MagickBooleanType Huffman2DEncodeImage(const ImageInfo *image_info,
Image *image,Image *inject_image,ExceptionInfo *exception)
{
@@ -1006,6 +1082,9 @@ static MagickBooleanType WritePS3Image(c
type=IdentifyImageCoderType(image,exception);
if (page == 1)
{
+ char
+ title[MagickPathExtent];
+
/*
Postscript header on the first page.
*/
@@ -1018,8 +1097,9 @@ static MagickBooleanType WritePS3Image(c
(void) FormatLocaleString(buffer,MagickPathExtent,
"%%%%Creator: ImageMagick %s\n",MagickLibVersionText);
(void) WriteBlobString(image,buffer);
+ FilenameToTitle(image->filename,title,MagickPathExtent);
(void) FormatLocaleString(buffer,MagickPathExtent,"%%%%Title: %s\n",
- image->filename);
+ title);
(void) WriteBlobString(image,buffer);
timer=GetMagickTime();
(void) FormatMagickTime(timer,sizeof(date),date);