From: Cristy <urban-warrior@imagemagick.org>
Date: Mon, 6 Mar 2023 14:46:21 -0500
Subject: CVE-2023-1289: recursion detection framework

origin: https://github.com/ImageMagick/ImageMagick6/commit/e8c0090c6d2df7b1553053dca2008e96724204bf
bug-debian-security: https://security-tracker.debian.org/tracker/CVE-2023-1289
---
 magick/constitute.c | 12 ++++++++++++
 magick/draw.c       | 55 +++++++++++++++++++++++++----------------------------
 magick/draw.h       |  3 +++
 magick/image.c      |  1 +
 magick/image.h      |  3 +++
 5 files changed, 45 insertions(+), 29 deletions(-)

diff --git a/magick/constitute.c b/magick/constitute.c
index e05c538..49e8f82 100644
--- a/magick/constitute.c
+++ b/magick/constitute.c
@@ -77,6 +77,11 @@
 #include "magick/transform.h"
 #include "magick/utility.h"
 
+/*  
+  Define declarations.
+*/
+#define MaxReadRecursionDepth  100
+
 /*
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %                                                                             %
@@ -558,9 +563,16 @@ MagickExport Image *ReadImage(const ImageInfo *image_info,
       if ((thread_support & DecoderThreadSupport) == 0)
         LockSemaphoreInfo(magick_info->semaphore);
       status=IsCoderAuthorized(read_info->magick,ReadPolicyRights,exception);
+      if (((ImageInfo *) image_info)->recursion_depth++ > MaxReadRecursionDepth)
+        {
+          (void) ThrowMagickException(exception,GetMagickModule(),CoderError,
+            "NumberOfImagesIsNotSupported","`%s'",read_info->magick);
+          status=MagickFalse;
+        }
       image=(Image *) NULL;
       if (status != MagickFalse)
         image=GetImageDecoder(magick_info)(read_info,exception);
+      ((ImageInfo *) image_info)->recursion_depth--;
       if ((thread_support & DecoderThreadSupport) == 0)
         UnlockSemaphoreInfo(magick_info->semaphore);
     }
diff --git a/magick/draw.c b/magick/draw.c
index e0bbc24..962a42f 100644
--- a/magick/draw.c
+++ b/magick/draw.c
@@ -381,6 +381,7 @@ MagickExport DrawInfo *CloneDrawInfo(const ImageInfo *image_info,
     clone_info->composite_mask=CloneImage(draw_info->composite_mask,0,0,
       MagickTrue,&draw_info->composite_mask->exception);
   clone_info->render=draw_info->render;
+  clone_info->image_info=CloneImageInfo(draw_info->image_info);
   clone_info->debug=IsEventLogging();
   return(clone_info);
 }
@@ -5820,21 +5821,18 @@ MagickExport void GetDrawInfo(const ImageInfo *image_info,DrawInfo *draw_info)
   ExceptionInfo
     *exception;
 
-  ImageInfo
-    *clone_info;
-
   /*
     Initialize draw attributes.
   */
   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
   assert(draw_info != (DrawInfo *) NULL);
   (void) memset(draw_info,0,sizeof(*draw_info));
-  clone_info=CloneImageInfo(image_info);
+  draw_info->image_info=CloneImageInfo(image_info);
   GetAffineMatrix(&draw_info->affine);
   exception=AcquireExceptionInfo();
   (void) QueryColorDatabase("#000F",&draw_info->fill,exception);
   (void) QueryColorDatabase("#FFF0",&draw_info->stroke,exception);
-  draw_info->stroke_antialias=clone_info->antialias;
+  draw_info->stroke_antialias=draw_info->image_info->antialias;
   draw_info->stroke_width=1.0;
   draw_info->fill_rule=EvenOddRule;
   draw_info->opacity=OpaqueOpacity;
@@ -5844,64 +5842,64 @@ MagickExport void GetDrawInfo(const ImageInfo *image_info,DrawInfo *draw_info)
   draw_info->linejoin=MiterJoin;
   draw_info->miterlimit=10;
   draw_info->decorate=NoDecoration;
-  if (clone_info->font != (char *) NULL)
-    draw_info->font=AcquireString(clone_info->font);
-  if (clone_info->density != (char *) NULL)
-    draw_info->density=AcquireString(clone_info->density);
-  draw_info->text_antialias=clone_info->antialias;
+  if (draw_info->image_info->font != (char *) NULL)
+    draw_info->font=AcquireString(draw_info->image_info->font);
+  if (draw_info->image_info->density != (char *) NULL)
+    draw_info->density=AcquireString(draw_info->image_info->density);
+  draw_info->text_antialias=draw_info->image_info->antialias;
   draw_info->pointsize=12.0;
-  if (fabs(clone_info->pointsize) >= MagickEpsilon)
-    draw_info->pointsize=clone_info->pointsize;
+  if (fabs(draw_info->image_info->pointsize) >= MagickEpsilon)
+    draw_info->pointsize=draw_info->image_info->pointsize;
   draw_info->undercolor.opacity=(Quantum) TransparentOpacity;
-  draw_info->border_color=clone_info->border_color;
+  draw_info->border_color=draw_info->image_info->border_color;
   draw_info->compose=OverCompositeOp;
-  if (clone_info->server_name != (char *) NULL)
-    draw_info->server_name=AcquireString(clone_info->server_name);
+  if (draw_info->image_info->server_name != (char *) NULL)
+    draw_info->server_name=AcquireString(draw_info->image_info->server_name);
   draw_info->render=MagickTrue;
   draw_info->clip_path=MagickFalse;
   draw_info->debug=IsEventLogging();
-  option=GetImageOption(clone_info,"direction");
+  option=GetImageOption(draw_info->image_info,"direction");
   if (option != (const char *) NULL)
     draw_info->direction=(DirectionType) ParseCommandOption(
       MagickDirectionOptions,MagickFalse,option);
   else
     draw_info->direction=UndefinedDirection;
-  option=GetImageOption(clone_info,"encoding");
+  option=GetImageOption(draw_info->image_info,"encoding");
   if (option != (const char *) NULL)
     (void) CloneString(&draw_info->encoding,option);
-  option=GetImageOption(clone_info,"family");
+  option=GetImageOption(draw_info->image_info,"family");
   if (option != (const char *) NULL)
     (void) CloneString(&draw_info->family,option);
-  option=GetImageOption(clone_info,"fill");
+  option=GetImageOption(draw_info->image_info,"fill");
   if (option != (const char *) NULL)
     (void) QueryColorDatabase(option,&draw_info->fill,exception);
-  option=GetImageOption(clone_info,"gravity");
+  option=GetImageOption(draw_info->image_info,"gravity");
   if (option != (const char *) NULL)
     draw_info->gravity=(GravityType) ParseCommandOption(MagickGravityOptions,
       MagickFalse,option);
-  option=GetImageOption(clone_info,"interline-spacing");
+  option=GetImageOption(draw_info->image_info,"interline-spacing");
   if (option != (const char *) NULL)
     draw_info->interline_spacing=GetDrawValue(option,&next_token);
-  option=GetImageOption(clone_info,"interword-spacing");
+  option=GetImageOption(draw_info->image_info,"interword-spacing");
   if (option != (const char *) NULL)
     draw_info->interword_spacing=GetDrawValue(option,&next_token);
-  option=GetImageOption(clone_info,"kerning");
+  option=GetImageOption(draw_info->image_info,"kerning");
   if (option != (const char *) NULL)
     draw_info->kerning=GetDrawValue(option,&next_token);
-  option=GetImageOption(clone_info,"stroke");
+  option=GetImageOption(draw_info->image_info,"stroke");
   if (option != (const char *) NULL)
     (void) QueryColorDatabase(option,&draw_info->stroke,exception);
-  option=GetImageOption(clone_info,"strokewidth");
+  option=GetImageOption(draw_info->image_info,"strokewidth");
   if (option != (const char *) NULL)
     draw_info->stroke_width=GetDrawValue(option,&next_token);
-  option=GetImageOption(clone_info,"style");
+  option=GetImageOption(draw_info->image_info,"style");
   if (option != (const char *) NULL)
     draw_info->style=(StyleType) ParseCommandOption(MagickStyleOptions,
       MagickFalse,option);
-  option=GetImageOption(clone_info,"undercolor");
+  option=GetImageOption(draw_info->image_info,"undercolor");
   if (option != (const char *) NULL)
     (void) QueryColorDatabase(option,&draw_info->undercolor,exception);
-  option=GetImageOption(clone_info,"weight");
+  option=GetImageOption(draw_info->image_info,"weight");
   if (option != (const char *) NULL)
     {
       ssize_t
@@ -5914,7 +5912,6 @@ MagickExport void GetDrawInfo(const ImageInfo *image_info,DrawInfo *draw_info)
     }
   exception=DestroyExceptionInfo(exception);
   draw_info->signature=MagickCoreSignature;
-  clone_info=DestroyImageInfo(clone_info);
 }
 
 /*
diff --git a/magick/draw.h b/magick/draw.h
index a44ef3a..46e622d 100644
--- a/magick/draw.h
+++ b/magick/draw.h
@@ -354,6 +354,9 @@ typedef struct _DrawInfo
 
   char
     *id;
+
+  ImageInfo
+    *image_info;
 } DrawInfo;
 
 typedef struct _PrimitiveInfo
diff --git a/magick/image.c b/magick/image.c
index 1fc3617..9ee22d8 100644
--- a/magick/image.c
+++ b/magick/image.c
@@ -1008,6 +1008,7 @@ MagickExport ImageInfo *CloneImageInfo(const ImageInfo *image_info)
   clone_info->subimage=image_info->scene;  /* deprecated */
   clone_info->subrange=image_info->number_scenes;  /* deprecated */
   clone_info->channel=image_info->channel;
+  clone_info->recursion_depth=image_info->recursion_depth;
   clone_info->debug=IsEventLogging();
   clone_info->signature=image_info->signature;
   return(clone_info);
diff --git a/magick/image.h b/magick/image.h
index ac69bef..e71df13 100644
--- a/magick/image.h
+++ b/magick/image.h
@@ -499,6 +499,9 @@ struct _ImageInfo
 
   MagickBooleanType
     synchronize;
+
+  size_t
+    recursion_depth;  /* recursion detection */
 };
 
 extern MagickExport ExceptionType
