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));
 }
 
openSUSE Build Service is sponsored by