[librsvg/librsvg-2.40: 3/10] Keep track of the number of acquired elements
- From: Federico Mena Quintero <federico src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [librsvg/librsvg-2.40: 3/10] Keep track of the number of acquired elements
- Date: Wed, 26 Feb 2020 17:43:09 +0000 (UTC)
commit a37f0f8f82eb8c874cb538b47ca443072cbafac4
Author: Federico Mena Quintero <federico gnome org>
Date: Wed Feb 26 11:06:03 2020 -0600
Keep track of the number of acquired elements
rsvg-base.c | 42 ++++++++++++++++++++++++++++++++++++++++++
rsvg-private.h | 2 ++
rsvg-structure.c | 3 +++
3 files changed, 47 insertions(+)
---
diff --git a/rsvg-base.c b/rsvg-base.c
index b040dad0..68e93f63 100644
--- a/rsvg-base.c
+++ b/rsvg-base.c
@@ -2166,6 +2166,41 @@ rsvg_push_discrete_layer (RsvgDrawingCtx * ctx)
ctx->render->push_discrete_layer (ctx);
}
+void
+rsvg_drawing_ctx_increase_num_elements_acquired (RsvgDrawingCtx *draw_ctx)
+{
+ draw_ctx->num_elements_acquired++;
+}
+
+/* This is a mitigation for the security-related bugs:
+ * https://gitlab.gnome.org/GNOME/librsvg/issues/323
+ * https://gitlab.gnome.org/GNOME/librsvg/issues/515
+ *
+ * Imagine the XML [billion laughs attack], but done in SVG's terms:
+ *
+ * - #323 above creates deeply nested groups of `<use>` elements.
+ * The first one references the second one ten times, the second one
+ * references the third one ten times, and so on. In the file given,
+ * this causes 10^17 objects to be rendered. While this does not
+ * exhaust memory, it would take a really long time.
+ *
+ * - #515 has deeply nested references of `<pattern>` elements. Each
+ * object inside each pattern has an attribute
+ * fill="url(#next_pattern)", so the number of final rendered objects
+ * grows exponentially.
+ *
+ * We deal with both cases by placing a limit on how many references
+ * will be resolved during the SVG rendering process, that is,
+ * how many `url(#foo)` will be resolved.
+ *
+ * [billion laughs attack]: https://bitbucket.org/tiran/defusedxml
+ */
+gboolean
+rsvg_drawing_ctx_limits_exceeded (RsvgDrawingCtx *draw_ctx)
+{
+ return draw_ctx->num_elements_acquired > 500000;
+}
+
RsvgNode *
rsvg_drawing_ctx_acquire_node_ref (RsvgDrawingCtx * ctx, RsvgNode *node)
{
@@ -2197,6 +2232,13 @@ rsvg_acquire_node (RsvgDrawingCtx * ctx, const char *url)
{
RsvgNode *node;
+ if (url == NULL)
+ return NULL;
+
+ rsvg_drawing_ctx_increase_num_elements_acquired (ctx);
+ if (rsvg_drawing_ctx_limits_exceeded (ctx))
+ return NULL;
+
node = rsvg_defs_lookup (ctx->defs, url);
if (node == NULL)
return NULL;
diff --git a/rsvg-private.h b/rsvg-private.h
index 7d0188b0..734c9db4 100644
--- a/rsvg-private.h
+++ b/rsvg-private.h
@@ -370,6 +370,8 @@ void rsvg_pop_discrete_layer (RsvgDrawingCtx * ctx);
G_GNUC_INTERNAL
void rsvg_push_discrete_layer (RsvgDrawingCtx * ctx);
G_GNUC_INTERNAL
+gboolean rsvg_drawing_ctx_limits_exceeded (RsvgDrawingCtx *draw_ctx);
+G_GNUC_INTERNAL
RsvgNode *rsvg_drawing_ctx_acquire_node_ref (RsvgDrawingCtx * ctx, RsvgNode *node);
G_GNUC_INTERNAL
RsvgNode *rsvg_acquire_node (RsvgDrawingCtx * ctx, const char *url);
diff --git a/rsvg-structure.c b/rsvg-structure.c
index 3c972e50..823a91b4 100644
--- a/rsvg-structure.c
+++ b/rsvg-structure.c
@@ -40,6 +40,9 @@ rsvg_node_draw (RsvgNode * self, RsvgDrawingCtx * ctx, int dominate)
RsvgState *state;
GSList *stacksave;
+ if (rsvg_drawing_ctx_limits_exceeded (ctx))
+ return;
+
state = self->state;
stacksave = ctx->drawsub_stack;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]