File ImageMagick-CVE-2025-55298.patch of Package ImageMagick.40619

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-7.0.7-34/MagickCore/image.c
===================================================================
--- ImageMagick-7.0.7-34.orig/MagickCore/image.c
+++ ImageMagick-7.0.7-34/MagickCore/image.c
@@ -1608,7 +1608,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.
 %
@@ -1622,135 +1622,166 @@ MagickExport VirtualPixelMethod GetImage
 %    o exception: return any errors or warnings in this structure.
 %
 */
-MagickExport size_t InterpretImageFilename(const ImageInfo *image_info,
-  Image *image,const char *format,int value,char *filename,
-  ExceptionInfo *exception)
+
+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;
+
+      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);
+}
 
-  register const char
-    *p;
+MagickExport size_t InterpretImageFilename(const ImageInfo *image_info,
+  Image *image,const char *format,int value,char *filename,
+  ExceptionInfo *exception)
+{
+  char
+    *p = filename,
+    pattern[MagickPathExtent];
 
-  ssize_t
-    field_width,
-    offset;
+  const char
+    *cursor = format;
 
-  canonical=MagickFalse;
-  offset=0;
-  (void) CopyMagickString(filename,format,MagickPathExtent);
-  for (p=strchr(format,'%'); p != (char *) NULL; p=strchr(p+1,'%'))
+  assert(format != (const char *) NULL);
+  assert(filename != (char *) NULL);
+  if (IsStringTrue(GetImageOption(image_info,"filename:literal")) != MagickFalse)
+    {
+      (void) CopyMagickString(filename,format,MagickPathExtent);
+      return(strlen(filename));
+    }
+  while ((*cursor != '\0') && ((p-filename) < ((ssize_t) MagickPathExtent-1)))
   {
-    q=(char *) p+1;
-    if (*q == '%')
+    const char
+      *specifier_start,
+      *start;
+
+    if (*cursor != '%')
       {
-        p=q+1;
+        *p++=(*cursor++);
         continue;
       }
-    field_width=0;
-    if (*q == '0')
-      field_width=(ssize_t) strtol(q,&q,10);
-    switch (*q)
-    {
-      case 'd':
-      case 'o':
-      case 'x':
+    start=cursor++;  /* Skip '%' */
+    if (*cursor == '%')
       {
-        q++;
-        c=(*q);
-        *q='\0';
-        (void) FormatLocaleString(filename+(p-format-offset),(size_t)
-          (MagickPathExtent-(p-format-offset)),p,value);
-        offset+=(4-field_width);
-        *q=c;
-        (void) ConcatenateMagickString(filename,q,MagickPathExtent);
-        canonical=MagickTrue;
-        if (*(q-1) != '%')
-          break;
-        p++;
-        break;
+        *p++='%';
+        cursor++;
+        continue;
       }
-      case '[':
+    specifier_start=cursor;
+    while (isdigit((int) ((unsigned char) *cursor)) != 0)
+      cursor++;
+    if ((*cursor == 'd') || (*cursor == 'o') || (*cursor == 'x'))
       {
-        char
-          pattern[MagickPathExtent];
-
         const char
-          *option;
-
-        register char
-          *r;
+          *specifier_end = cursor+1;
 
-        register ssize_t
-          i;
+        if (IsValidFormatSpecifier(specifier_start,specifier_end) != MagickFalse)
+         {
+            char
+              format_specifier[MagickPathExtent];
+
+            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) >= MagickPathExtent))
+              return(0);
+            (void) CopyMagickString(p,pattern,MagickPathExtent-(p-filename));
+            p+=strlen(pattern);
+            cursor++;
+            continue;
+          }
+        else
+          {
+            /*
+              Invalid specifier — treat as literal.
+            */
+            cursor=start;
+            *p++=(*cursor++);
+            continue;
+          }
+      }
+    if (*cursor == '[')
+      {
+        const char
+          *end = strchr(cursor,']'),
+          *option = (const char *) NULL;
 
-        ssize_t
-          depth;
-
-        /*
-          Image option.
-        */
-        if (strchr(p,']') == (char *) NULL)
-          break;
-        depth=1;
-        r=q+1;
-        for (i=0; (i < (MagickPathExtent-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;
-        option=(const char *) NULL;
-        if (image != (Image *) NULL)
-          option=GetImageProperty(image,pattern,exception);
-        if ((option == (const char *) NULL) && (image != (Image *) NULL))
-          option=GetImageArtifact(image,pattern);
+        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,exception);
+            if (option == (const char *) NULL)
+              option=GetImageArtifact(image,pattern);
+          }
         if ((option == (const char *) NULL) &&
             (image_info != (ImageInfo *) NULL))
           option=GetImageOption(image_info,pattern);
         if (option == (const char *) NULL)
-          break;
-        q--;
-        c=(*q);
-        *q='\0';
-        (void) CopyMagickString(filename+(p-format-offset),option,(size_t)
-          (MagickPathExtent-(p-format-offset)));
-        offset+=strlen(pattern)-4;
-        *q=c;
-        (void) ConcatenateMagickString(filename,r+1,MagickPathExtent);
-        canonical=MagickTrue;
-        if (*(q-1) != '%')
-          break;
-        p++;
-        break;
+          continue;
+        option_length=strlen(option);
+        if ((p-filename+option_length) >= MagickPathExtent)
+          return(0);
+        (void) CopyMagickString(p,option,MagickPathExtent-(p-filename));
+        p+=option_length;
+        cursor=end+1;
+        continue;
       }
-      default:
-        break;
-    }
+    /*
+      Invalid or unsupported specifier — treat as literal.
+    */
+    cursor=start;
+    if ((p-filename+1) >= MagickPathExtent)
+      return(0);
+    *p++=(*cursor++);
   }
-  for (q=filename; *q != '\0'; q++)
-    if ((*q == '%') && (*(q+1) == '%'))
-      {
-        (void) CopyMagickString(q,q+1,(size_t) (MagickPathExtent-(q-filename)));
-        canonical=MagickTrue;
-      }
-  if (canonical == MagickFalse)
-    (void) CopyMagickString(filename,format,MagickPathExtent);
+  *p='\0';
   return(strlen(filename));
 }
+
 
 /*
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
openSUSE Build Service is sponsored by