summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNick Wellnhofer <wellnhofer@aevum.de>2019-10-04 14:42:59 +0200
committerNick Wellnhofer <wellnhofer@aevum.de>2019-10-04 14:42:59 +0200
commit24e3973bc03c15d534b2eac6e70fc2b2bef2b6c0 (patch)
treeeef46e5233ed46c68e3107226aba59805268a581
parent64966ebefdbd350a2c34577f1bf88e39b3a48ece (diff)
downloadlibxml2-24e3973bc03c15d534b2eac6e70fc2b2bef2b6c0.tar.gz
Make xmlDumpElementContent non-recursive
Avoid call stack overflow when dumping deeply nested element declarations. Found by OSS-Fuzz.
-rw-r--r--valid.c157
1 files changed, 89 insertions, 68 deletions
diff --git a/valid.c b/valid.c
index fca3cc06..eaccb11e 100644
--- a/valid.c
+++ b/valid.c
@@ -1148,84 +1148,105 @@ 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
* @content: An element table
@@ -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: