File ImageMagick-CVE-2025-55298.patch of Package ImageMagick.40311
From 1f93323df9d8c011c31bc4c6880390071f7fb895 Mon Sep 17 00:00:00 2001
From: Cristy <urban-warrior@imagemagick.org>
Date: Sun, 17 Aug 2025 14:16:24 -0400
Subject: [PATCH]
https://github.com/ImageMagick/ImageMagick/security/advisories/GHSA-9ccg-6pjw-x645
---
MagickCore/image.c | 32 ++++++++++++++++++++++++++++++++
1 file changed, 32 insertions(+)
Index: ImageMagick-6.8.8-1/magick/image.c
===================================================================
--- ImageMagick-6.8.8-1.orig/magick/image.c
+++ ImageMagick-6.8.8-1/magick/image.c
@@ -1495,7 +1495,7 @@ MagickExport VirtualPixelMethod GetImage
%
% A description of each parameter follows.
%
-% o image_info: the image info..
+% o image_info: the image info.
%
% o image: the image.
%
@@ -1507,146 +1507,161 @@ MagickExport VirtualPixelMethod GetImage
% o filename: return the formatted filename in this character buffer.
%
*/
-MagickExport size_t InterpretImageFilename(const ImageInfo *image_info,
- Image *image,const char *format,int value,char *filename)
+static inline MagickBooleanType IsValidFormatSpecifier(const char *start,
+ const char *end)
{
char
- *q;
+ specifier = end[-1];
- int
- c;
+ size_t
+ length = end-start;
- MagickBooleanType
- canonical;
+ /*
+ Is this a valid format specifier?
+ */
+ if ((specifier != 'd') && (specifier != 'x') && (specifier != 'o'))
+ return(MagickFalse);
+ if ((length == 1) && (*start == specifier))
+ return(MagickTrue);
+ if (length >= 2)
+ {
+ size_t
+ i = 0;
- register const char
- *p;
+ if (*start == '0')
+ {
+ if ((length >= 3) && (start[1] == '0'))
+ return(MagickFalse);
+ i=1;
+ }
+ for ( ; i < (length-1); i++)
+ if (isdigit((int) ((unsigned char) start[i])) == 0)
+ return(MagickFalse);
+ return(MagickTrue);
+ }
+ return(MagickFalse);
+}
- size_t
- length;
+MagickExport size_t InterpretImageFilename(const ImageInfo *image_info,
+ Image *image,const char *format,int value,char *filename)
+{
+ char
+ *p = filename,
+ pattern[MaxTextExtent];
- canonical=MagickFalse;
- length=0;
- (void) CopyMagickString(filename,format,MaxTextExtent);
- for (p=strchr(format,'%'); p != (char *) NULL; p=strchr(p+1,'%'))
+ const char
+ *cursor = format;
+
+ assert(format != (const char *) NULL);
+ assert(filename != (char *) NULL);
+ if (IsStringTrue(GetImageOption(image_info,"filename:literal")) != MagickFalse)
+ {
+ (void) CopyMagickString(filename,format,MaxTextExtent);
+ return(strlen(filename));
+ }
+ while ((*cursor != '\0') && ((p-filename) < ((ssize_t) MaxTextExtent-1)))
{
- q=(char *) p+1;
- if (*q == '%')
+ const char
+ *specifier_start,
+ *start;
+
+ if (*cursor != '%')
{
- p++;
+ *p++=(*cursor++);
continue;
}
- if (*q == '0')
+ start=cursor++; /* Skip '%' */
+ if (*cursor == '%')
{
- ssize_t
- value;
-
- value=(ssize_t) strtol(q,&q,10);
- (void) value;
+ *p++='%';
+ cursor++;
+ continue;
}
- switch (*q)
- {
- case 'd':
- case 'o':
- case 'x':
+ specifier_start=cursor;
+ while (isdigit((int) ((unsigned char) *cursor)) != 0)
+ cursor++;
+ if ((*cursor == 'd') || (*cursor == 'o') || (*cursor == 'x'))
{
- q++;
- c=(*q);
- *q='\0';
- (void) FormatLocaleString(filename+(p-format),(size_t) (MaxTextExtent-
- (p-format)),p,value);
- *q=c;
- (void) ConcatenateMagickString(filename,q,MaxTextExtent);
- canonical=MagickTrue;
- if (*(q-1) != '%')
- break;
- p++;
- break;
+ const char
+ *specifier_end = cursor+1;
+
+ if (IsValidFormatSpecifier(specifier_start,specifier_end) != MagickFalse)
+ {
+ char
+ format_specifier[MaxTextExtent];
+
+ size_t
+ length = cursor-specifier_start;
+
+ ssize_t
+ count;
+
+ (void) snprintf(format_specifier,sizeof(format_specifier),
+ "%%%.*s%c",(int) length,specifier_start,*cursor);
+ count=FormatLocaleString(pattern,sizeof(pattern),format_specifier,
+ value);
+ if ((count <= 0) || ((p-filename+count) >= MaxTextExtent))
+ return(0);
+ (void) CopyMagickString(p,pattern,MaxTextExtent-(p-filename));
+ p+=strlen(pattern);
+ cursor++;
+ continue;
+ }
+ else
+ {
+ /*
+ Invalid specifier — treat as literal.
+ */
+ cursor=start;
+ *p++=(*cursor++);
+ continue;
+ }
}
- case '[':
+ if (*cursor == '[')
{
- char
- pattern[MaxTextExtent];
-
const char
- *value;
-
- register char
- *r;
+ *end = strchr(cursor,']'),
+ *option = (const char *) NULL;
- register ssize_t
- i;
-
- ssize_t
- depth;
-
- /*
- Image option.
- */
- if (strchr(p,']') == (char *) NULL)
- break;
- depth=1;
- r=q+1;
- for (i=0; (i < (MaxTextExtent-1L)) && (*r != '\0'); i++)
- {
- if (*r == '[')
- depth++;
- if (*r == ']')
- depth--;
- if (depth <= 0)
- break;
- pattern[i]=(*r++);
- }
- pattern[i]='\0';
- if (LocaleNCompare(pattern,"filename:",9) != 0)
- break;
- value=(const char *) NULL;
-#if 0
- /* FUTURE: remove this code. -- Anthony 29 Arpil 2012
- Removed as GetMagickProperty() will will never match a "filename:"
- string as this is not a 'known' image property.
- */
- if ((image_info != (const ImageInfo *) NULL) &&
- (image != (const Image *) NULL))
- value=GetMagickProperty(image_info,image,pattern);
- else
-#endif
- if (image != (Image *) NULL)
- value=GetImageProperty(image,pattern);
- if ((value == (const char *) NULL) &&
- (image != (Image *) NULL))
- value=GetImageArtifact(image,pattern);
- if ((value == (const char *) NULL) &&
+ size_t
+ extent,
+ option_length;
+
+ if (end == (const char *) NULL)
+ continue;
+ extent=(size_t) (end-cursor-1);
+ if (extent >= sizeof(pattern))
+ continue;
+ (void) CopyMagickString(pattern,cursor+1,extent+1);
+ pattern[extent]='\0';
+ if (image != NULL)
+ {
+ option=GetImageProperty(image,pattern);
+ if (option == (const char *) NULL)
+ option=GetImageArtifact(image,pattern);
+ }
+ if ((option == (const char *) NULL) &&
(image_info != (ImageInfo *) NULL))
- value=GetImageOption(image_info,pattern);
- if (value == (const char *) NULL)
- break;
- q--;
- c=(*q);
- *q='\0';
- (void) CopyMagickString(filename+(p-format-length),value,(size_t)
- (MaxTextExtent-(p-format-length)));
- length+=strlen(pattern)-1;
- *q=c;
- (void) ConcatenateMagickString(filename,r+1,MaxTextExtent);
- canonical=MagickTrue;
- if (*(q-1) != '%')
- break;
- p++;
- break;
+ option=GetImageOption(image_info,pattern);
+ if (option == (const char *) NULL)
+ continue;
+ option_length=strlen(option);
+ if ((p-filename+option_length) >= MaxTextExtent)
+ return(0);
+ (void) CopyMagickString(p,option,MaxTextExtent-(p-filename));
+ p+=option_length;
+ cursor=end+1;
+ continue;
}
- default:
- break;
- }
+ /*
+ Invalid or unsupported specifier — treat as literal.
+ */
+ cursor=start;
+ if ((p-filename+1) >= MaxTextExtent)
+ return(0);
+ *p++=(*cursor++);
}
- for (q=filename; *q != '\0'; q++)
- if ((*q == '%') && (*(q+1) == '%'))
- {
- (void) CopyMagickString(q,q+1,(size_t) (MaxTextExtent-(q-filename)));
- canonical=MagickTrue;
- }
- if (canonical == MagickFalse)
- (void) CopyMagickString(filename,format,MaxTextExtent);
+ *p='\0';
return(strlen(filename));
}