Commit 8911876f1 for imagemagick.org
commit 8911876f1e1e8f69cf1c1dd8f9a69685c8b776ae
Author: Cristy <urban-warrior@imagemagick.org>
Date: Sun Oct 4 14:31:55 2026 -0400
https://github.com/ImageMagick/ImageMagick/security/advisories/GHSA-x258-xjqf-6j3f
diff --git a/MagickCore/draw.c b/MagickCore/draw.c
index 24d36812f..6261b3ced 100644
--- a/MagickCore/draw.c
+++ b/MagickCore/draw.c
@@ -93,6 +93,7 @@
*/
#define AntialiasThreshold (1.0/3.0)
#define BezierQuantum 200
+#define MaxVectorRecursionDepth 400
#define PrimitiveExtentPad 4296.0
#define MaxBezierCoordinates 67108864
#define MacroExpansionLimit 262144
@@ -191,7 +192,7 @@ typedef struct _PathInfo
*/
static Image
*DrawClippingMask(Image *,const DrawInfo *,const char *,const char *,
- ExceptionInfo *);
+ const size_t,ExceptionInfo *);
static MagickBooleanType
DrawStrokePolygon(Image *,const DrawInfo *,const PrimitiveInfo *,
@@ -1510,8 +1511,10 @@ static MagickBooleanType DrawBoundingRectangles(Image *image,
% o exception: return any errors or warnings in this structure.
%
*/
-MagickExport MagickBooleanType DrawClipPath(Image *image,
- const DrawInfo *draw_info,const char *id,ExceptionInfo *exception)
+
+static MagickBooleanType DrawClipPath_(Image *image,
+ const DrawInfo *draw_info,const char *id,const size_t depth,
+ ExceptionInfo *exception)
{
const char
*clip_path;
@@ -1526,13 +1529,19 @@ MagickExport MagickBooleanType DrawClipPath(Image *image,
if (clip_path == (const char *) NULL)
return(MagickFalse);
clipping_mask=DrawClippingMask(image,draw_info,draw_info->clip_mask,clip_path,
- exception);
+ depth+1,exception);
if (clipping_mask == (Image *) NULL)
return(MagickFalse);
status=SetImageMask(image,WritePixelMask,clipping_mask,exception);
clipping_mask=DestroyImage(clipping_mask);
return(status);
}
+
+MagickExport MagickBooleanType DrawClipPath(Image *image,
+ const DrawInfo *draw_info,const char *id,ExceptionInfo *exception)
+{
+ return(DrawClipPath_(image,draw_info,id,0,exception));
+}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -1551,7 +1560,8 @@ MagickExport MagickBooleanType DrawClipPath(Image *image,
% The format of the DrawClippingMask method is:
%
% Image *DrawClippingMask(Image *image,const DrawInfo *draw_info,
-% const char *id,const char *clip_path,ExceptionInfo *exception)
+% const char *id,const char *clip_path,const size_t depth,
+% ExceptionInfo *exception)
%
% A description of each parameter follows:
%
@@ -1563,11 +1573,14 @@ MagickExport MagickBooleanType DrawClipPath(Image *image,
%
% o clip_path: the clip path.
%
+% o depth: track the vector depth.
+%
% o exception: return any errors or warnings in this structure.
%
*/
static Image *DrawClippingMask(Image *image,const DrawInfo *draw_info,
- const char *id,const char *clip_path,ExceptionInfo *exception)
+ const char *id,const char *clip_path,const size_t depth,
+ ExceptionInfo *exception)
{
DrawInfo
*clone_info;
@@ -1611,7 +1624,7 @@ static Image *DrawClippingMask(Image *image,const DrawInfo *draw_info,
clone_info->stroke_width=0.0;
clone_info->alpha=OpaqueAlpha;
clone_info->clip_path=MagickTrue;
- status=RenderMVGContent(clip_mask,clone_info,0,exception);
+ status=RenderMVGContent(clip_mask,clone_info,depth+1,exception);
clone_info=DestroyDrawInfo(clone_info);
separate_mask=SeparateImage(clip_mask,AlphaChannel,exception);
if (separate_mask == (Image *) NULL)
@@ -1645,7 +1658,8 @@ static Image *DrawClippingMask(Image *image,const DrawInfo *draw_info,
% The format of the DrawCompositeMask method is:
%
% Image *DrawCompositeMask(Image *image,const DrawInfo *draw_info,
-% const char *id,const char *mask_path,ExceptionInfo *exception)
+% const char *id,const char *mask_path,const size_t depth,
+% ExceptionInfo *exception)
%
% A description of each parameter follows:
%
@@ -1657,11 +1671,14 @@ static Image *DrawClippingMask(Image *image,const DrawInfo *draw_info,
%
% o mask_path: the mask path.
%
+% o depth: track the vector depth.
+%
% o exception: return any errors or warnings in this structure.
%
*/
static Image *DrawCompositeMask(Image *image,const DrawInfo *draw_info,
- const char *id,const char *mask_path,ExceptionInfo *exception)
+ const char *id,const char *mask_path,const size_t depth,
+ ExceptionInfo *exception)
{
Image
*composite_mask,
@@ -1703,7 +1720,7 @@ static Image *DrawCompositeMask(Image *image,const DrawInfo *draw_info,
exception);
clone_info->stroke_width=0.0;
clone_info->alpha=OpaqueAlpha;
- status=RenderMVGContent(composite_mask,clone_info,0,exception);
+ status=RenderMVGContent(composite_mask,clone_info,depth+1,exception);
clone_info=DestroyDrawInfo(clone_info);
separate_mask=SeparateImage(composite_mask,AlphaChannel,exception);
if (separate_mask != (Image *) NULL)
@@ -2440,7 +2457,7 @@ static SplayTreeInfo *GetMVGMacros(const char *primitive,
}
if (LocaleCompare(token,"push") == 0)
{
- if (n++ >= MagickMaxRecursionDepth)
+ if (n++ >= MaxVectorRecursionDepth)
{
(void) ThrowMagickException(exception,GetMagickModule(),
DrawError,"VectorGraphicsNestedTooDeeply","`%s'",token);
@@ -2600,7 +2617,7 @@ static MagickBooleanType RenderMVGContent(Image *image,
assert(draw_info->signature == MagickCoreSignature);
if (IsEventLogging() != MagickFalse)
(void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
- if (depth >= MagickMaxRecursionDepth)
+ if (depth >= MaxVectorRecursionDepth)
ThrowBinaryException(DrawError,"VectorGraphicsNestedTooDeeply",
image->filename);
if ((draw_info->primitive == (char *) NULL) ||
@@ -2803,7 +2820,7 @@ static MagickBooleanType RenderMVGContent(Image *image,
break;
if (i <= n)
break;
- if (classDepth++ >= MagickMaxRecursionDepth)
+ if (classDepth++ >= MaxVectorRecursionDepth)
{
(void) ThrowMagickException(exception,GetMagickModule(),
DrawError,"VectorGraphicsNestedTooDeeply","`%s'",token);
@@ -2858,7 +2875,7 @@ static MagickBooleanType RenderMVGContent(Image *image,
graphic_context[n]->clipping_mask=
DestroyImage(graphic_context[n]->clipping_mask);
graphic_context[n]->clipping_mask=DrawClippingMask(image,
- graphic_context[n],token,clip_path,exception);
+ graphic_context[n],token,clip_path,depth+1,exception);
if (graphic_context[n]->compliance != SVGCompliance)
{
clip_path=(const char *) GetValueFromSplayTree(macros,
@@ -2866,9 +2883,9 @@ static MagickBooleanType RenderMVGContent(Image *image,
if (clip_path != (const char *) NULL)
(void) SetImageArtifact(image,
graphic_context[n]->clip_mask,clip_path);
- status&=(MagickStatusType) DrawClipPath(image,
+ status&=(MagickStatusType) DrawClipPath_(image,
graphic_context[n],graphic_context[n]->clip_mask,
- exception);
+ depth+1,exception);
}
}
break;
@@ -3268,7 +3285,7 @@ static MagickBooleanType RenderMVGContent(Image *image,
graphic_context[n]->composite_mask=
DestroyImage(graphic_context[n]->composite_mask);
graphic_context[n]->composite_mask=DrawCompositeMask(image,
- graphic_context[n],token,mask_path,exception);
+ graphic_context[n],token,mask_path,depth+1,exception);
if (graphic_context[n]->compliance != SVGCompliance)
status=SetImageMask(image,CompositePixelMask,
graphic_context[n]->composite_mask,exception);
@@ -3571,7 +3588,7 @@ static MagickBooleanType RenderMVGContent(Image *image,
(void) GetNextToken(q,&q,extent,token);
(void) CloneString(&graphic_context[n]->id,token);
}
- if (n >= MagickMaxRecursionDepth)
+ if (n >= MaxVectorRecursionDepth)
{
(void) ThrowMagickException(exception,GetMagickModule(),
DrawError,"VectorGraphicsNestedTooDeeply","`%s'",
@@ -4640,8 +4657,8 @@ static MagickBooleanType RenderMVGContent(Image *image,
if (clip_path != (const char *) NULL)
(void) SetImageArtifact(image,graphic_context[n]->clip_mask,
clip_path);
- status&=(MagickStatusType) DrawClipPath(image,graphic_context[n],
- graphic_context[n]->clip_mask,exception);
+ status&=(MagickStatusType) DrawClipPath_(image,graphic_context[n],
+ graphic_context[n]->clip_mask,depth+1,exception);
}
status&=(MagickStatusType) DrawPrimitive(image,graphic_context[n],
primitive_info,exception);