From 298b30ea4ebee137226acf9bb38678bd82704582 Mon Sep 17 00:00:00 2001
From: Michal Vasko <mvasko@cesnet.cz>
Date: Mon, 8 Mar 2021 14:32:58 +0100
Subject: [PATCH] common FEATURE add a hard limit for recursion

Fixes #1453
---
 src/common.h.in |  3 +++
 src/xml.c       | 12 +++++++++---
 2 files changed, 12 insertions(+), 3 deletions(-)

diff --git a/src/common.h.in b/src/common.h.in
index a5bf2b038..624beba9f 100644
--- a/src/common.h.in
+++ b/src/common.h.in
@@ -53,6 +53,9 @@
 /* how many bytes add when enlarging buffers */
 #define LY_BUF_STEP 128
 
+/* hard limit on recursion for cases with theoretical unlimited recursion */
+#define LY_RECURSION_LIMIT 10000
+
 /* internal logging options */
 enum int_log_opts {
     ILO_LOG = 0, /* log normally */
diff --git a/src/xml.c b/src/xml.c
index 1bc4fdfa5..7e4760976 100644
--- a/src/xml.c
+++ b/src/xml.c
@@ -943,7 +943,8 @@ parse_attr(struct ly_ctx *ctx, const char *data, unsigned int *len, struct lyxml
 
 /* logs directly */
 struct lyxml_elem *
-lyxml_parse_elem(struct ly_ctx *ctx, const char *data, unsigned int *len, struct lyxml_elem *parent, int options)
+lyxml_parse_elem(struct ly_ctx *ctx, const char *data, unsigned int *len, struct lyxml_elem *parent, int options,
+                 int bt_count)
 {
     const char *c = data, *start, *e;
     const char *lws;    /* leading white space for handling mixed content */
@@ -958,6 +959,11 @@ lyxml_parse_elem(struct ly_ctx *ctx, const char *data, unsigned int *len, struct
 
     *len = 0;
 
+    if (bt_count > LY_RECURSION_LIMIT) {
+        LOGVAL(ctx, LYE_XML_INVAL, LY_VLOG_NONE, NULL, "Recursion limit %d reached", LY_RECURSION_LIMIT);
+        return NULL;
+    }
+
     if (*c != '<') {
         return NULL;
     }
@@ -1141,7 +1147,7 @@ lyxml_parse_elem(struct ly_ctx *ctx, const char *data, unsigned int *len, struct
                     lyxml_add_child(ctx, elem, child);
                     elem->flags |= LYXML_ELEM_MIXED;
                 }
-                child = lyxml_parse_elem(ctx, c, &size, elem, options);
+                child = lyxml_parse_elem(ctx, c, &size, elem, options, bt_count + 1);
                 if (!child) {
                     goto error;
                 }
@@ -1295,7 +1301,7 @@ lyxml_parse_mem(struct ly_ctx *ctx, const char *data, int options)
         }
     }
 
-    root = lyxml_parse_elem(ctx, c, &len, NULL, options);
+    root = lyxml_parse_elem(ctx, c, &len, NULL, options, 0);
     if (!root) {
         goto error;
     } else if (!first) {
