diff --git a/Don-t-process-siblings-of-root-in-xmlXIncludeProcess.patch b/Don-t-process-siblings-of-root-in-xmlXIncludeProcess.patch new file mode 100644 index 0000000000000000000000000000000000000000..2c8fb7202dc9e3535f540fe1e797a5ec83b02e06 --- /dev/null +++ b/Don-t-process-siblings-of-root-in-xmlXIncludeProcess.patch @@ -0,0 +1,88 @@ +From 11b5745927481d6a716acef5408da20899eab8a2 Mon Sep 17 00:00:00 2001 +From: Nick Wellnhofer +Date: Fri, 7 Aug 2020 18:39:19 +0200 +Subject: [PATCH 108/139] Don't process siblings of root in xmlXIncludeProcess + +xmlXIncludeDoProcess would follow the siblings of the tree root and +also expand these nodes. When using an XML reader, this could lead to +siblings of the current node being expanded without having been parsed +completely. +--- + xinclude.c | 38 ++++++++++++++++++-------------------- + 1 file changed, 18 insertions(+), 20 deletions(-) + +diff --git a/xinclude.c b/xinclude.c +index 0f1af9c..2917d45 100644 +--- a/xinclude.c ++++ b/xinclude.c +@@ -1980,6 +1980,8 @@ xmlXIncludeLoadFallback(xmlXIncludeCtxtPtr ctxt, xmlNodePtr fallback, int nr) { + (ctxt == NULL)) + return(-1); + if (fallback->children != NULL) { ++ xmlNodePtr child, next; ++ + /* + * It's possible that the fallback also has 'includes' + * (Bug 129969), so we re-process the fallback just in case +@@ -1990,11 +1992,13 @@ xmlXIncludeLoadFallback(xmlXIncludeCtxtPtr ctxt, xmlNodePtr fallback, int nr) { + newctxt->_private = ctxt->_private; + newctxt->base = xmlStrdup(ctxt->base); /* Inherit the base from the existing context */ + xmlXIncludeSetFlags(newctxt, ctxt->parseFlags); +- ret = xmlXIncludeDoProcess(newctxt, ctxt->doc, fallback->children); ++ for (child = fallback->children; child != NULL; child = next) { ++ next = child->next; ++ if (xmlXIncludeDoProcess(newctxt, ctxt->doc, child) < 0) ++ ret = -1; ++ } + if (ctxt->nbErrors > oldNbErrors) + ret = -1; +- else if (ret > 0) +- ret = 0; /* xmlXIncludeDoProcess can return +ve number */ + xmlXIncludeFreeContext(newctxt); + + ctxt->incTab[nr]->inc = xmlDocCopyNodeList(ctxt->doc, +@@ -2396,7 +2400,7 @@ xmlXIncludeDoProcess(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr tree) { + * First phase: lookup the elements in the document + */ + cur = tree; +- while ((cur != NULL) && (cur != tree->parent)) { ++ do { + /* TODO: need to work on entities -> stack */ + if (xmlXIncludeTestNode(ctxt, cur) == 1) { + xmlXIncludePreProcessNode(ctxt, cur); +@@ -2407,22 +2411,16 @@ xmlXIncludeDoProcess(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr tree) { + cur = cur->children; + continue; + } +- if (cur->next != NULL) { +- cur = cur->next; +- } else { +- if (cur == tree) +- break; +- do { +- cur = cur->parent; +- if ((cur == NULL) || (cur == tree->parent)) +- break; /* do */ +- if (cur->next != NULL) { +- cur = cur->next; +- break; /* do */ +- } +- } while (cur != NULL); +- } +- } ++ do { ++ if (cur == tree) ++ break; ++ if (cur->next != NULL) { ++ cur = cur->next; ++ break; ++ } ++ cur = cur->parent; ++ } while (cur != NULL); ++ } while ((cur != NULL) && (cur != tree)); + + /* + * Second Phase : collect the infosets fragments +-- +1.8.3.1 + diff --git a/Don-t-recurse-into-xi-include-children-in-xmlXInclud.patch b/Don-t-recurse-into-xi-include-children-in-xmlXInclud.patch new file mode 100644 index 0000000000000000000000000000000000000000..5e69695873904b03e32be7ab06810255462ae350 --- /dev/null +++ b/Don-t-recurse-into-xi-include-children-in-xmlXInclud.patch @@ -0,0 +1,208 @@ +From 0f9817c75b50a77c6aeb8f36801966fdadad229a Mon Sep 17 00:00:00 2001 +From: Nick Wellnhofer +Date: Wed, 10 Jun 2020 16:34:52 +0200 +Subject: [PATCH 107/139] Don't recurse into xi:include children in + xmlXIncludeDoProcess + +Otherwise, nested xi:include nodes might result in a use-after-free +if XML_PARSE_NOXINCNODE is specified. + +Found with libFuzzer and ASan. +--- + result/XInclude/fallback3.xml | 8 ++++++++ + result/XInclude/fallback3.xml.err | 0 + result/XInclude/fallback3.xml.rdr | 25 +++++++++++++++++++++++++ + result/XInclude/fallback4.xml | 10 ++++++++++ + result/XInclude/fallback4.xml.err | 0 + result/XInclude/fallback4.xml.rdr | 29 +++++++++++++++++++++++++++++ + test/XInclude/docs/fallback3.xml | 9 +++++++++ + test/XInclude/docs/fallback4.xml | 7 +++++++ + xinclude.c | 24 ++++++++++-------------- + 9 files changed, 98 insertions(+), 14 deletions(-) + create mode 100644 result/XInclude/fallback3.xml + create mode 100644 result/XInclude/fallback3.xml.err + create mode 100644 result/XInclude/fallback3.xml.rdr + create mode 100644 result/XInclude/fallback4.xml + create mode 100644 result/XInclude/fallback4.xml.err + create mode 100644 result/XInclude/fallback4.xml.rdr + create mode 100644 test/XInclude/docs/fallback3.xml + create mode 100644 test/XInclude/docs/fallback4.xml + +diff --git a/result/XInclude/fallback3.xml b/result/XInclude/fallback3.xml +new file mode 100644 +index 0000000..b423551 +--- /dev/null ++++ b/result/XInclude/fallback3.xml +@@ -0,0 +1,8 @@ ++ ++ ++ ++

something

++

really

++

simple

++
++
+diff --git a/result/XInclude/fallback3.xml.err b/result/XInclude/fallback3.xml.err +new file mode 100644 +index 0000000..e69de29 +diff --git a/result/XInclude/fallback3.xml.rdr b/result/XInclude/fallback3.xml.rdr +new file mode 100644 +index 0000000..aa2f137 +--- /dev/null ++++ b/result/XInclude/fallback3.xml.rdr +@@ -0,0 +1,25 @@ ++0 1 a 0 0 ++1 14 #text 0 1 ++ ++1 1 doc 0 0 ++2 14 #text 0 1 ++ ++2 1 p 0 0 ++3 3 #text 0 1 something ++2 15 p 0 0 ++2 14 #text 0 1 ++ ++2 1 p 0 0 ++3 3 #text 0 1 really ++2 15 p 0 0 ++2 14 #text 0 1 ++ ++2 1 p 0 0 ++3 3 #text 0 1 simple ++2 15 p 0 0 ++2 14 #text 0 1 ++ ++1 15 doc 0 0 ++1 14 #text 0 1 ++ ++0 15 a 0 0 +diff --git a/result/XInclude/fallback4.xml b/result/XInclude/fallback4.xml +new file mode 100644 +index 0000000..9883fd5 +--- /dev/null ++++ b/result/XInclude/fallback4.xml +@@ -0,0 +1,10 @@ ++ ++ ++ ++ ++

something

++

really

++

simple

++
++ ++
+diff --git a/result/XInclude/fallback4.xml.err b/result/XInclude/fallback4.xml.err +new file mode 100644 +index 0000000..e69de29 +diff --git a/result/XInclude/fallback4.xml.rdr b/result/XInclude/fallback4.xml.rdr +new file mode 100644 +index 0000000..628b951 +--- /dev/null ++++ b/result/XInclude/fallback4.xml.rdr +@@ -0,0 +1,29 @@ ++0 1 a 0 0 ++1 14 #text 0 1 ++ ++1 14 #text 0 1 ++ ++1 1 doc 0 0 ++2 14 #text 0 1 ++ ++2 1 p 0 0 ++3 3 #text 0 1 something ++2 15 p 0 0 ++2 14 #text 0 1 ++ ++2 1 p 0 0 ++3 3 #text 0 1 really ++2 15 p 0 0 ++2 14 #text 0 1 ++ ++2 1 p 0 0 ++3 3 #text 0 1 simple ++2 15 p 0 0 ++2 14 #text 0 1 ++ ++1 15 doc 0 0 ++1 14 #text 0 1 ++ ++1 14 #text 0 1 ++ ++0 15 a 0 0 +diff --git a/test/XInclude/docs/fallback3.xml b/test/XInclude/docs/fallback3.xml +new file mode 100644 +index 0000000..0c8b6c9 +--- /dev/null ++++ b/test/XInclude/docs/fallback3.xml +@@ -0,0 +1,9 @@ ++ ++ ++ ++ ++ There is no c.xml ... ++ ++ ++ ++ +diff --git a/test/XInclude/docs/fallback4.xml b/test/XInclude/docs/fallback4.xml +new file mode 100644 +index 0000000..b500a63 +--- /dev/null ++++ b/test/XInclude/docs/fallback4.xml +@@ -0,0 +1,7 @@ ++ ++ ++ ++ ++ ++ ++ +diff --git a/xinclude.c b/xinclude.c +index 461c1a5..0f1af9c 100644 +--- a/xinclude.c ++++ b/xinclude.c +@@ -2396,21 +2396,19 @@ xmlXIncludeDoProcess(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr tree) { + * First phase: lookup the elements in the document + */ + cur = tree; +- if (xmlXIncludeTestNode(ctxt, cur) == 1) +- xmlXIncludePreProcessNode(ctxt, cur); + while ((cur != NULL) && (cur != tree->parent)) { + /* TODO: need to work on entities -> stack */ +- if ((cur->children != NULL) && +- (cur->children->type != XML_ENTITY_DECL) && +- (cur->children->type != XML_XINCLUDE_START) && +- (cur->children->type != XML_XINCLUDE_END)) { +- cur = cur->children; +- if (xmlXIncludeTestNode(ctxt, cur)) +- xmlXIncludePreProcessNode(ctxt, cur); +- } else if (cur->next != NULL) { ++ if (xmlXIncludeTestNode(ctxt, cur) == 1) { ++ xmlXIncludePreProcessNode(ctxt, cur); ++ } else if ((cur->children != NULL) && ++ (cur->children->type != XML_ENTITY_DECL) && ++ (cur->children->type != XML_XINCLUDE_START) && ++ (cur->children->type != XML_XINCLUDE_END)) { ++ cur = cur->children; ++ continue; ++ } ++ if (cur->next != NULL) { + cur = cur->next; +- if (xmlXIncludeTestNode(ctxt, cur)) +- xmlXIncludePreProcessNode(ctxt, cur); + } else { + if (cur == tree) + break; +@@ -2420,8 +2418,6 @@ xmlXIncludeDoProcess(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr tree) { + break; /* do */ + if (cur->next != NULL) { + cur = cur->next; +- if (xmlXIncludeTestNode(ctxt, cur)) +- xmlXIncludePreProcessNode(ctxt, cur); + break; /* do */ + } + } while (cur != NULL); +-- +1.8.3.1 + diff --git a/Don-t-try-to-handle-namespaces-when-building-HTML-do.patch b/Don-t-try-to-handle-namespaces-when-building-HTML-do.patch new file mode 100644 index 0000000000000000000000000000000000000000..eba1670f125583a34dc5a00bd92eb216ecddde97 --- /dev/null +++ b/Don-t-try-to-handle-namespaces-when-building-HTML-do.patch @@ -0,0 +1,115 @@ +From 21ca8829a7366d72995adfeb21296d959fbb3777 Mon Sep 17 00:00:00 2001 +From: Nick Wellnhofer +Date: Sat, 25 Jul 2020 17:57:29 +0200 +Subject: [PATCH 095/139] Don't try to handle namespaces when building HTML + documents + +Don't try to resolve namespace in xmlSAX2StartElement when parsing +HTML documents. This useless operation could slow down the parser +considerably. + +Found by OSS-Fuzz. +--- + SAX2.c | 76 +++++++++++++++++++++++++++++++++--------------------------------- + 1 file changed, 38 insertions(+), 38 deletions(-) + +diff --git a/SAX2.c b/SAX2.c +index 9df0184..4450a3f 100644 +--- a/SAX2.c ++++ b/SAX2.c +@@ -1663,23 +1663,23 @@ xmlSAX2StartElement(void *ctx, const xmlChar *fullname, const xmlChar **atts) + } + } + +- /* +- * Insert all the defaulted attributes from the DTD especially namespaces +- */ +- if ((!ctxt->html) && +- ((ctxt->myDoc->intSubset != NULL) || +- (ctxt->myDoc->extSubset != NULL))) { +- xmlCheckDefaultedAttributes(ctxt, name, prefix, atts); +- } ++ if (!ctxt->html) { ++ /* ++ * Insert all the defaulted attributes from the DTD especially ++ * namespaces ++ */ ++ if ((ctxt->myDoc->intSubset != NULL) || ++ (ctxt->myDoc->extSubset != NULL)) { ++ xmlCheckDefaultedAttributes(ctxt, name, prefix, atts); ++ } + +- /* +- * process all the attributes whose name start with "xmlns" +- */ +- if (atts != NULL) { +- i = 0; +- att = atts[i++]; +- value = atts[i++]; +- if (!ctxt->html) { ++ /* ++ * process all the attributes whose name start with "xmlns" ++ */ ++ if (atts != NULL) { ++ i = 0; ++ att = atts[i++]; ++ value = atts[i++]; + while ((att != NULL) && (value != NULL)) { + if ((att[0] == 'x') && (att[1] == 'm') && (att[2] == 'l') && + (att[3] == 'n') && (att[4] == 's')) +@@ -1688,30 +1688,30 @@ xmlSAX2StartElement(void *ctx, const xmlChar *fullname, const xmlChar **atts) + att = atts[i++]; + value = atts[i++]; + } +- } +- } ++ } + +- /* +- * Search the namespace, note that since the attributes have been +- * processed, the local namespaces are available. +- */ +- ns = xmlSearchNs(ctxt->myDoc, ret, prefix); +- if ((ns == NULL) && (parent != NULL)) +- ns = xmlSearchNs(ctxt->myDoc, parent, prefix); +- if ((prefix != NULL) && (ns == NULL)) { +- ns = xmlNewNs(ret, NULL, prefix); +- xmlNsWarnMsg(ctxt, XML_NS_ERR_UNDEFINED_NAMESPACE, +- "Namespace prefix %s is not defined\n", +- prefix, NULL); +- } ++ /* ++ * Search the namespace, note that since the attributes have been ++ * processed, the local namespaces are available. ++ */ ++ ns = xmlSearchNs(ctxt->myDoc, ret, prefix); ++ if ((ns == NULL) && (parent != NULL)) ++ ns = xmlSearchNs(ctxt->myDoc, parent, prefix); ++ if ((prefix != NULL) && (ns == NULL)) { ++ ns = xmlNewNs(ret, NULL, prefix); ++ xmlNsWarnMsg(ctxt, XML_NS_ERR_UNDEFINED_NAMESPACE, ++ "Namespace prefix %s is not defined\n", ++ prefix, NULL); ++ } + +- /* +- * set the namespace node, making sure that if the default namespace +- * is unbound on a parent we simply keep it NULL +- */ +- if ((ns != NULL) && (ns->href != NULL) && +- ((ns->href[0] != 0) || (ns->prefix != NULL))) +- xmlSetNs(ret, ns); ++ /* ++ * set the namespace node, making sure that if the default namespace ++ * is unbound on a parent we simply keep it NULL ++ */ ++ if ((ns != NULL) && (ns->href != NULL) && ++ ((ns->href[0] != 0) || (ns->prefix != NULL))) ++ xmlSetNs(ret, ns); ++ } + + /* + * process all the other attributes +-- +1.8.3.1 + diff --git a/Fix-UTF-8-decoder-in-HTML-parser.patch b/Fix-UTF-8-decoder-in-HTML-parser.patch new file mode 100644 index 0000000000000000000000000000000000000000..f193916322649eedf7959279776b4edd99f47251 --- /dev/null +++ b/Fix-UTF-8-decoder-in-HTML-parser.patch @@ -0,0 +1,58 @@ +From 1493130ef24f8af2e1e70fdf12827374f670f7bf Mon Sep 17 00:00:00 2001 +From: Nick Wellnhofer +Date: Wed, 15 Jul 2020 12:54:25 +0200 +Subject: [PATCH 085/139] Fix UTF-8 decoder in HTML parser + +Reject sequences starting with a continuation byte as well as overlong +sequences like the XML parser. + +Also fixes an infinite loop in connection with previous commit 50078922 +since htmlCurrentChar would return 0 even if not at the end of the +buffer. + +Found by OSS-Fuzz. +--- + HTMLparser.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/HTMLparser.c b/HTMLparser.c +index 26ed124..d31e2ec 100644 +--- a/HTMLparser.c ++++ b/HTMLparser.c +@@ -439,6 +439,8 @@ htmlCurrentChar(xmlParserCtxtPtr ctxt, int *len) { + + c = *cur; + if (c & 0x80) { ++ if ((c & 0x40) == 0) ++ goto encoding_error; + if (cur[1] == 0) { + xmlParserInputGrow(ctxt->input, INPUT_CHUNK); + cur = ctxt->input->cur; +@@ -467,18 +469,24 @@ htmlCurrentChar(xmlParserCtxtPtr ctxt, int *len) { + val |= (cur[1] & 0x3f) << 12; + val |= (cur[2] & 0x3f) << 6; + val |= cur[3] & 0x3f; ++ if (val < 0x10000) ++ goto encoding_error; + } else { + /* 3-byte code */ + *len = 3; + val = (cur[0] & 0xf) << 12; + val |= (cur[1] & 0x3f) << 6; + val |= cur[2] & 0x3f; ++ if (val < 0x800) ++ goto encoding_error; + } + } else { + /* 2-byte code */ + *len = 2; + val = (cur[0] & 0x1f) << 6; + val |= cur[1] & 0x3f; ++ if (val < 0x80) ++ goto encoding_error; + } + if (!IS_CHAR(val)) { + htmlParseErrInt(ctxt, XML_ERR_INVALID_CHAR, +-- +1.8.3.1 + diff --git a/Fix-XInclude-regression-introduced-with-recent-commi.patch b/Fix-XInclude-regression-introduced-with-recent-commi.patch new file mode 100644 index 0000000000000000000000000000000000000000..e69cab60d5d4c68060fc1255cec8737100c02319 --- /dev/null +++ b/Fix-XInclude-regression-introduced-with-recent-commi.patch @@ -0,0 +1,128 @@ +From dba82a8c0453b7d4d138167a771c1c2988b889be Mon Sep 17 00:00:00 2001 +From: Nick Wellnhofer +Date: Sun, 16 Aug 2020 23:02:20 +0200 +Subject: [PATCH 121/139] Fix XInclude regression introduced with recent commit + +The change to xmlXIncludeLoadFallback in commit 11b57459 could +process already freed nodes if text nodes were merged after deleting +nodes with an empty fallback. + +Found by OSS-Fuzz. +--- + xinclude.c | 31 +++++++++++++++++-------------- + 1 file changed, 17 insertions(+), 14 deletions(-) + +diff --git a/xinclude.c b/xinclude.c +index 41ff4e5..ff265eb 100644 +--- a/xinclude.c ++++ b/xinclude.c +@@ -91,7 +91,8 @@ struct _xmlXIncludeCtxt { + }; + + static int +-xmlXIncludeDoProcess(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr tree); ++xmlXIncludeDoProcess(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr tree, ++ int skipRoot); + + + /************************************************************************ +@@ -732,7 +733,7 @@ xmlXIncludeRecurseDoc(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc, + */ + newctxt->parseFlags = ctxt->parseFlags; + newctxt->incTotal = ctxt->incTotal; +- xmlXIncludeDoProcess(newctxt, doc, xmlDocGetRootElement(doc)); ++ xmlXIncludeDoProcess(newctxt, doc, xmlDocGetRootElement(doc), 0); + ctxt->incTotal = newctxt->incTotal; + for (i = 0;i < ctxt->incNr;i++) { + newctxt->incTab[i]->count--; +@@ -1984,8 +1985,6 @@ xmlXIncludeLoadFallback(xmlXIncludeCtxtPtr ctxt, xmlNodePtr fallback, int nr) { + (ctxt == NULL)) + return(-1); + if (fallback->children != NULL) { +- xmlNodePtr child, next; +- + /* + * It's possible that the fallback also has 'includes' + * (Bug 129969), so we re-process the fallback just in case +@@ -1997,11 +1996,8 @@ xmlXIncludeLoadFallback(xmlXIncludeCtxtPtr ctxt, xmlNodePtr fallback, int nr) { + newctxt->base = xmlStrdup(ctxt->base); /* Inherit the base from the existing context */ + xmlXIncludeSetFlags(newctxt, ctxt->parseFlags); + newctxt->incTotal = ctxt->incTotal; +- for (child = fallback->children; child != NULL; child = next) { +- next = child->next; +- if (xmlXIncludeDoProcess(newctxt, ctxt->doc, child) < 0) +- ret = -1; +- } ++ if (xmlXIncludeDoProcess(newctxt, ctxt->doc, fallback, 1) < 0) ++ ret = -1; + ctxt->incTotal = newctxt->incTotal; + if (ctxt->nbErrors > oldNbErrors) + ret = -1; +@@ -2386,6 +2382,7 @@ xmlXIncludeTestNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) { + * @ctxt: the XInclude processing context + * @doc: an XML document + * @tree: the top of the tree to process ++ * @skipRoot: don't process the root node of the tree + * + * Implement the XInclude substitution on the XML document @doc + * +@@ -2393,13 +2390,16 @@ xmlXIncludeTestNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) { + * or the number of substitutions done. + */ + static int +-xmlXIncludeDoProcess(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr tree) { ++xmlXIncludeDoProcess(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr tree, ++ int skipRoot) { + xmlNodePtr cur; + int ret = 0; + int i, start; + + if ((doc == NULL) || (tree == NULL) || (tree->type == XML_NAMESPACE_DECL)) + return(-1); ++ if ((skipRoot) && (tree->children == NULL)) ++ return(-1); + if (ctxt == NULL) + return(-1); + +@@ -2413,7 +2413,10 @@ xmlXIncludeDoProcess(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr tree) { + /* + * First phase: lookup the elements in the document + */ +- cur = tree; ++ if (skipRoot) ++ cur = tree->children; ++ else ++ cur = tree; + do { + /* TODO: need to work on entities -> stack */ + if (xmlXIncludeTestNode(ctxt, cur) == 1) { +@@ -2521,7 +2524,7 @@ xmlXIncludeProcessTreeFlagsData(xmlNodePtr tree, int flags, void *data) { + ctxt->_private = data; + ctxt->base = xmlStrdup((xmlChar *)tree->doc->URL); + xmlXIncludeSetFlags(ctxt, flags); +- ret = xmlXIncludeDoProcess(ctxt, tree->doc, tree); ++ ret = xmlXIncludeDoProcess(ctxt, tree->doc, tree, 0); + if ((ret >= 0) && (ctxt->nbErrors > 0)) + ret = -1; + +@@ -2605,7 +2608,7 @@ xmlXIncludeProcessTreeFlags(xmlNodePtr tree, int flags) { + return(-1); + ctxt->base = xmlNodeGetBase(tree->doc, tree); + xmlXIncludeSetFlags(ctxt, flags); +- ret = xmlXIncludeDoProcess(ctxt, tree->doc, tree); ++ ret = xmlXIncludeDoProcess(ctxt, tree->doc, tree, 0); + if ((ret >= 0) && (ctxt->nbErrors > 0)) + ret = -1; + +@@ -2645,7 +2648,7 @@ xmlXIncludeProcessNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) { + if ((node == NULL) || (node->type == XML_NAMESPACE_DECL) || + (node->doc == NULL) || (ctxt == NULL)) + return(-1); +- ret = xmlXIncludeDoProcess(ctxt, node->doc, node); ++ ret = xmlXIncludeDoProcess(ctxt, node->doc, node, 0); + if ((ret >= 0) && (ctxt->nbErrors > 0)) + ret = -1; + return(ret); +-- +1.8.3.1 + diff --git a/Fix-another-memory-leak-in-xmlSchemaValAtomicType.patch b/Fix-another-memory-leak-in-xmlSchemaValAtomicType.patch new file mode 100644 index 0000000000000000000000000000000000000000..2e4ba48b72374b6d8dbacd028c1e388c61fad32d --- /dev/null +++ b/Fix-another-memory-leak-in-xmlSchemaValAtomicType.patch @@ -0,0 +1,28 @@ +From 50f18830e179f273c244d4969485c4154c81cc01 Mon Sep 17 00:00:00 2001 +From: Nick Wellnhofer +Date: Sun, 21 Jun 2020 15:21:45 +0200 +Subject: [PATCH 058/139] Fix another memory leak in xmlSchemaValAtomicType + +Don't collapse language IDs twice. + +Found with libFuzzer and ASan. +--- + xmlschemastypes.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/xmlschemastypes.c b/xmlschemastypes.c +index 1a44052..35edfd6 100644 +--- a/xmlschemastypes.c ++++ b/xmlschemastypes.c +@@ -2636,7 +2636,7 @@ xmlSchemaValAtomicType(xmlSchemaTypePtr type, const xmlChar * value, + goto return0; + } + case XML_SCHEMAS_LANGUAGE: +- if (normOnTheFly) { ++ if ((norm == NULL) && (normOnTheFly)) { + norm = xmlSchemaCollapseString(value); + if (norm != NULL) + value = norm; +-- +1.8.3.1 + diff --git a/Fix-double-free-in-XML-reader-with-XIncludes.patch b/Fix-double-free-in-XML-reader-with-XIncludes.patch new file mode 100644 index 0000000000000000000000000000000000000000..6d1a2e41b331e7231addec0219d209686f8f981f --- /dev/null +++ b/Fix-double-free-in-XML-reader-with-XIncludes.patch @@ -0,0 +1,29 @@ +From ba589adc2f86c6be9ad7e0d771d4c9b09d059b89 Mon Sep 17 00:00:00 2001 +From: Nick Wellnhofer +Date: Tue, 25 Aug 2020 23:50:39 +0200 +Subject: [PATCH 138/139] Fix double free in XML reader with XIncludes + +An XInclude with empty fallback could lead to a double free in +xmlTextReaderRead. + +Found by OSS-Fuzz. +--- + xmlreader.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/xmlreader.c b/xmlreader.c +index 6ae6e92..1ab15ba 100644 +--- a/xmlreader.c ++++ b/xmlreader.c +@@ -1491,6 +1491,8 @@ get_next_node: + (reader->node->prev->type != XML_DTD_NODE)) { + xmlNodePtr tmp = reader->node->prev; + if ((tmp->extra & NODE_IS_PRESERVED) == 0) { ++ if (oldnode == tmp) ++ oldnode = NULL; + xmlUnlinkNode(tmp); + xmlTextReaderFreeNode(reader, tmp); + } +-- +1.8.3.1 + diff --git a/Fix-exponential-runtime-and-memory-in-xi-fallback-pr.patch b/Fix-exponential-runtime-and-memory-in-xi-fallback-pr.patch new file mode 100644 index 0000000000000000000000000000000000000000..f6303b7c5143bf9f333edeb4c2939d383e8b0a2a --- /dev/null +++ b/Fix-exponential-runtime-and-memory-in-xi-fallback-pr.patch @@ -0,0 +1,317 @@ +From 1abf2967f955858764a6de5d7b7fe247cb637853 Mon Sep 17 00:00:00 2001 +From: Nick Wellnhofer +Date: Thu, 6 Aug 2020 17:51:57 +0200 +Subject: [PATCH 109/139] Fix exponential runtime and memory in xi:fallback + processing + +When creating XML_XINCLUDE_START nodes, the children of the original +xi:include node must be freed, otherwise fallback content is copied +twice, doubling runtime and memory consumption for each nested +xi:fallback/xi:include pair. + +Found with libFuzzer. +--- + result/XInclude/fallback5.xml | 51 +++++++++++++++++ + result/XInclude/fallback5.xml.rdr | 116 ++++++++++++++++++++++++++++++++++++++ + test/XInclude/docs/fallback5.xml | 83 +++++++++++++++++++++++++++ + xinclude.c | 8 +++ + 4 files changed, 258 insertions(+) + create mode 100644 result/XInclude/fallback5.xml + create mode 100644 result/XInclude/fallback5.xml.rdr + create mode 100644 test/XInclude/docs/fallback5.xml + +diff --git a/result/XInclude/fallback5.xml b/result/XInclude/fallback5.xml +new file mode 100644 +index 0000000..0ba503d +--- /dev/null ++++ b/result/XInclude/fallback5.xml +@@ -0,0 +1,51 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +diff --git a/result/XInclude/fallback5.xml.rdr b/result/XInclude/fallback5.xml.rdr +new file mode 100644 +index 0000000..0e1dab7 +--- /dev/null ++++ b/result/XInclude/fallback5.xml.rdr +@@ -0,0 +1,116 @@ ++0 1 a 0 0 ++1 14 #text 0 1 ++ ++1 14 #text 0 1 ++ ++1 1 elem 1 0 ++1 14 #text 0 1 ++ ++1 14 #text 0 1 ++ ++1 1 elem 1 0 ++1 14 #text 0 1 ++ ++1 14 #text 0 1 ++ ++1 1 elem 1 0 ++1 14 #text 0 1 ++ ++1 14 #text 0 1 ++ ++1 1 elem 1 0 ++1 14 #text 0 1 ++ ++1 14 #text 0 1 ++ ++1 1 elem 1 0 ++1 14 #text 0 1 ++ ++1 14 #text 0 1 ++ ++1 1 elem 1 0 ++1 14 #text 0 1 ++ ++1 14 #text 0 1 ++ ++1 1 elem 1 0 ++1 14 #text 0 1 ++ ++1 14 #text 0 1 ++ ++1 1 elem 1 0 ++1 14 #text 0 1 ++ ++1 14 #text 0 1 ++ ++1 1 elem 1 0 ++1 14 #text 0 1 ++ ++1 14 #text 0 1 ++ ++1 1 elem 1 0 ++1 14 #text 0 1 ++ ++1 14 #text 0 1 ++ ++1 1 elem 1 0 ++1 14 #text 0 1 ++ ++1 14 #text 0 1 ++ ++1 1 elem 1 0 ++1 14 #text 0 1 ++ ++1 14 #text 0 1 ++ ++1 1 elem 1 0 ++1 14 #text 0 1 ++ ++1 14 #text 0 1 ++ ++1 1 elem 1 0 ++1 14 #text 0 1 ++ ++1 14 #text 0 1 ++ ++1 1 elem 1 0 ++1 14 #text 0 1 ++ ++1 14 #text 0 1 ++ ++1 1 elem 1 0 ++1 14 #text 0 1 ++ ++1 14 #text 0 1 ++ ++1 14 #text 0 1 ++ ++1 14 #text 0 1 ++ ++1 14 #text 0 1 ++ ++1 14 #text 0 1 ++ ++1 14 #text 0 1 ++ ++1 14 #text 0 1 ++ ++1 14 #text 0 1 ++ ++1 14 #text 0 1 ++ ++1 14 #text 0 1 ++ ++1 14 #text 0 1 ++ ++1 14 #text 0 1 ++ ++1 14 #text 0 1 ++ ++1 14 #text 0 1 ++ ++1 14 #text 0 1 ++ ++1 14 #text 0 1 ++ ++0 15 a 0 0 +diff --git a/test/XInclude/docs/fallback5.xml b/test/XInclude/docs/fallback5.xml +new file mode 100644 +index 0000000..d3ad424 +--- /dev/null ++++ b/test/XInclude/docs/fallback5.xml +@@ -0,0 +1,83 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +diff --git a/xinclude.c b/xinclude.c +index 2917d45..5ea87ad 100644 +--- a/xinclude.c ++++ b/xinclude.c +@@ -2260,11 +2260,19 @@ xmlXIncludeIncludeNode(xmlXIncludeCtxtPtr ctxt, int nr) { + xmlUnlinkNode(cur); + xmlFreeNode(cur); + } else { ++ xmlNodePtr child, next; ++ + /* + * Change the current node as an XInclude start one, and add an + * XInclude end one + */ + cur->type = XML_XINCLUDE_START; ++ /* Remove fallback children */ ++ for (child = cur->children; child != NULL; child = next) { ++ next = child->next; ++ xmlUnlinkNode(child); ++ xmlFreeNode(child); ++ } + end = xmlNewDocNode(cur->doc, cur->ns, cur->name, NULL); + if (end == NULL) { + xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, +-- +1.8.3.1 + diff --git a/Fix-integer-overflow-in-_xmlSchemaParseGYear.patch b/Fix-integer-overflow-in-_xmlSchemaParseGYear.patch new file mode 100644 index 0000000000000000000000000000000000000000..1b6bedddff60a15236fc0fba376f028f22245d6a --- /dev/null +++ b/Fix-integer-overflow-in-_xmlSchemaParseGYear.patch @@ -0,0 +1,33 @@ +From 18425d3ad5a9bbe5c6e7fd4a9a45691e6c8862d1 Mon Sep 17 00:00:00 2001 +From: Nick Wellnhofer +Date: Sun, 21 Jun 2020 19:14:23 +0200 +Subject: [PATCH 060/139] Fix integer overflow in _xmlSchemaParseGYear + +Found with libFuzzer and UBSan. +--- + xmlschemastypes.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/xmlschemastypes.c b/xmlschemastypes.c +index 35edfd6..164db94 100644 +--- a/xmlschemastypes.c ++++ b/xmlschemastypes.c +@@ -1222,7 +1222,14 @@ _xmlSchemaParseGYear (xmlSchemaValDatePtr dt, const xmlChar **str) { + firstChar = cur; + + while ((*cur >= '0') && (*cur <= '9')) { +- dt->year = dt->year * 10 + (*cur - '0'); ++ int digit = *cur - '0'; ++ ++ if (dt->year > LONG_MAX / 10) ++ return 2; ++ dt->year *= 10; ++ if (dt->year > LONG_MAX - digit) ++ return 2; ++ dt->year += digit; + cur++; + digcnt++; + } +-- +1.8.3.1 + diff --git a/Fix-integer-overflow-in-htmlParseCharRef.patch b/Fix-integer-overflow-in-htmlParseCharRef.patch new file mode 100644 index 0000000000000000000000000000000000000000..615cf1cc00e614d841c9fa44137b71818628f64f --- /dev/null +++ b/Fix-integer-overflow-in-htmlParseCharRef.patch @@ -0,0 +1,65 @@ +From 31ca4a728cf96c9a341d0bfe489d2c0ba71dc6ff Mon Sep 17 00:00:00 2001 +From: Nick Wellnhofer +Date: Mon, 15 Jun 2020 18:47:53 +0200 +Subject: [PATCH 054/139] Fix integer overflow in htmlParseCharRef + +Fixes #115. +--- + HTMLparser.c | 27 +++++++++++++++++---------- + 1 file changed, 17 insertions(+), 10 deletions(-) + +diff --git a/HTMLparser.c b/HTMLparser.c +index 5dd62df..be7e14f 100644 +--- a/HTMLparser.c ++++ b/HTMLparser.c +@@ -3400,13 +3400,16 @@ htmlParseCharRef(htmlParserCtxtPtr ctxt) { + ((NXT(2) == 'x') || NXT(2) == 'X')) { + SKIP(3); + while (CUR != ';') { +- if ((CUR >= '0') && (CUR <= '9')) +- val = val * 16 + (CUR - '0'); +- else if ((CUR >= 'a') && (CUR <= 'f')) +- val = val * 16 + (CUR - 'a') + 10; +- else if ((CUR >= 'A') && (CUR <= 'F')) +- val = val * 16 + (CUR - 'A') + 10; +- else { ++ if ((CUR >= '0') && (CUR <= '9')) { ++ if (val < 0x110000) ++ val = val * 16 + (CUR - '0'); ++ } else if ((CUR >= 'a') && (CUR <= 'f')) { ++ if (val < 0x110000) ++ val = val * 16 + (CUR - 'a') + 10; ++ } else if ((CUR >= 'A') && (CUR <= 'F')) { ++ if (val < 0x110000) ++ val = val * 16 + (CUR - 'A') + 10; ++ } else { + htmlParseErr(ctxt, XML_ERR_INVALID_HEX_CHARREF, + "htmlParseCharRef: missing semicolon\n", + NULL, NULL); +@@ -3419,9 +3422,10 @@ htmlParseCharRef(htmlParserCtxtPtr ctxt) { + } else if ((CUR == '&') && (NXT(1) == '#')) { + SKIP(2); + while (CUR != ';') { +- if ((CUR >= '0') && (CUR <= '9')) +- val = val * 10 + (CUR - '0'); +- else { ++ if ((CUR >= '0') && (CUR <= '9')) { ++ if (val < 0x110000) ++ val = val * 10 + (CUR - '0'); ++ } else { + htmlParseErr(ctxt, XML_ERR_INVALID_DEC_CHARREF, + "htmlParseCharRef: missing semicolon\n", + NULL, NULL); +@@ -3440,6 +3444,9 @@ htmlParseCharRef(htmlParserCtxtPtr ctxt) { + */ + if (IS_CHAR(val)) { + return(val); ++ } else if (val >= 0x110000) { ++ htmlParseErr(ctxt, XML_ERR_INVALID_CHAR, ++ "htmlParseCharRef: value too large\n", NULL, NULL); + } else { + htmlParseErrInt(ctxt, XML_ERR_INVALID_CHAR, + "htmlParseCharRef: invalid xmlChar value %d\n", +-- +1.8.3.1 + diff --git a/Fix-integer-overflow-when-comparing-schema-dates.patch b/Fix-integer-overflow-when-comparing-schema-dates.patch new file mode 100644 index 0000000000000000000000000000000000000000..51c0e17c75a9b6fab7a40180f244eb1837d937ee --- /dev/null +++ b/Fix-integer-overflow-when-comparing-schema-dates.patch @@ -0,0 +1,41 @@ +From 8e7c20a1af8776677d7890f30b7a180567701a49 Mon Sep 17 00:00:00 2001 +From: Nick Wellnhofer +Date: Mon, 3 Aug 2020 17:30:41 +0200 +Subject: [PATCH 103/139] Fix integer overflow when comparing schema dates + +Found by OSS-Fuzz. +--- + xmlschemastypes.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/xmlschemastypes.c b/xmlschemastypes.c +index 4249d70..d6b9f92 100644 +--- a/xmlschemastypes.c ++++ b/xmlschemastypes.c +@@ -3691,6 +3691,8 @@ xmlSchemaCompareDurations(xmlSchemaValPtr x, xmlSchemaValPtr y) + minday = 0; + maxday = 0; + } else { ++ if (myear > LONG_MAX / 366) ++ return -2; + /* FIXME: This doesn't take leap year exceptions every 100/400 years + into account. */ + maxday = 365 * myear + (myear + 3) / 4; +@@ -4079,6 +4081,14 @@ xmlSchemaCompareDates (xmlSchemaValPtr x, xmlSchemaValPtr y) + if ((x == NULL) || (y == NULL)) + return -2; + ++ if ((x->value.date.year > LONG_MAX / 366) || ++ (x->value.date.year < LONG_MIN / 366) || ++ (y->value.date.year > LONG_MAX / 366) || ++ (y->value.date.year < LONG_MIN / 366)) { ++ /* Possible overflow when converting to days. */ ++ return -2; ++ } ++ + if (x->value.date.tz_flag) { + + if (!y->value.date.tz_flag) { +-- +1.8.3.1 + diff --git a/Fix-integer-overflow-when-parsing-min-max-Occurs.patch b/Fix-integer-overflow-when-parsing-min-max-Occurs.patch new file mode 100644 index 0000000000000000000000000000000000000000..262997b1bb13085ad29ea0489d174f755518b130 --- /dev/null +++ b/Fix-integer-overflow-when-parsing-min-max-Occurs.patch @@ -0,0 +1,55 @@ +From 070d635e771a24f33e8480fa60689a881c9fa636 Mon Sep 17 00:00:00 2001 +From: Nick Wellnhofer +Date: Sun, 21 Jun 2020 16:26:38 +0200 +Subject: [PATCH 059/139] Fix integer overflow when parsing {min,max}Occurs + +Clamp value to INT_MAX. + +Found with libFuzzer and UBSan. +--- + xmlschemas.c | 22 ++++++++++++++++++++-- + 1 file changed, 20 insertions(+), 2 deletions(-) + +diff --git a/xmlschemas.c b/xmlschemas.c +index 81c47bc..cc20063 100644 +--- a/xmlschemas.c ++++ b/xmlschemas.c +@@ -6074,7 +6074,16 @@ xmlGetMaxOccurs(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node, + return (def); + } + while ((*cur >= '0') && (*cur <= '9')) { +- ret = ret * 10 + (*cur - '0'); ++ if (ret > INT_MAX / 10) { ++ ret = INT_MAX; ++ } else { ++ int digit = *cur - '0'; ++ ret *= 10; ++ if (ret > INT_MAX - digit) ++ ret = INT_MAX; ++ else ++ ret += digit; ++ } + cur++; + } + while (IS_BLANK_CH(*cur)) +@@ -6126,7 +6135,16 @@ xmlGetMinOccurs(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node, + return (def); + } + while ((*cur >= '0') && (*cur <= '9')) { +- ret = ret * 10 + (*cur - '0'); ++ if (ret > INT_MAX / 10) { ++ ret = INT_MAX; ++ } else { ++ int digit = *cur - '0'; ++ ret *= 10; ++ if (ret > INT_MAX - digit) ++ ret = INT_MAX; ++ else ++ ret += digit; ++ } + cur++; + } + while (IS_BLANK_CH(*cur)) +-- +1.8.3.1 + diff --git a/Fix-memory-leak-in-runtest.c.patch b/Fix-memory-leak-in-runtest.c.patch new file mode 100644 index 0000000000000000000000000000000000000000..8706704736853c5d9a5f0b48d1dfe729641f6e10 --- /dev/null +++ b/Fix-memory-leak-in-runtest.c.patch @@ -0,0 +1,37 @@ +From e1c2d0adf02692fd668cfbb7025db437f1f5490b Mon Sep 17 00:00:00 2001 +From: Nick Wellnhofer +Date: Sun, 16 Aug 2020 22:22:57 +0200 +Subject: [PATCH 120/139] Fix memory leak in runtest.c + +--- + runtest.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/runtest.c b/runtest.c +index 19ed629..0f178cb 100644 +--- a/runtest.c ++++ b/runtest.c +@@ -2108,16 +2108,16 @@ errParseTest(const char *filename, const char *result, const char *err, + xmlDocDumpMemory(doc, (xmlChar **) &base, &size); + } + res = compareFileMem(result, base, size); +- if (res != 0) { +- fprintf(stderr, "Result for %s failed in %s\n", filename, result); +- return(-1); +- } + } + if (doc != NULL) { + if (base != NULL) + xmlFree((char *)base); + xmlFreeDoc(doc); + } ++ if (res != 0) { ++ fprintf(stderr, "Result for %s failed in %s\n", filename, result); ++ return(-1); ++ } + if (err != NULL) { + res = compareFileMem(err, testErrors, testErrorsSize); + if (res != 0) { +-- +1.8.3.1 + diff --git a/Fix-memory-leak-in-xmlXIncludeAddNode-error-paths.patch b/Fix-memory-leak-in-xmlXIncludeAddNode-error-paths.patch new file mode 100644 index 0000000000000000000000000000000000000000..e1987010aaf6531bed6c7c4c55361747de2aa4fe --- /dev/null +++ b/Fix-memory-leak-in-xmlXIncludeAddNode-error-paths.patch @@ -0,0 +1,52 @@ +From fbb7fa9a9ad8269834d32ff872b1477ff7b9c705 Mon Sep 17 00:00:00 2001 +From: Nick Wellnhofer +Date: Wed, 19 Aug 2020 13:13:20 +0200 +Subject: [PATCH 131/139] Fix memory leak in xmlXIncludeAddNode error paths + +Found by OSS-Fuzz. +--- + xinclude.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/xinclude.c b/xinclude.c +index 9024535..aac30d5 100644 +--- a/xinclude.c ++++ b/xinclude.c +@@ -627,8 +627,8 @@ xmlXIncludeAddNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr cur) { + xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_RECURSION, + "detected a local recursion with no xpointer in %s\n", + URL); +- if (fragment != NULL) +- xmlFree(fragment); ++ xmlFree(URL); ++ xmlFree(fragment); + return(-1); + } + +@@ -640,12 +640,15 @@ xmlXIncludeAddNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr cur) { + if (xmlStrEqual(URL, ctxt->urlTab[i])) { + xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_RECURSION, + "detected a recursion in %s\n", URL); ++ xmlFree(URL); ++ xmlFree(fragment); + return(-1); + } + } + } + + ref = xmlXIncludeNewRef(ctxt, URL, cur); ++ xmlFree(URL); + if (ref == NULL) { + return(-1); + } +@@ -653,7 +656,6 @@ xmlXIncludeAddNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr cur) { + ref->doc = NULL; + ref->xml = xml; + ref->count = 1; +- xmlFree(URL); + return(0); + } + +-- +1.8.3.1 + diff --git a/Fix-memory-leak-in-xmlXIncludeIncludeNode-error-path.patch b/Fix-memory-leak-in-xmlXIncludeIncludeNode-error-path.patch new file mode 100644 index 0000000000000000000000000000000000000000..d872d22af01be3b530225eaf1227c49d27a9dd82 --- /dev/null +++ b/Fix-memory-leak-in-xmlXIncludeIncludeNode-error-path.patch @@ -0,0 +1,33 @@ +From 5725c1153a74d997aa8ea8547574c049b040d5cb Mon Sep 17 00:00:00 2001 +From: Nick Wellnhofer +Date: Wed, 10 Jun 2020 15:11:40 +0200 +Subject: [PATCH 106/139] Fix memory leak in xmlXIncludeIncludeNode error paths + +Found with libFuzzer and ASan. +--- + xinclude.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/xinclude.c b/xinclude.c +index baeb8db..461c1a5 100644 +--- a/xinclude.c ++++ b/xinclude.c +@@ -2238,6 +2238,7 @@ xmlXIncludeIncludeNode(xmlXIncludeCtxtPtr ctxt, int nr) { + XML_XINCLUDE_MULTIPLE_ROOT, + "XInclude error: would result in multiple root nodes\n", + NULL); ++ xmlFreeNodeList(list); + return(-1); + } + } +@@ -2265,6 +2266,7 @@ xmlXIncludeIncludeNode(xmlXIncludeCtxtPtr ctxt, int nr) { + xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, + XML_XINCLUDE_BUILD_FAILED, + "failed to build node\n", NULL); ++ xmlFreeNodeList(list); + return(-1); + } + end->type = XML_XINCLUDE_END; +-- +1.8.3.1 + diff --git a/Fix-memory-leak-in-xmlXIncludeLoadDoc-error-path.patch b/Fix-memory-leak-in-xmlXIncludeLoadDoc-error-path.patch new file mode 100644 index 0000000000000000000000000000000000000000..320c1f81897a12db8a72829769467adbaab12a34 --- /dev/null +++ b/Fix-memory-leak-in-xmlXIncludeLoadDoc-error-path.patch @@ -0,0 +1,33 @@ +From ff009f991314ce8711f8a6a7f99107c10fb0a807 Mon Sep 17 00:00:00 2001 +From: Nick Wellnhofer +Date: Sat, 30 May 2020 15:32:25 +0200 +Subject: [PATCH 042/139] Fix memory leak in xmlXIncludeLoadDoc error path + +Found by OSS-Fuzz. +--- + xinclude.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/xinclude.c b/xinclude.c +index 5d44df4..baeb8db 100644 +--- a/xinclude.c ++++ b/xinclude.c +@@ -1608,6 +1608,7 @@ loaded: + XML_XINCLUDE_XPTR_RESULT, + "XPointer is not a range: #%s\n", + fragment); ++ xmlXPathFreeObject(xptr); + xmlXPathFreeContext(xptrctxt); + xmlFree(URL); + xmlFree(fragment); +@@ -1615,6 +1616,7 @@ loaded: + case XPATH_NODESET: + if ((xptr->nodesetval == NULL) || + (xptr->nodesetval->nodeNr <= 0)) { ++ xmlXPathFreeObject(xptr); + xmlXPathFreeContext(xptrctxt); + xmlFree(URL); + xmlFree(fragment); +-- +1.8.3.1 + diff --git a/Fix-memory-leak-when-shared-libxml-dll-is-unloaded.patch b/Fix-memory-leak-when-shared-libxml-dll-is-unloaded.patch new file mode 100644 index 0000000000000000000000000000000000000000..0d1274a6849231b6b3b8155ab47e07941d26c12e --- /dev/null +++ b/Fix-memory-leak-when-shared-libxml-dll-is-unloaded.patch @@ -0,0 +1,40 @@ +From c7c526d6d0f605ed090f8fc1bbede9e439d3185c Mon Sep 17 00:00:00 2001 +From: Kevin Puetz +Date: Mon, 13 Jan 2020 18:49:01 -0600 +Subject: [PATCH 021/139] Fix memory leak when shared libxml.dll is unloaded + +When a multiple modules (process/plugins) all link to libxml2.dll +they will in fact share a single loaded instance of it. +It is unsafe for any of them to call xmlCleanupParser, +as this would deinitialize the shared state and break others that might +still have ongoing use. + +However, on windows atexit is per-module (rather process-wide), so if used +*within* libxml2 it is possible to register a clean up when all users +are done and libxml2.dll is about to actually unload. + +This allows multiple plugins to link with and share libxml2 without +a premature cleanup if one is unloaded, while still cleaning up if *all* +such callers are themselves unloaded. +--- + parser.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/parser.c b/parser.c +index 43a1a0a..1ba988c 100644 +--- a/parser.c ++++ b/parser.c +@@ -14741,6 +14741,10 @@ xmlInitParser(void) { + if (xmlParserInitialized != 0) + return; + ++#if defined(WIN32) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL)) ++ atexit(xmlCleanupParser); ++#endif ++ + #ifdef LIBXML_THREAD_ENABLED + __xmlGlobalInitMutexLock(); + if (xmlParserInitialized == 0) { +-- +1.8.3.1 + diff --git a/Fix-quadratic-runtime-when-parsing-HTML-script-conte.patch b/Fix-quadratic-runtime-when-parsing-HTML-script-conte.patch new file mode 100644 index 0000000000000000000000000000000000000000..7c1fbd48121c26370aca0fbf9bdddbfedb3b6bff --- /dev/null +++ b/Fix-quadratic-runtime-when-parsing-HTML-script-conte.patch @@ -0,0 +1,62 @@ +From 500789224b59fa70d6837be5cd1edb8e2f1eccb6 Mon Sep 17 00:00:00 2001 +From: Nick Wellnhofer +Date: Sun, 12 Jul 2020 20:28:47 +0200 +Subject: [PATCH 083/139] Fix quadratic runtime when parsing HTML script + content + +If htmlParseScript returns upon hitting an invalid character, +htmlParseLookupSequence will be called again with checkIndex reset to +zero, potentially resulting in quadratic runtime. Make sure that +htmlParseScript consumes all input in one go and simply skips over +invalid characters similar to htmlParseCharDataInternal. + +Found by OSS-Fuzz. +--- + HTMLparser.c | 17 +++++++---------- + 1 file changed, 7 insertions(+), 10 deletions(-) + +diff --git a/HTMLparser.c b/HTMLparser.c +index 1dea794..26ed124 100644 +--- a/HTMLparser.c ++++ b/HTMLparser.c +@@ -2928,7 +2928,7 @@ htmlParseScript(htmlParserCtxtPtr ctxt) { + + SHRINK; + cur = CUR_CHAR(l); +- while (IS_CHAR_CH(cur)) { ++ while (cur != 0) { + if ((cur == '<') && (NXT(1) == '/')) { + /* + * One should break here, the specification is clear: +@@ -2959,7 +2959,12 @@ htmlParseScript(htmlParserCtxtPtr ctxt) { + } + } + } +- COPY_BUF(l,buf,nbchar,cur); ++ if (IS_CHAR_CH(cur)) { ++ COPY_BUF(l,buf,nbchar,cur); ++ } else { ++ htmlParseErrInt(ctxt, XML_ERR_INVALID_CHAR, ++ "Invalid char in CDATA 0x%X\n", cur); ++ } + if (nbchar >= HTML_PARSER_BIG_BUFFER_SIZE) { + buf[nbchar] = 0; + if (ctxt->sax->cdataBlock!= NULL) { +@@ -2977,14 +2982,6 @@ htmlParseScript(htmlParserCtxtPtr ctxt) { + cur = CUR_CHAR(l); + } + +- if ((!(IS_CHAR_CH(cur))) && (!((cur == 0) && (ctxt->progressive)))) { +- htmlParseErrInt(ctxt, XML_ERR_INVALID_CHAR, +- "Invalid char in CDATA 0x%X\n", cur); +- if (ctxt->input->cur < ctxt->input->end) { +- NEXT; +- } +- } +- + if ((nbchar != 0) && (ctxt->sax != NULL) && (!ctxt->disableSAX)) { + buf[nbchar] = 0; + if (ctxt->sax->cdataBlock!= NULL) { +-- +1.8.3.1 + diff --git a/Fix-undefined-behavior-in-xmlXPathTryStreamCompile.patch b/Fix-undefined-behavior-in-xmlXPathTryStreamCompile.patch new file mode 100644 index 0000000000000000000000000000000000000000..cfb67d3fd3e302f3f5039ec610444ba1ec14fbe1 --- /dev/null +++ b/Fix-undefined-behavior-in-xmlXPathTryStreamCompile.patch @@ -0,0 +1,27 @@ +From 487871b0e39bcc69ec0c1f69c30e2697712c6829 Mon Sep 17 00:00:00 2001 +From: Nick Wellnhofer +Date: Wed, 10 Jun 2020 13:23:43 +0200 +Subject: [PATCH 048/139] Fix undefined behavior in xmlXPathTryStreamCompile + +&NULL[0] is undefined behavior. +--- + xpath.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/xpath.c b/xpath.c +index 1510d69..74848cd 100644 +--- a/xpath.c ++++ b/xpath.c +@@ -14104,8 +14104,7 @@ xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) { + } + } + +- stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH, +- &namespaces[0]); ++ stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH, namespaces); + if (namespaces != NULL) { + xmlFree((xmlChar **)namespaces); + } +-- +1.8.3.1 + diff --git a/Fuzz-XInclude-engine.patch b/Fuzz-XInclude-engine.patch new file mode 100644 index 0000000000000000000000000000000000000000..ffff794ecd5a102c1bedf359b6e4466d5c82f7da --- /dev/null +++ b/Fuzz-XInclude-engine.patch @@ -0,0 +1,65 @@ +From 6c128fd58a0e4641c23a345d413672494622db1b Mon Sep 17 00:00:00 2001 +From: Nick Wellnhofer +Date: Fri, 5 Jun 2020 13:43:45 +0200 +Subject: [PATCH 111/139] Fuzz XInclude engine + +--- + xinclude.c | 15 +++++++++++++++ + 4 files changed, 28 insertions(+), 3 deletions(-) + +diff --git a/xinclude.c b/xinclude.c +index 5ea87ad..41ff4e5 100644 +--- a/xinclude.c ++++ b/xinclude.c +@@ -86,6 +86,8 @@ struct _xmlXIncludeCtxt { + xmlChar * base; /* the current xml:base */ + + void *_private; /* application data */ ++ ++ unsigned long incTotal; /* total number of processed inclusions */ + }; + + static int +@@ -729,7 +731,9 @@ xmlXIncludeRecurseDoc(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc, + * (bug 132597) + */ + newctxt->parseFlags = ctxt->parseFlags; ++ newctxt->incTotal = ctxt->incTotal; + xmlXIncludeDoProcess(newctxt, doc, xmlDocGetRootElement(doc)); ++ ctxt->incTotal = newctxt->incTotal; + for (i = 0;i < ctxt->incNr;i++) { + newctxt->incTab[i]->count--; + newctxt->incTab[i] = NULL; +@@ -1992,11 +1996,13 @@ xmlXIncludeLoadFallback(xmlXIncludeCtxtPtr ctxt, xmlNodePtr fallback, int nr) { + newctxt->_private = ctxt->_private; + newctxt->base = xmlStrdup(ctxt->base); /* Inherit the base from the existing context */ + xmlXIncludeSetFlags(newctxt, ctxt->parseFlags); ++ newctxt->incTotal = ctxt->incTotal; + for (child = fallback->children; child != NULL; child = next) { + next = child->next; + if (xmlXIncludeDoProcess(newctxt, ctxt->doc, child) < 0) + ret = -1; + } ++ ctxt->incTotal = newctxt->incTotal; + if (ctxt->nbErrors > oldNbErrors) + ret = -1; + xmlXIncludeFreeContext(newctxt); +@@ -2411,6 +2417,15 @@ xmlXIncludeDoProcess(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr tree) { + do { + /* TODO: need to work on entities -> stack */ + if (xmlXIncludeTestNode(ctxt, cur) == 1) { ++#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION ++ /* ++ * Avoid superlinear expansion by limiting the total number ++ * of replacements. ++ */ ++ if (ctxt->incTotal >= 20) ++ return(-1); ++#endif ++ ctxt->incTotal++; + xmlXIncludePreProcessNode(ctxt, cur); + } else if ((cur->children != NULL) && + (cur->children->type != XML_ENTITY_DECL) && +-- +1.8.3.1 + diff --git a/Limit-size-of-free-lists-in-XML-reader-when-fuzzing.patch b/Limit-size-of-free-lists-in-XML-reader-when-fuzzing.patch new file mode 100644 index 0000000000000000000000000000000000000000..a33649aaf5bf252ffd29f305f21a2cfe5f0ae59b --- /dev/null +++ b/Limit-size-of-free-lists-in-XML-reader-when-fuzzing.patch @@ -0,0 +1,60 @@ +From f0fd1b67fc883a24cdd039abb3d4fe4696104d72 Mon Sep 17 00:00:00 2001 +From: Nick Wellnhofer +Date: Wed, 26 Aug 2020 00:16:38 +0200 +Subject: [PATCH 139/139] Limit size of free lists in XML reader when fuzzing + +Keeping objects on a free list can hide memory errors. Only allow a +single node on free lists used by the XML reader when fuzzing. This +should hide fewer errors while still exercising the free list logic. +--- + xmlreader.c | 13 ++++++++++--- + 1 file changed, 10 insertions(+), 3 deletions(-) + +diff --git a/xmlreader.c b/xmlreader.c +index 1ab15ba..a9b9ef9 100644 +--- a/xmlreader.c ++++ b/xmlreader.c +@@ -48,6 +48,13 @@ + + #define MAX_ERR_MSG_SIZE 64000 + ++#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION ++/* Keeping free objects can hide memory errors. */ ++#define MAX_FREE_NODES 1 ++#else ++#define MAX_FREE_NODES 100 ++#endif ++ + /* + * The following VA_COPY was coded following an example in + * the Samba project. It may not be sufficient for some +@@ -365,7 +372,7 @@ xmlTextReaderFreeProp(xmlTextReaderPtr reader, xmlAttrPtr cur) { + + DICT_FREE(cur->name); + if ((reader != NULL) && (reader->ctxt != NULL) && +- (reader->ctxt->freeAttrsNr < 100)) { ++ (reader->ctxt->freeAttrsNr < MAX_FREE_NODES)) { + cur->next = reader->ctxt->freeAttrs; + reader->ctxt->freeAttrs = cur; + reader->ctxt->freeAttrsNr++; +@@ -466,7 +473,7 @@ xmlTextReaderFreeNodeList(xmlTextReaderPtr reader, xmlNodePtr cur) { + if (((cur->type == XML_ELEMENT_NODE) || + (cur->type == XML_TEXT_NODE)) && + (reader != NULL) && (reader->ctxt != NULL) && +- (reader->ctxt->freeElemsNr < 100)) { ++ (reader->ctxt->freeElemsNr < MAX_FREE_NODES)) { + cur->next = reader->ctxt->freeElems; + reader->ctxt->freeElems = cur; + reader->ctxt->freeElemsNr++; +@@ -554,7 +561,7 @@ xmlTextReaderFreeNode(xmlTextReaderPtr reader, xmlNodePtr cur) { + if (((cur->type == XML_ELEMENT_NODE) || + (cur->type == XML_TEXT_NODE)) && + (reader != NULL) && (reader->ctxt != NULL) && +- (reader->ctxt->freeElemsNr < 100)) { ++ (reader->ctxt->freeElemsNr < MAX_FREE_NODES)) { + cur->next = reader->ctxt->freeElems; + reader->ctxt->freeElems = cur; + reader->ctxt->freeElemsNr++; +-- +1.8.3.1 + diff --git a/libxml2.spec b/libxml2.spec index b189e0086a080683aed8ca5a2a59a3956d430846..ade59f4d2ea64bf96b63758a2ebe1c4ebe957954 100644 --- a/libxml2.spec +++ b/libxml2.spec @@ -1,7 +1,7 @@ Summary: Library providing XML and HTML support Name: libxml2 Version: 2.9.10 -Release: 6 +Release: 7 License: MIT Group: Development/Libraries Source: ftp://xmlsoft.org/libxml2/libxml2-%{version}.tar.gz @@ -33,6 +33,27 @@ Patch23: Limit-regexp-nesting-depth.patch Patch24: Fix-exponential-runtime-in-xmlFARecurseDeterminism.patch Patch25: Fix-more-quadratic-runtime-issues-in-HTML-push-parse.patch Patch26: Reset-HTML-parser-input-before-reporting-error.patch +Patch27: Fix-memory-leak-when-shared-libxml-dll-is-unloaded.patch +Patch28: Fix-memory-leak-in-xmlXIncludeLoadDoc-error-path.patch +Patch29: Fix-undefined-behavior-in-xmlXPathTryStreamCompile.patch +Patch30: Fix-integer-overflow-in-htmlParseCharRef.patch +Patch31: Fix-another-memory-leak-in-xmlSchemaValAtomicType.patch +Patch32: Fix-integer-overflow-when-parsing-min-max-Occurs.patch +Patch33: Fix-integer-overflow-in-_xmlSchemaParseGYear.patch +Patch34: Fix-quadratic-runtime-when-parsing-HTML-script-conte.patch +Patch35: Fix-UTF-8-decoder-in-HTML-parser.patch +Patch36: Don-t-try-to-handle-namespaces-when-building-HTML-do.patch +Patch37: Fix-integer-overflow-when-comparing-schema-dates.patch +Patch38: Fix-memory-leak-in-xmlXIncludeIncludeNode-error-path.patch +Patch39: Don-t-recurse-into-xi-include-children-in-xmlXInclud.patch +Patch40: Don-t-process-siblings-of-root-in-xmlXIncludeProcess.patch +Patch41: Fix-exponential-runtime-and-memory-in-xi-fallback-pr.patch +Patch42: Fuzz-XInclude-engine.patch +Patch43: Fix-memory-leak-in-runtest.c.patch +Patch44: Fix-XInclude-regression-introduced-with-recent-commi.patch +Patch45: Fix-memory-leak-in-xmlXIncludeAddNode-error-paths.patch +Patch46: Fix-double-free-in-XML-reader-with-XIncludes.patch +Patch47: Limit-size-of-free-lists-in-XML-reader-when-fuzzing.patch BuildRoot: %{_tmppath}/%{name}-%{version}-root BuildRequires: python2-devel @@ -224,6 +245,9 @@ rm -fr %{buildroot} %changelog +* Tue Sep 8 2020 yangzhuangzhuang - 2.9.10-7 +- Fix some issues found in fuzzing testcases + * Fri Aug 28 2020 zoulin - 2.9.10-6 - Fix more quadratic runtime issues in HTML push parse - Fix reset HTML parser input before reporting error