212 lines
6.8 KiB
Diff
212 lines
6.8 KiB
Diff
From 3be39335ced799eb1ec312b7b542c84dac4ebd57 Mon Sep 17 00:00:00 2001
|
|
From: Nick Wellnhofer <wellnhofer@aevum.de>
|
|
Date: Fri, 4 Oct 2019 14:42:59 +0200
|
|
Subject: [PATCH] Make xmlDumpElementContent non-recursive
|
|
|
|
Avoid call stack overflow when dumping deeply nested element
|
|
declarations.
|
|
|
|
Found by OSS-Fuzz.
|
|
|
|
backport from https://gitlab.gnome.org/GNOME/libxml2/commit/24e3973bc03c15d534b2eac6e70fc2b2bef2b6c0
|
|
---
|
|
valid.c | 157 ++++++++++++++++++++++++++++++++------------------------
|
|
1 file changed, 89 insertions(+), 68 deletions(-)
|
|
|
|
diff --git a/valid.c b/valid.c
|
|
index b1cfede..632c5e7 100644
|
|
--- a/valid.c
|
|
+++ b/valid.c
|
|
@@ -1148,83 +1148,104 @@ xmlFreeElementContent(xmlElementContentPtr cur) {
|
|
|
|
#ifdef LIBXML_OUTPUT_ENABLED
|
|
/**
|
|
- * xmlDumpElementContent:
|
|
+ * xmlDumpElementOccur:
|
|
* @buf: An XML buffer
|
|
- * @content: An element table
|
|
- * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
|
|
+ * @cur: An element table
|
|
*
|
|
- * This will dump the content of the element table as an XML DTD definition
|
|
+ * Dump the occurence operator of an element.
|
|
*/
|
|
static void
|
|
-xmlDumpElementContent(xmlBufferPtr buf, xmlElementContentPtr content, int glob) {
|
|
- if (content == NULL) return;
|
|
-
|
|
- if (glob) xmlBufferWriteChar(buf, "(");
|
|
- switch (content->type) {
|
|
- case XML_ELEMENT_CONTENT_PCDATA:
|
|
- xmlBufferWriteChar(buf, "#PCDATA");
|
|
- break;
|
|
- case XML_ELEMENT_CONTENT_ELEMENT:
|
|
- if (content->prefix != NULL) {
|
|
- xmlBufferWriteCHAR(buf, content->prefix);
|
|
- xmlBufferWriteChar(buf, ":");
|
|
- }
|
|
- xmlBufferWriteCHAR(buf, content->name);
|
|
- break;
|
|
- case XML_ELEMENT_CONTENT_SEQ:
|
|
- if ((content->c1 != NULL) &&
|
|
- ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
|
|
- (content->c1->type == XML_ELEMENT_CONTENT_SEQ)))
|
|
- xmlDumpElementContent(buf, content->c1, 1);
|
|
- else
|
|
- xmlDumpElementContent(buf, content->c1, 0);
|
|
- xmlBufferWriteChar(buf, " , ");
|
|
- if ((content->c2 != NULL) &&
|
|
- ((content->c2->type == XML_ELEMENT_CONTENT_OR) ||
|
|
- ((content->c2->type == XML_ELEMENT_CONTENT_SEQ) &&
|
|
- (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE))))
|
|
- xmlDumpElementContent(buf, content->c2, 1);
|
|
- else
|
|
- xmlDumpElementContent(buf, content->c2, 0);
|
|
- break;
|
|
- case XML_ELEMENT_CONTENT_OR:
|
|
- if ((content->c1 != NULL) &&
|
|
- ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
|
|
- (content->c1->type == XML_ELEMENT_CONTENT_SEQ)))
|
|
- xmlDumpElementContent(buf, content->c1, 1);
|
|
- else
|
|
- xmlDumpElementContent(buf, content->c1, 0);
|
|
- xmlBufferWriteChar(buf, " | ");
|
|
- if ((content->c2 != NULL) &&
|
|
- ((content->c2->type == XML_ELEMENT_CONTENT_SEQ) ||
|
|
- ((content->c2->type == XML_ELEMENT_CONTENT_OR) &&
|
|
- (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE))))
|
|
- xmlDumpElementContent(buf, content->c2, 1);
|
|
- else
|
|
- xmlDumpElementContent(buf, content->c2, 0);
|
|
- break;
|
|
- default:
|
|
- xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
|
|
- "Internal: ELEMENT content corrupted invalid type\n",
|
|
- NULL);
|
|
- }
|
|
- if (glob)
|
|
- xmlBufferWriteChar(buf, ")");
|
|
- switch (content->ocur) {
|
|
+xmlDumpElementOccur(xmlBufferPtr buf, xmlElementContentPtr cur) {
|
|
+ switch (cur->ocur) {
|
|
case XML_ELEMENT_CONTENT_ONCE:
|
|
- break;
|
|
+ break;
|
|
case XML_ELEMENT_CONTENT_OPT:
|
|
- xmlBufferWriteChar(buf, "?");
|
|
- break;
|
|
+ xmlBufferWriteChar(buf, "?");
|
|
+ break;
|
|
case XML_ELEMENT_CONTENT_MULT:
|
|
- xmlBufferWriteChar(buf, "*");
|
|
- break;
|
|
+ xmlBufferWriteChar(buf, "*");
|
|
+ break;
|
|
case XML_ELEMENT_CONTENT_PLUS:
|
|
- xmlBufferWriteChar(buf, "+");
|
|
- break;
|
|
+ xmlBufferWriteChar(buf, "+");
|
|
+ break;
|
|
}
|
|
}
|
|
|
|
+/**
|
|
+ * xmlDumpElementContent:
|
|
+ * @buf: An XML buffer
|
|
+ * @content: An element table
|
|
+ *
|
|
+ * This will dump the content of the element table as an XML DTD definition
|
|
+ */
|
|
+static void
|
|
+xmlDumpElementContent(xmlBufferPtr buf, xmlElementContentPtr content) {
|
|
+ xmlElementContentPtr cur;
|
|
+
|
|
+ if (content == NULL) return;
|
|
+
|
|
+ xmlBufferWriteChar(buf, "(");
|
|
+ cur = content;
|
|
+
|
|
+ do {
|
|
+ if (cur == NULL) return;
|
|
+
|
|
+ switch (cur->type) {
|
|
+ case XML_ELEMENT_CONTENT_PCDATA:
|
|
+ xmlBufferWriteChar(buf, "#PCDATA");
|
|
+ break;
|
|
+ case XML_ELEMENT_CONTENT_ELEMENT:
|
|
+ if (cur->prefix != NULL) {
|
|
+ xmlBufferWriteCHAR(buf, cur->prefix);
|
|
+ xmlBufferWriteChar(buf, ":");
|
|
+ }
|
|
+ xmlBufferWriteCHAR(buf, cur->name);
|
|
+ break;
|
|
+ case XML_ELEMENT_CONTENT_SEQ:
|
|
+ case XML_ELEMENT_CONTENT_OR:
|
|
+ if ((cur != content) &&
|
|
+ (cur->parent != NULL) &&
|
|
+ ((cur->type != cur->parent->type) ||
|
|
+ (cur->ocur != XML_ELEMENT_CONTENT_ONCE)))
|
|
+ xmlBufferWriteChar(buf, "(");
|
|
+ cur = cur->c1;
|
|
+ continue;
|
|
+ default:
|
|
+ xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
|
|
+ "Internal: ELEMENT cur corrupted invalid type\n",
|
|
+ NULL);
|
|
+ }
|
|
+
|
|
+ while (cur != content) {
|
|
+ xmlElementContentPtr parent = cur->parent;
|
|
+
|
|
+ if (parent == NULL) return;
|
|
+
|
|
+ if (((cur->type == XML_ELEMENT_CONTENT_OR) ||
|
|
+ (cur->type == XML_ELEMENT_CONTENT_SEQ)) &&
|
|
+ ((cur->type != parent->type) ||
|
|
+ (cur->ocur != XML_ELEMENT_CONTENT_ONCE)))
|
|
+ xmlBufferWriteChar(buf, ")");
|
|
+ xmlDumpElementOccur(buf, cur);
|
|
+
|
|
+ if (cur == parent->c1) {
|
|
+ if (parent->type == XML_ELEMENT_CONTENT_SEQ)
|
|
+ xmlBufferWriteChar(buf, " , ");
|
|
+ else if (parent->type == XML_ELEMENT_CONTENT_OR)
|
|
+ xmlBufferWriteChar(buf, " | ");
|
|
+
|
|
+ cur = parent->c2;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ cur = parent;
|
|
+ }
|
|
+ } while (cur != content);
|
|
+
|
|
+ xmlBufferWriteChar(buf, ")");
|
|
+ xmlDumpElementOccur(buf, content);
|
|
+}
|
|
+
|
|
/**
|
|
* xmlSprintfElementContent:
|
|
* @buf: an output buffer
|
|
@@ -1703,7 +1724,7 @@ xmlDumpElementDecl(xmlBufferPtr buf, xmlElementPtr elem) {
|
|
}
|
|
xmlBufferWriteCHAR(buf, elem->name);
|
|
xmlBufferWriteChar(buf, " ");
|
|
- xmlDumpElementContent(buf, elem->content, 1);
|
|
+ xmlDumpElementContent(buf, elem->content);
|
|
xmlBufferWriteChar(buf, ">\n");
|
|
break;
|
|
case XML_ELEMENT_TYPE_ELEMENT:
|
|
@@ -1714,7 +1735,7 @@ xmlDumpElementDecl(xmlBufferPtr buf, xmlElementPtr elem) {
|
|
}
|
|
xmlBufferWriteCHAR(buf, elem->name);
|
|
xmlBufferWriteChar(buf, " ");
|
|
- xmlDumpElementContent(buf, elem->content, 1);
|
|
+ xmlDumpElementContent(buf, elem->content);
|
|
xmlBufferWriteChar(buf, ">\n");
|
|
break;
|
|
default:
|
|
--
|
|
2.18.1
|
|
|