On Thu, Jan 05, 2006 at 02:04:39PM +0100, Florian Weimer wrote: > A better fix would be to bypass the shell and invoke the delegate > directly (using fork and execve). If this is not feasible, the file > name should be translated according to this pseudo-code:
I went for an even more simple fix: pass a temporary, securely named symlink to external delegates, instead of the user-supplied filename. We get rid of the problem this way without any restrictions on allowed characters in filenames. There's still the problem of information disclosure because the symlink in /tmp displays the full path to the image file, but I think that's less severe than the original problem. Furthermore, users can easily circumvent it setting MAGICK_TMPDIR to a 700 directory. Unfortunately, even though the hack should be good enough for Debian, it is not suitable for upstream because of portability issues. > Please pass this message to upstream nevertheless (I couldn't find a > security contact on their web pages). Assuming you were referring to me, I'm currently too short on time to act as an intermediary for problems in packages I'm not even the maintainer of. Therefore, I'd be grateful if someone else stepped in and worked with upstream to settle on a long-term solution. I'm not aware of a specific security contact, but a message to one of their web forums usually gets fast attention. Regards, Daniel.
diff -u imagemagick-6.2.4.5/magick/blob.c imagemagick-6.2.4.5/magick/blob.c --- imagemagick-6.2.4.5/magick/blob.c +++ imagemagick-6.2.4.5/magick/blob.c @@ -2120,25 +2120,8 @@ /* Form filename for multi-part images. */ - (void) CopyMagickString(filename,image->filename,MaxTextExtent); - for (p=strchr(filename,'%'); p != (char *) NULL; p=strchr(p+1,'%')) - { - char - *q; - - q=p+1; - if (*q == '0') - (void) strtol(q,&q,10); - if ((*q == '%') || (*q == 'd') || (*q == 'o') || (*q == 'x')) - { - char - format[MaxTextExtent]; - - (void) CopyMagickString(format,p,MaxTextExtent); - (void) FormatMagickString(p,MaxTextExtent,format,image->scene); - break; - } - } + (void) FormatMagickStringNumeric(filename,MaxTextExtent,image->filename, + image->scene); if (image_info->adjoin == MagickFalse) if ((image->previous != (Image *) NULL) || (GetNextImageInList(image) != (Image *) NULL)) diff -u imagemagick-6.2.4.5/debian/rules imagemagick-6.2.4.5/debian/rules --- imagemagick-6.2.4.5/debian/rules +++ imagemagick-6.2.4.5/debian/rules @@ -24,7 +24,7 @@ --prefix=/usr \ --mandir=\$${prefix}/share/man \ --infodir=\$${prefix}/share/info \ - --with-gs-font-dir=/usr/share/fonts/type1/gsfonts\ + --with-gs-font-dir=/usr/share/fonts/type1/gsfonts \ --with-magick-plus-plus \ --enable-shared \ --enable-lzw \ diff -u imagemagick-6.2.4.5/debian/changelog imagemagick-6.2.4.5/debian/changelog --- imagemagick-6.2.4.5/debian/changelog +++ imagemagick-6.2.4.5/debian/changelog @@ -1,3 +1,29 @@ +imagemagick (6:6.2.4.5-0.6) unstable; urgency=high + + * Non-maintainer upload. + * magick/display.c: In DisplayImageCommand(), expand command line before + allocating ressources based on argc. Patch and analysis thanks to + Eero Häkkinen. Closes: #345595 + * magick/{animate.c,blob.c,display.c,image.c,log.c,montage.c,string.c, + string_.h}: Implement new utility function FormatMagickStringNumeric() + to securely expand a user-supplied format string with a single numeric + argument. Adjust code to use this function where appropriate. + (CVE-2006-0082) Closes: #345876 + * coders/pdf.c,coders/ps.c,magick/delegate.c,magick/delegate.h, + magick/methods.h: Do not call external delegates with user-supplied + filename, but with securely named symlinks only to prevent shell command + injection (CVE-2005-4601). Closes: #345238 + * debian/rules: Make sure to include trailing spaces in multi-line + commands to keep recent make happy. Cures problems with ghostscript + font path. Fix thanks to Jeff Lessem. Closes: #347486 + * debian/imagemagick.mime: Rather than autodetect the type of an image, + derive it from the mime type. As a side effect, this change allows to + use arbitrary filenames with the 'see' command, even if they have + special meaning to imagemagick internally. Also clean up some typos + and superfluous entries once we're at it. Closes: #344997 + + -- Daniel Kobras <[EMAIL PROTECTED]> Tue, 17 Jan 2006 18:33:58 +0100 + imagemagick (6:6.2.4.5-0.5) unstable; urgency=low * Another NMU to complete the installability fixes from 6:6.2.4.5-0.4. diff -u imagemagick-6.2.4.5/debian/imagemagick.mime imagemagick-6.2.4.5/debian/imagemagick.mime --- imagemagick-6.2.4.5/debian/imagemagick.mime +++ imagemagick-6.2.4.5/debian/imagemagick.mime @@ -1,45 +1,42 @@ -image/avs; display '%s'; test=test -n "$DISPLAY" -image/bie; display '%s'; test=test -n "$DISPLAY" -image/x-ms-bmp; display '%s'; test=test -n "$DISPLAY" -image/cmyk; display '%s'; test=test -n "$DISPLAY" -image/dcx; display '%s'; test=test -n "$DISPLAY" -image/eps; display '%s'; test=test -n "$DISPLAY" -image/fax; display '%s'; test=test -n "$DISPLAY" -image/fits; display '%s'; test=test -n "$DISPLAY" -image/gif; display '%s'; test=test -n "$DISPLAY" -image/gray; display '%s'; test=test -n "$DISPLAY" -image/gradation; display '%s'; test=test -n "$DISPLAY" -image/hdf; display '%s'; test=test -n "$DISPLAY" -image/jpeg; display '%s'; test=test -n "$DISPLAY" -image/pjpeg; display '%s'; test=test -n "$DISPLAY" -image/map; display '%s'; test=test -n "$DISPLAY" -image/miff; display '%s'; test=test -n "$DISPLAY" -image/mono; display '%s'; test=test -n "$DISPLAY" -image/mtv; display '%s'; test=test -n "$DISPLAY" -image/x-portable-bitmap; display '%s'; test=test -n "$DISPLAY" -image/pcd; display '%s'; test=test -n "$DISPLAY" -image/pcx; display '%s'; test=test -n "$DISPLAY" -image/pdf; display '%s'; test=test -n "$DISPLAY" -image/x-portable-graymap; display '%s'; test=test -n "$DISPLAY" -image/pict; display '%s'; test=test -n "$DISPLAY" -image/png; display '%s'; test=test -n "$DISPLAY" -image/x-portable-anymap; display '%s'; test=test -n "$DISPLAY" -image/x-portable-pixmap; display '%s'; test=test -n "$DISPLAY" -image/ps; display '%s'; test=test -n "$DISPLAY" -image/rad; display '%s'; test=test -n "$DISPLAY" -image/x-rgb; display '%s'; test=test -n "$DISPLAY" -image/rgba; display '%s'; test=test -n "$DISPLAY" -image/rla; display '%s'; test=test -n "$DISPLAY" -image/rle; display '%s'; test=test -n "$DISPLAY" -image/sgi; display '%s'; test=test -n "$DISPLAY" -image/sun-raster; display '%s'; test=test -n "$DISPLAY" -image/targa; display '%s'; test=test -n "$DISPLAY" -image/tiff; display '%s'; test=test -n "$DISPLAY" -image/uyvu; display '%s'; test=test -n "$DISPLAY" -image/vid; display '%s'; test=test -n "$DISPLAY" -image/viff; display '%s'; test=test -n "$DISPLAY" -image/x-xbitmap; display '%s'; test=test -n "$DISPLAY" -image/x-xpixmap; display '%s'; test=test -n "$DISPLAY" -image/x-xwindowdump; display '%s'; test=test -n "$DISPLAY" -image/x-icon; display '%s'; test=test -n "$DISPLAY" -image/yuv; display '%s'; test=test -n "$DISPLAY" +image/avs; display 'avs:%s'; test=test -n "$DISPLAY" +image/bie; display 'jbig:%s'; test=test -n "$DISPLAY" +image/x-ms-bmp; display 'bmp:%s'; test=test -n "$DISPLAY" +image/cmyk; display 'cmyk:%s'; test=test -n "$DISPLAY" +image/dcx; display 'dcx:%s'; test=test -n "$DISPLAY" +image/eps; display 'eps:%s'; test=test -n "$DISPLAY" +image/fax; display 'fax:%s'; test=test -n "$DISPLAY" +image/fits; display 'fits:%s'; test=test -n "$DISPLAY" +image/gif; display 'gif:%s'; test=test -n "$DISPLAY" +image/gray; display 'gray:%s'; test=test -n "$DISPLAY" +image/jpeg; display 'jpeg:%s'; test=test -n "$DISPLAY" +image/pjpeg; display 'jpeg:%s'; test=test -n "$DISPLAY" +image/miff; display 'miff:%s'; test=test -n "$DISPLAY" +image/mono; display 'mono:%s'; test=test -n "$DISPLAY" +image/mtv; display 'mtv:%s'; test=test -n "$DISPLAY" +image/x-portable-bitmap; display 'pbm:%s'; test=test -n "$DISPLAY" +image/pcd; display 'pcd:%s'; test=test -n "$DISPLAY" +image/pcx; display 'pcx:%s'; test=test -n "$DISPLAY" +image/pdf; display 'pdf:%s'; test=test -n "$DISPLAY" +image/x-portable-graymap; display 'pgm:%s'; test=test -n "$DISPLAY" +image/pict; display 'pict:%s'; test=test -n "$DISPLAY" +image/png; display 'png:%s'; test=test -n "$DISPLAY" +image/x-portable-anymap; display 'pnm:%s'; test=test -n "$DISPLAY" +image/x-portable-pixmap; display 'ppm:%s'; test=test -n "$DISPLAY" +image/ps; display 'ps:%s'; test=test -n "$DISPLAY" +image/rad; display 'rad:%s'; test=test -n "$DISPLAY" +image/x-rgb; display 'rgb:%s'; test=test -n "$DISPLAY" +image/rgba; display 'rgba:%s'; test=test -n "$DISPLAY" +image/rla; display 'rla:%s'; test=test -n "$DISPLAY" +image/rle; display 'rle:%s'; test=test -n "$DISPLAY" +image/sgi; display 'sgi:%s'; test=test -n "$DISPLAY" +image/sun-raster; display 'sun:%s'; test=test -n "$DISPLAY" +image/targa; display 'tga:%s'; test=test -n "$DISPLAY" +image/tiff; display 'tiff:%s'; test=test -n "$DISPLAY" +image/uyvy; display 'uyvy:%s'; test=test -n "$DISPLAY" +image/vid; display 'vid:%s'; test=test -n "$DISPLAY" +image/viff; display 'viff:%s'; test=test -n "$DISPLAY" +image/x-xbitmap; display 'xbm:%s'; test=test -n "$DISPLAY" +image/x-xpixmap; display 'xpm:%s'; test=test -n "$DISPLAY" +image/x-xwindowdump; display 'xwd:%s'; test=test -n "$DISPLAY" +image/x-icon; display 'icon:%s'; test=test -n "$DISPLAY" +image/yuv; display 'yuv:%s'; test=test -n "$DISPLAY" only in patch2: unchanged: --- imagemagick-6.2.4.5.orig/coders/pdf.c +++ imagemagick-6.2.4.5/coders/pdf.c @@ -356,6 +356,16 @@ " -sPDFPassword=%s",read_info->authenticate); (void) CopyMagickString(filename,read_info->filename,MaxTextExtent); (void) AcquireUniqueFilename(read_info->filename); + if (AcquireTemporarySymlink((char *) image_info->filename,filename) + == MagickFalse) + { + (void) RelinquishUniqueFileResource(postscript_filename); + (void) RelinquishUniqueFileResource(read_info->filename); + (void) DestroyImageInfo(read_info); + ThrowFileException(exception,FileOpenError,"UnableToCreateTemporaryFile", + image_info->filename); + return((Image *) NULL); + } (void) FormatMagickString(command,MaxTextExtent, GetDelegateCommands(delegate_info), read_info->antialias != MagickFalse ? 4 : 1, @@ -363,6 +373,8 @@ read_info->filename,postscript_filename,image_info->filename); status=InvokePostscriptDelegate(read_info->verbose,command); image=ReadImage(read_info,exception); + unlink(image_info->filename); + (void) CopyMagickString((char *) image_info->filename,filename,MaxTextExtent); (void) RelinquishUniqueFileResource(postscript_filename); (void) RelinquishUniqueFileResource(read_info->filename); read_info=DestroyImageInfo(read_info); only in patch2: unchanged: --- imagemagick-6.2.4.5.orig/coders/ps.c +++ imagemagick-6.2.4.5/coders/ps.c @@ -479,6 +479,16 @@ } (void) CopyMagickString(filename,read_info->filename,MaxTextExtent); (void) AcquireUniqueFilename(read_info->filename); + if (AcquireTemporarySymlink((char *) image_info->filename,filename) + == MagickFalse) + { + (void) RelinquishUniqueFileResource(postscript_filename); + (void) RelinquishUniqueFileResource(read_info->filename); + (void) DestroyImageInfo(read_info); + ThrowFileException(&image->exception,FileOpenError, + "UnableToCreateTemporaryFile",image_info->filename); + return((Image *) NULL); + } (void) FormatMagickString(command,MaxTextExtent, GetDelegateCommands(delegate_info), read_info->antialias != MagickFalse ? 4 : 1, @@ -495,6 +505,8 @@ } (void) RelinquishUniqueFileResource(postscript_filename); (void) RelinquishUniqueFileResource(read_info->filename); + unlink(image_info->filename); + (void) CopyMagickString((char *) image_info->filename,filename,MaxTextExtent); if (image == (Image *) NULL) { /* only in patch2: unchanged: --- imagemagick-6.2.4.5.orig/magick/animate.c +++ imagemagick-6.2.4.5/magick/animate.c @@ -604,7 +604,7 @@ /* Form filename for multi-part images. */ - (void) FormatMagickString(filename,MaxTextExtent, + (void) FormatMagickStringNumeric(filename,MaxTextExtent, image_info->filename,scene); if (LocaleCompare(filename,image_info->filename) == 0) (void) FormatMagickString(filename,MaxTextExtent,"%s[%lu]", only in patch2: unchanged: --- imagemagick-6.2.4.5.orig/magick/delegate.c +++ imagemagick-6.2.4.5/magick/delegate.c @@ -673,6 +673,72 @@ % % % % % % ++ A c q u i r e T e m p o r a r y S y m l i n k % +% % +% % +% % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% AcquireTemporarySymlink replaces the contents of the string buffer pointed +% to by filename with the unique name of a symbolic link. True is returned +% if a symlink waas created, or False is returned if there is a failure. +% The allocated symlink should be recovered via the LiberateTemporaryFile() +% function once it is no longer required. +% +% The format of the AcquireTemporarySymlink method is: +% +% unsigned int AcquireTemporarySymlink(char *linkname, const char *name) +% +% A description of each parameter follows. +% +% o linkname: Specifies a pointer to an array of characters that must be +% MaxTextExtent characters of size. The unique +% name of the symlink is returned in this array. +% o name: Specifies a file name the symlink should point to. +*/ +MagickExport unsigned int AcquireTemporarySymlink(char *linkname, const char *name) +{ + char + *tempname; + + int + fd, + tries; + + assert(linkname != (char *)NULL); + linkname[0]='\0'; + linkname[MaxTextExtent-1]='\0'; + + for (tries=0; tries < 15; tries++) + { + tempname=tempnam(getenv("MAGICK_TMPDIR"),"magick-"); + strncpy(linkname,tempname,MaxTextExtent-1); + free(tempname); + if (*name == '/') + fd=symlink(name, linkname); + else + { + char cname[MaxTextExtent]; + if (!getcwd(cname,(size_t)MaxTextExtent)) + return (MagickFalse); + strncat(cname,"/",MaxTextExtent-1); + strncat(cname,name,MaxTextExtent-1); + fd=symlink(cname,linkname); + } + if (fd != -1) + { + close(fd); + return (MagickTrue); + } + } + return (MagickFalse); +} + +/* +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% % +% % +% % % I n v o k e D e l e g a t e % % % % % @@ -704,8 +770,11 @@ char *command, **commands, + linkedname[MaxTextExtent], + linkedinfoname[MaxTextExtent], filename[MaxTextExtent]; + const DelegateInfo *delegate_info; @@ -725,20 +794,40 @@ assert(image->signature == MagickSignature); if (image->debug != MagickFalse) (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); + linkedname[0]='\0'; + linkedinfoname[0]='\0'; temporary=(MagickBooleanType) (*image->filename == '\0'); if (temporary != MagickFalse) - if (AcquireUniqueFilename(image->filename) == MagickFalse) - { - ThrowFileException(exception,FileOpenError, - "UnableToCreateTemporaryFile",image->filename); - return(MagickFalse); - } + { + if (AcquireUniqueFilename(image->filename) == MagickFalse) + { + ThrowFileException(exception,FileOpenError, + "UnableToCreateTemporaryFile",image->filename); + return(MagickFalse); + } + } + else + { + (void) CopyMagickString(linkedname,image->filename,MaxTextExtent); + if (AcquireTemporarySymlink(image->filename,linkedname) == MagickFalse) + { + ThrowFileException(exception,FileOpenError, + "UnableToCreateTemporaryFile",image->filename); + return(MagickFalse); + } + } + (void) CopyMagickString(filename,image->filename,MaxTextExtent); delegate_info=GetDelegateInfo(decode,encode,exception); if (delegate_info == (DelegateInfo *) NULL) { if (temporary != MagickFalse) (void) RelinquishUniqueFileResource(image->filename); + else + { + unlink(image->filename); + (void) CopyMagickString(image->filename,linkedname,MaxTextExtent); + } (void) ThrowMagickException(exception,GetMagickModule(),DelegateError, "NoTagFound","`%s'",decode ? decode : encode); return(MagickFalse); @@ -749,12 +838,31 @@ { if (temporary != MagickFalse) (void) RelinquishUniqueFileResource(image->filename); + else + { + unlink(image->filename); + (void) CopyMagickString(image->filename,linkedname, + MaxTextExtent); + } ThrowFileException(exception,FileOpenError, "UnableToCreateTemporaryFile",image_info->filename); return(MagickFalse); } image_info->temporary=MagickTrue; } + else + { + (void) CopyMagickString(linkedinfoname,image_info->filename, + MaxTextExtent); + if (AcquireTemporarySymlink(image_info->filename,linkedinfoname) + == MagickFalse) + { + ThrowFileException(exception,FileOpenError, + "UnableToCreateTemporaryFile",image_info->filename); + return(MagickFalse); + } + } + if (delegate_info->mode != 0) if (((decode != (const char *) NULL) && (delegate_info->encode != (char *) NULL)) || @@ -795,6 +903,12 @@ (void) RelinquishUniqueFileResource(image_info->zero); if (temporary != MagickFalse) (void) RelinquishUniqueFileResource(image->filename); + else + { + unlink(image->filename); + (void) CopyMagickString(image->filename,linkedname, + MaxTextExtent); + } (void) ThrowMagickException(exception,GetMagickModule(), DelegateError,"DelegateFailed","`%s'",decode ? decode : encode); return(MagickFalse); @@ -822,6 +936,12 @@ (void) RelinquishUniqueFileResource(image_info->zero); if (temporary != MagickFalse) (void) RelinquishUniqueFileResource(image->filename); + else + { + unlink(image->filename); + (void) CopyMagickString(image->filename,linkedname, + MaxTextExtent); + } clone_info=DestroyImageInfo(clone_info); (void) ThrowMagickException(exception,GetMagickModule(), DelegateError,"DelegateFailed","`%s'",decode ? decode : encode); @@ -843,6 +963,18 @@ { if (temporary != MagickFalse) (void) RelinquishUniqueFileResource(image->filename); + else + { + unlink(image->filename); + (void) CopyMagickString(image->filename,linkedname, + MaxTextExtent); + } + if (*linkedinfoname) + { + unlink(image_info->filename); + (void) CopyMagickString(image_info->filename,linkedinfoname, + MaxTextExtent); + } (void) ThrowMagickException(exception,GetMagickModule(), ResourceLimitError,"MemoryAllocationFailed","`%s'", decode ? decode : encode); @@ -895,6 +1027,18 @@ commands=(char **) RelinquishMagickMemory(commands); if (temporary != MagickFalse) (void) RelinquishUniqueFileResource(image->filename); + else + { + unlink(image->filename); + (void) CopyMagickString(image->filename,linkedname, + MaxTextExtent); + } + if (*linkedinfoname) + { + unlink(image_info->filename); + (void) CopyMagickString(image_info->filename,linkedinfoname, + MaxTextExtent); + } return((MagickBooleanType) (status == MagickFalse)); } only in patch2: unchanged: --- imagemagick-6.2.4.5.orig/magick/delegate.h +++ imagemagick-6.2.4.5/magick/delegate.h @@ -96,6 +96,9 @@ extern MagickExport long GetDelegateMode(const DelegateInfo *); +extern MagickExport unsigned int + AcquireTemporarySymlink(char *, const char *); + extern MagickExport MagickBooleanType InvokePostscriptDelegate(const MagickBooleanType,const char *), InvokeDelegate(ImageInfo *,Image *,const char *,const char *,ExceptionInfo *), only in patch2: unchanged: --- imagemagick-6.2.4.5.orig/magick/display.c +++ imagemagick-6.2.4.5/magick/display.c @@ -1841,10 +1841,7 @@ image_number=0; last_image=0; last_scene=0; - image_marker=(unsigned long *) - AcquireMagickMemory((argc+1)*sizeof(*image_marker)); - for (i=0; i <= argc; i++) - image_marker[i]=(unsigned long) argc; + image_marker=(unsigned long *) NULL; option=(char *) NULL; pend=MagickFalse; resource_database=(XrmDatabase) NULL; @@ -1852,9 +1849,6 @@ server_name=(char *) NULL; state=0; status=MagickTrue; - if (image_marker == (unsigned long *) NULL) - ThrowDisplayException(ResourceLimitError,"MemoryAllocationFailed", - strerror(errno)); /* Check for server name specified on the command line. */ @@ -1863,6 +1857,13 @@ if (status == MagickFalse) ThrowDisplayException(ResourceLimitError,"MemoryAllocationFailed", strerror(errno)); + image_marker=(unsigned long *) + AcquireMagickMemory((argc+1)*sizeof(*image_marker)); + for (i=0; i <= argc; i++) + image_marker[i]=(unsigned long) argc; + if (image_marker == (unsigned long *) NULL) + ThrowDisplayException(ResourceLimitError,"MemoryAllocationFailed", + strerror(errno)); for (i=1; i < (long) argc; i++) { /* @@ -1983,7 +1984,7 @@ /* Form filename for multi-part images. */ - (void) FormatMagickString(filename,MaxTextExtent, + (void) FormatMagickStringNumeric(filename,MaxTextExtent, image_info->filename,scene); if (LocaleCompare(filename,image_info->filename) == 0) (void) FormatMagickString(filename,MaxTextExtent,"%s.%lu", only in patch2: unchanged: --- imagemagick-6.2.4.5.orig/magick/image.c +++ imagemagick-6.2.4.5/magick/image.c @@ -2869,25 +2869,8 @@ /* Rectify multi-image file support. */ - (void) CopyMagickString(filename,image_info->filename,MaxTextExtent); - for (p=strchr(filename,'%'); p != (char *) NULL; p=strchr(p+1,'%')) - { - char - *q; - - q=(char *) p+1; - if (*q == '0') - (void) strtol(q,&q,10); - if ((*q == '%') || (*q == 'd') || (*q == 'o') || (*q == 'x')) - { - char - format[MaxTextExtent]; - - (void) CopyMagickString(format,p,MaxTextExtent); - (void) FormatMagickString(p,MaxTextExtent,format,image_info->scene); - break; - } - } + (void) FormatMagickStringNumeric(filename,MaxTextExtent, + image_info->filename,image_info->scene); if ((LocaleCompare(filename,image_info->filename) != 0) && (strchr(filename,'%') == (char *) NULL)) image_info->adjoin=MagickFalse; only in patch2: unchanged: --- imagemagick-6.2.4.5.orig/magick/log.c +++ imagemagick-6.2.4.5/magick/log.c @@ -914,8 +914,8 @@ char filename[MaxTextExtent]; - (void) FormatMagickString(filename,MaxTextExtent,log_info->filename, - log_info->generation % log_info->generations); + (void) FormatMagickStringNumeric(filename,MaxTextExtent, + log_info->filename,log_info->generation % log_info->generations); log_info->file=fopen(filename,"w"); if (log_info->file == (FILE *) NULL) { only in patch2: unchanged: --- imagemagick-6.2.4.5.orig/magick/methods.h +++ imagemagick-6.2.4.5/magick/methods.h @@ -47,6 +47,7 @@ #define AcquireSemaphoreInfo PrependMagickMethod(AcquireSemaphoreInfo) #define AcquireStringInfo PrependMagickMethod(AcquireStringInfo) #define AcquireString PrependMagickMethod(AcquireString) +#define AcquireTemporarySymlink PrependMagickMethod(AcquireTemporarySymlink) #define AcquireUniqueFilename PrependMagickMethod(AcquireUniqueFilename) #define AcquireUniqueFileResource PrependMagickMethod(AcquireUniqueFileResource) #define AdaptiveThresholdImage PrependMagickMethod(AdaptiveThresholdImage) only in patch2: unchanged: --- imagemagick-6.2.4.5.orig/magick/montage.c +++ imagemagick-6.2.4.5/magick/montage.c @@ -530,7 +530,7 @@ /* Form filename for multi-part images. */ - (void) FormatMagickString(filename,MaxTextExtent, + (void) FormatMagickStringNumeric(filename,MaxTextExtent, image_info->filename,scene); if (LocaleCompare(filename,image_info->filename) == 0) (void) FormatMagickString(filename,MaxTextExtent,"%s.%lu", only in patch2: unchanged: --- imagemagick-6.2.4.5.orig/magick/string.c +++ imagemagick-6.2.4.5/magick/string.c @@ -960,6 +960,75 @@ % % % % % % +% F o r m a t M a g i c k S t r i n g N u m e r i c % +% % +% % +% % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% Method FormatMagickStringNumeric formats output for a single numeric +% argument. It takes into account that the format string given might be +% untrusted user input, and returns the length of the formatted string. +% +% The format of the FormatMagickStringNumeric method is: +% +% long FormatMagickStringNumeric(char *string,const size_t length, +% const char *format,int value) +% +% A description of each parameter follows. +% +% o string: FormatMagickStringNumeric() returns the formatted string in this +% character buffer. +% +% o length: The maximum length of the string. +% +% o format: A string describing the format to use to write the numeric +% argument. Only the first numeric format identifier is replaced. +% +% o value: Numeric value to substitute into format string. +% +% +*/ +MagickExport long FormatMagickStringNumeric(char *string,const size_t length,const char *format,int value) +{ + char + *p; + + (void) CopyMagickString(string, format, length); + + for (p=strchr(format,'%'); p != (char *) NULL; p=strchr(p+1,'%')) + { + char + *q; + + q=(char *) p+1; + if (*q == '0') + (void) strtol(q,&q,10); + if ((*q == '%') || (*q == 'd') || (*q == 'o') || (*q == 'x')) + { + char + c; + + q++; + c=*q; + *q='\0'; + (void) snprintf(string+(p-format),length-(p-format),p,value); + *q=c; + (void) ConcatenateMagickString(string,q,length); + if (*(q-1) == '%') + p++; + else + break; + } + } + return (long)strlen(string); +} + +/* +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% % +% % +% % % F o r m a t M a g i c k S t r i n g % % % % % only in patch2: unchanged: --- imagemagick-6.2.4.5.orig/magick/string_.h +++ imagemagick-6.2.4.5/magick/string_.h @@ -60,6 +60,7 @@ magick_attribute((format (printf,3,4))), FormatMagickStringList(char *,const size_t,const char *,va_list) magick_attribute((format (printf,3,0))), + FormatMagickStringNumeric(char *,const size_t,const char *,int), LocaleCompare(const char *,const char *), LocaleNCompare(const char *,const char *,const size_t);