upgrade to upstream v2.9.12

Signed-off-by: Zhipeng Xie <xiezhipeng1@huawei.com>
This commit is contained in:
Zhipeng Xie 2021-11-10 14:10:19 +08:00
parent 7c91ca8f90
commit 41b0da9246
93 changed files with 30 additions and 8100 deletions

View File

@ -1,110 +0,0 @@
From 6b4717d61ddd8499872ff7249b6712732c8b11cb Mon Sep 17 00:00:00 2001
From: David Kilzer <ddkilzer@apple.com>
Date: Mon, 6 Jul 2020 12:36:27 +0200
Subject: [PATCH] Add regexp regression tests
- Bug 757711: heap-buffer-overflow in xmlFAParsePosCharGroup
<https://bugzilla.gnome.org/show_bug.cgi?id=757711>
- Bug 783015 - Integer-overflow in xmlFAParseQuantExact
<https://bugzilla.gnome.org/show_bug.cgi?id=783015>
(Regexptests): Add support for checking stderr output when
running regexp tests. This makes it possible to check in test
cases that fail and not see false-positive error output when
running the tests. Unlike other libxml2 test suites, if there
is no stderr output, no *.err file needs to be created.
---
Makefile.am | 12 +++++++-----
result/regexp/bug757711 | 2 ++
result/regexp/bug757711.err | 2 ++
result/regexp/bug783015 | 4 ++++
result/regexp/bug783015.err | 1 +
test/regexp/bug757711 | 1 +
test/regexp/bug783015 | 4 ++++
7 files changed, 21 insertions(+), 5 deletions(-)
create mode 100644 result/regexp/bug757711
create mode 100644 result/regexp/bug757711.err
create mode 100644 result/regexp/bug783015
create mode 100644 result/regexp/bug783015.err
create mode 100644 test/regexp/bug757711
create mode 100644 test/regexp/bug783015
diff --git a/Makefile.am b/Makefile.am
index 2a9d4709..76a834ef 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -907,14 +907,16 @@ Regexptests: testRegexp$(EXEEXT)
if [ ! -d $$i ] ; then \
if [ ! -f $(srcdir)/result/regexp/$$name ] ; then \
echo New test file $$name ; \
- $(CHECKER) $(top_builddir)/testRegexp -i $$i > $(srcdir)/result/regexp/$$name; \
+ $(CHECKER) $(top_builddir)/testRegexp -i $$i > $(srcdir)/result/regexp/$$name 2> $(srcdir)/result/regexp/$$name.err ; \
+ if [ ! -s "$(srcdir)/result/regexp/$$name.err" ] ; then rm $(srcdir)/result/regexp/$$name.err; fi ; \
grep "MORY ALLO" .memdump | grep -v "MEMORY ALLOCATED : 0";\
else \
- log=`$(CHECKER) $(top_builddir)/testRegexp -i $$i 2>&1 > result.$$name ; \
+ log=`$(CHECKER) $(top_builddir)/testRegexp -i $$i > result.$$name 2> error.$$name ; \
grep "MORY ALLO" .memdump | grep -v "MEMORY ALLOCATED : 0";\
- diff $(srcdir)/result/regexp/$$name result.$$name` ; \
- if [ -n "$$log" ] ; then echo $$name result ; echo "$$log" ; fi ; \
- rm result.$$name ; \
+ diff $(srcdir)/result/regexp/$$name result.$$name ; \
+ if [ -s "$(srcdir)/result/regexp/$$name.err" -o -s "error.$$name" ] ; then diff $(srcdir)/result/regexp/$$name.err error.$$name ; fi` ; \
+ if [ -n "$$log" ] ; then echo $$name result ; echo $$log ; fi ; \
+ rm result.$$name error.$$name ; \
fi ; fi ; done)
# Disabled for now
diff --git a/result/regexp/bug757711 b/result/regexp/bug757711
new file mode 100644
index 00000000..0991e4e2
--- /dev/null
+++ b/result/regexp/bug757711
@@ -0,0 +1,2 @@
+Regexp: [;^((-
+ failed to compile
diff --git a/result/regexp/bug757711.err b/result/regexp/bug757711.err
new file mode 100644
index 00000000..f1cae806
--- /dev/null
+++ b/result/regexp/bug757711.err
@@ -0,0 +1,2 @@
+regexp error : failed to compile: Expecting the end of a char range
+regexp error : failed to compile: xmlFAParseCharClass: ']' expected
diff --git a/result/regexp/bug783015 b/result/regexp/bug783015
new file mode 100644
index 00000000..653f6f09
--- /dev/null
+++ b/result/regexp/bug783015
@@ -0,0 +1,4 @@
+Regexp: .{2147483647}
+input: Fail
+Regexp: .{2147483648}
+ failed to compile
diff --git a/result/regexp/bug783015.err b/result/regexp/bug783015.err
new file mode 100644
index 00000000..a00edc98
--- /dev/null
+++ b/result/regexp/bug783015.err
@@ -0,0 +1 @@
+regexp error : failed to compile: Improper quantifier
diff --git a/test/regexp/bug757711 b/test/regexp/bug757711
new file mode 100644
index 00000000..29098354
--- /dev/null
+++ b/test/regexp/bug757711
@@ -0,0 +1 @@
+=>[;^((-
diff --git a/test/regexp/bug783015 b/test/regexp/bug783015
new file mode 100644
index 00000000..5c91a0f1
--- /dev/null
+++ b/test/regexp/bug783015
@@ -0,0 +1,4 @@
+# This assumes 32-bit ints.
+=>.{2147483647}
+input
+=>.{2147483648}
--
2.23.0

View File

@ -1,51 +0,0 @@
From bf22713507fe1fc3a2c4b525cf0a88c2dc87a3a2 Mon Sep 17 00:00:00 2001
From: Joel Hockey <joel.hockey@gmail.com>
Date: Sun, 16 Aug 2020 17:19:35 -0700
Subject: [PATCH] Validate UTF8 in xmlEncodeEntities
Code is currently assuming UTF-8 without validating. Truncated UTF-8
input can cause out-of-bounds array access.
Adds further checks to partial fix in 50f06b3e.
Fixes #178
Signed-off-by: guoxiaoqi <guoxiaoqi2@huawei.com>
---
entities.c | 16 +++++++++++++++-
1 file changed, 15 insertions(+), 1 deletion(-)
diff --git a/entities.c b/entities.c
index 37b99a5..1a8f86f 100644
--- a/entities.c
+++ b/entities.c
@@ -704,11 +704,25 @@ xmlEncodeEntitiesInternal(xmlDocPtr doc, const xmlChar *input, int attr) {
} else {
/*
* We assume we have UTF-8 input.
+ * It must match either:
+ * 110xxxxx 10xxxxxx
+ * 1110xxxx 10xxxxxx 10xxxxxx
+ * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
+ * That is:
+ * cur[0] is 11xxxxxx
+ * cur[1] is 10xxxxxx
+ * cur[2] is 10xxxxxx if cur[0] is 111xxxxx
+ * cur[3] is 10xxxxxx if cur[0] is 1111xxxx
+ * cur[0] is not 11111xxx
*/
char buf[11], *ptr;
int val = 0, l = 1;
- if (*cur < 0xC0) {
+ if (((cur[0] & 0xC0) != 0xC0) ||
+ ((cur[1] & 0xC0) != 0x80) ||
+ (((cur[0] & 0xE0) == 0xE0) && ((cur[2] & 0xC0) != 0x80)) ||
+ (((cur[0] & 0xF0) == 0xF0) && ((cur[3] & 0xC0) != 0x80)) ||
+ (((cur[0] & 0xF8) == 0xF8))) {
xmlEntitiesErr(XML_CHECK_NOT_UTF8,
"xmlEncodeEntities: input not UTF-8");
if (doc != NULL)
--
1.8.3.1

View File

@ -1,40 +0,0 @@
From 1098c30a040e72a4654968547f415be4e4c40fe7 Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
Date: Thu, 22 Apr 2021 19:26:28 +0200
Subject: [PATCH] Fix user-after-free with `xmllint --xinclude --dropdtd`
The --dropdtd option can leave dangling pointers in entity reference
nodes. Make sure to skip these nodes when processing XIncludes.
This also avoids scanning entity declarations and even modifying
them inadvertently during XInclude processing.
Move from a block list to an allow list approach to avoid descending
into other node types that can't contain elements.
Fixes #237.
Signed-off-by: guoxiaoqi <guoxiaoqi2@huawei.com>
---
xinclude.c | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/xinclude.c b/xinclude.c
index 1636caf..b2e6ea1 100644
--- a/xinclude.c
+++ b/xinclude.c
@@ -2430,9 +2430,8 @@ xmlXIncludeDoProcess(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr tree,
ctxt->incTotal++;
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->type == XML_DOCUMENT_NODE) ||
+ (cur->type == XML_ELEMENT_NODE))) {
cur = cur->children;
continue;
}
--
1.8.3.1

View File

@ -1,67 +0,0 @@
From 8598060bacada41a0eb09d95c97744ff4e428f8e Mon Sep 17 00:00:00 2001
From: Daniel Veillard <veillard@redhat.com>
Date: Thu, 13 May 2021 14:55:12 +0200
Subject: [PATCH] Patch for security issue CVE-2021-3541
This is relapted to parameter entities expansion and following
the line of the billion laugh attack. Somehow in that path the
counting of parameters was missed and the normal algorithm based
on entities "density" was useless.
---
parser.c | 26 ++++++++++++++++++++++++++
1 file changed, 26 insertions(+)
diff --git a/parser.c b/parser.c
index f5e5e169..c9312fa4 100644
--- a/parser.c
+++ b/parser.c
@@ -140,6 +140,7 @@ xmlParserEntityCheck(xmlParserCtxtPtr ctxt, size_t size,
xmlEntityPtr ent, size_t replacement)
{
size_t consumed = 0;
+ int i;
if ((ctxt == NULL) || (ctxt->options & XML_PARSE_HUGE))
return (0);
@@ -177,6 +178,28 @@ xmlParserEntityCheck(xmlParserCtxtPtr ctxt, size_t size,
rep = NULL;
}
}
+
+ /*
+ * Prevent entity exponential check, not just replacement while
+ * parsing the DTD
+ * The check is potentially costly so do that only once in a thousand
+ */
+ if ((ctxt->instate == XML_PARSER_DTD) && (ctxt->nbentities > 10000) &&
+ (ctxt->nbentities % 1024 == 0)) {
+ for (i = 0;i < ctxt->inputNr;i++) {
+ consumed += ctxt->inputTab[i]->consumed +
+ (ctxt->inputTab[i]->cur - ctxt->inputTab[i]->base);
+ }
+ if (ctxt->nbentities > consumed * XML_PARSER_NON_LINEAR) {
+ xmlFatalErr(ctxt, XML_ERR_ENTITY_LOOP, NULL);
+ ctxt->instate = XML_PARSER_EOF;
+ return (1);
+ }
+ consumed = 0;
+ }
+
+
+
if (replacement != 0) {
if (replacement < XML_MAX_TEXT_LENGTH)
return(0);
@@ -7963,6 +7986,9 @@ xmlParsePEReference(xmlParserCtxtPtr ctxt)
xmlChar start[4];
xmlCharEncoding enc;
+ if (xmlParserEntityCheck(ctxt, 0, entity, 0))
+ return;
+
if ((entity->etype == XML_EXTERNAL_PARAMETER_ENTITY) &&
((ctxt->options & XML_PARSE_NOENT) == 0) &&
((ctxt->options & XML_PARSE_DTDVALID) == 0) &&
--
GitLab

View File

@ -1,105 +0,0 @@
From 52649b63ebd0dc45df0c5e6b209af6f6d96515ca Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
Date: Thu, 2 Jan 2020 14:45:28 +0100
Subject: [PATCH] Check for overflow when allocating two-dimensional arrays
Found by lgtm.com
---
xmlregexp.c | 46 +++++++++++++++++++++++++++++++++++++---------
1 file changed, 37 insertions(+), 9 deletions(-)
diff --git a/xmlregexp.c b/xmlregexp.c
index 5a2deb9..0bd938f 100644
--- a/xmlregexp.c
+++ b/xmlregexp.c
@@ -26,6 +26,9 @@
#ifdef HAVE_LIMITS_H
#include <limits.h>
#endif
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
#include <libxml/tree.h>
#include <libxml/parserInternals.h>
@@ -36,6 +39,9 @@
#ifndef INT_MAX
#define INT_MAX 123456789 /* easy to flag and big enough for our needs */
#endif
+#ifndef SIZE_MAX
+#define SIZE_MAX ((size_t) -1)
+#endif
/* #define DEBUG_REGEXP_GRAPH */
/* #define DEBUG_REGEXP_EXEC */
@@ -418,6 +424,32 @@ xmlRegexpErrCompile(xmlRegParserCtxtPtr ctxt, const char *extra)
************************************************************************/
static int xmlFAComputesDeterminism(xmlRegParserCtxtPtr ctxt);
+
+/**
+ * xmlRegCalloc2:
+ * @dim1: size of first dimension
+ * @dim2: size of second dimension
+ * @elemSize: size of element
+ *
+ * Allocate a two-dimensional array and set all elements to zero.
+ *
+ * Returns the new array or NULL in case of error.
+ */
+static void*
+xmlRegCalloc2(size_t dim1, size_t dim2, size_t elemSize) {
+ size_t totalSize;
+ void *ret;
+
+ /* Check for overflow */
+ if (dim1 > SIZE_MAX / dim2 / elemSize)
+ return (NULL);
+ totalSize = dim1 * dim2 * elemSize;
+ ret = xmlMalloc(totalSize);
+ if (ret != NULL)
+ memset(ret, 0, totalSize);
+ return (ret);
+}
+
/**
* xmlRegEpxFromParse:
* @ctxt: the parser context used to build it
@@ -540,8 +572,8 @@ xmlRegEpxFromParse(xmlRegParserCtxtPtr ctxt) {
#ifdef DEBUG_COMPACTION
printf("Final: %d atoms\n", nbatoms);
#endif
- transitions = (int *) xmlMalloc((nbstates + 1) *
- (nbatoms + 1) * sizeof(int));
+ transitions = (int *) xmlRegCalloc2(nbstates + 1, nbatoms + 1,
+ sizeof(int));
if (transitions == NULL) {
xmlFree(stateRemap);
xmlFree(stringRemap);
@@ -551,7 +583,6 @@ xmlRegEpxFromParse(xmlRegParserCtxtPtr ctxt) {
xmlFree(ret);
return(NULL);
}
- memset(transitions, 0, (nbstates + 1) * (nbatoms + 1) * sizeof(int));
/*
* Allocate the transition table. The first entry for each
@@ -577,12 +608,9 @@ xmlRegEpxFromParse(xmlRegParserCtxtPtr ctxt) {
continue;
atomno = stringRemap[trans->atom->no];
if ((trans->atom->data != NULL) && (transdata == NULL)) {
- transdata = (void **) xmlMalloc(nbstates * nbatoms *
- sizeof(void *));
- if (transdata != NULL)
- memset(transdata, 0,
- nbstates * nbatoms * sizeof(void *));
- else {
+ transdata = (void **) xmlRegCalloc2(nbstates, nbatoms,
+ sizeof(void *));
+ if (transdata == NULL) {
xmlRegexpErrMemory(ctxt, "compiling regexp");
break;
}
--
1.8.3.1

View File

@ -1,41 +0,0 @@
From 5c7e0a9a4608ac442e727f6e479cf2a6dea368ec Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
Date: Tue, 11 Feb 2020 16:29:30 +0100
Subject: [PATCH] Copy some XMLReader option flags to parser context
The parser context stores some options both in the "options" bits and
extra members like "validate" or "replaceEntities". Which of these
are actually read is inconsistent, so make sure to also update the
bit field.
---
xmlreader.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/xmlreader.c b/xmlreader.c
index f3891e4..e336bc7 100644
--- a/xmlreader.c
+++ b/xmlreader.c
@@ -3848,16 +3848,20 @@ xmlTextReaderSetParserProp(xmlTextReaderPtr reader, int prop, int value) {
return(0);
case XML_PARSER_VALIDATE:
if (value != 0) {
+ ctxt->options |= XML_PARSE_DTDVALID;
ctxt->validate = 1;
reader->validate = XML_TEXTREADER_VALIDATE_DTD;
} else {
+ ctxt->options &= ~XML_PARSE_DTDVALID;
ctxt->validate = 0;
}
return(0);
case XML_PARSER_SUBST_ENTITIES:
if (value != 0) {
+ ctxt->options |= XML_PARSE_NOENT;
ctxt->replaceEntities = 1;
} else {
+ ctxt->options &= ~XML_PARSE_NOENT;
ctxt->replaceEntities = 0;
}
return(0);
--
1.8.3.1

View File

@ -1,38 +0,0 @@
From 00a86d414ba9a9e1cd588182b87518e4e3af9466 Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
Date: Sun, 16 Aug 2020 23:38:00 +0200
Subject: [PATCH] Don't add formatting newlines to XInclude nodes
---
xmlsave.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/xmlsave.c b/xmlsave.c
index f1d40b9..2225628 100644
--- a/xmlsave.c
+++ b/xmlsave.c
@@ -1049,7 +1049,9 @@ xmlNodeDumpOutputInternal(xmlSaveCtxtPtr ctxt, xmlNodePtr cur) {
while (1) {
if (cur == root)
return;
- if (ctxt->format == 1) {
+ if ((ctxt->format == 1) &&
+ (cur->type != XML_XINCLUDE_START) &&
+ (cur->type != XML_XINCLUDE_END)) {
xmlOutputBufferWrite(buf, 1, "\n");
}
if (cur->next != NULL) {
@@ -1224,7 +1226,9 @@ xmlDocContentDumpOutput(xmlSaveCtxtPtr ctxt, xmlDocPtr cur) {
else
#endif
xmlNodeDumpOutputInternal(ctxt, child);
- xmlOutputBufferWrite(buf, 1, "\n");
+ if ((child->type != XML_XINCLUDE_START) &&
+ (child->type != XML_XINCLUDE_END))
+ xmlOutputBufferWrite(buf, 1, "\n");
child = child->next;
}
}
--
1.8.3.1

View File

@ -1,99 +0,0 @@
From eddfbc38fa7e84ccd480eab3738e40d1b2c83979 Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
Date: Wed, 22 Jan 2020 22:03:45 +0100
Subject: [PATCH] Don't load external entity from xmlSAX2GetEntity
Despite the comment, I can't see a reason why external entities must be
loaded in the SAX handler. For external entities, the handler is
typically first invoked via xmlParseReference which will later load the
entity on its own if it wasn't loaded yet.
The old code also lead to duplicated SAX events which makes it
basically impossible to reuse xmlSAX2GetEntity for a custom SAX parser.
See the change to the expected test output.
Note that xmlSAX2GetEntity was loading the entity via
xmlParseCtxtExternalEntity while xmlParseReference uses
xmlParseExternalEntityPrivate. In the previous commit, the two
functions were merged, trying to compensate for some slight differences
between the two mostly identical implementations.
But the more urgent reason for this change is that xmlParseReference
has the facility to abort early when recursive entities are detected,
avoiding what could practically amount to an infinite loop.
If you want to backport this change, note that the previous three
commits are required as well:
f9ea1a24 Fix copying of entities in xmlParseReference
5c7e0a9a Copy some XMLReader option flags to parser context
1a3e584a Merge code paths loading external entities
Found by OSS-Fuzz.
---
SAX2.c | 30 ------------------------------
result/noent/ent2.sax2 | 7 -------
2 files changed, 37 deletions(-)
diff --git a/SAX2.c b/SAX2.c
index 5f141f9..6045ca1 100644
--- a/SAX2.c
+++ b/SAX2.c
@@ -590,36 +590,6 @@ xmlSAX2GetEntity(void *ctx, const xmlChar *name)
} else {
ret = xmlGetDocEntity(ctxt->myDoc, name);
}
- if ((ret != NULL) &&
- ((ctxt->validate) || (ctxt->replaceEntities)) &&
- (ret->children == NULL) &&
- (ret->etype == XML_EXTERNAL_GENERAL_PARSED_ENTITY)) {
- int val;
-
- /*
- * for validation purposes we really need to fetch and
- * parse the external entity
- */
- xmlNodePtr children;
- unsigned long oldnbent = ctxt->nbentities;
-
- val = xmlParseCtxtExternalEntity(ctxt, ret->URI,
- ret->ExternalID, &children);
- if (val == 0) {
- xmlAddChildList((xmlNodePtr) ret, children);
- } else {
- xmlFatalErrMsg(ctxt, XML_ERR_ENTITY_PROCESSING,
- "Failure to process entity %s\n", name, NULL);
- ctxt->validate = 0;
- return(NULL);
- }
- ret->owner = 1;
- if (ret->checked == 0) {
- ret->checked = (ctxt->nbentities - oldnbent + 1) * 2;
- if ((ret->content != NULL) && (xmlStrchr(ret->content, '<')))
- ret->checked |= 1;
- }
- }
return(ret);
}
diff --git a/result/noent/ent2.sax2 b/result/noent/ent2.sax2
index 88c6aa6..d17f2ff 100644
--- a/result/noent/ent2.sax2
+++ b/result/noent/ent2.sax2
@@ -17,13 +17,6 @@ SAX.characters(my title, 8)
SAX.endElementNs(title, NULL, NULL)
SAX.characters(
, 1)
-SAX.ignorableWhitespace(
-, 1)
-SAX.startElementNs(title, NULL, NULL, 0, 0, 0)
-SAX.characters(my title, 8)
-SAX.endElementNs(title, NULL, NULL)
-SAX.characters(
-, 1)
SAX.characters(
This text is about XML, the, 31)
SAX.getEntity(xml)
--
1.8.3.1

View File

@ -1,88 +0,0 @@
From 11b5745927481d6a716acef5408da20899eab8a2 Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
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

View File

@ -1,208 +0,0 @@
From 0f9817c75b50a77c6aeb8f36801966fdadad229a Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
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 @@
+<?xml version="1.0"?>
+<a>
+ <doc xml:base="../ents/something.xml">
+<p>something</p>
+<p>really</p>
+<p>simple</p>
+</doc>
+</a>
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 @@
+<?xml version="1.0"?>
+<a>
+
+ <doc xml:base="../ents/something.xml">
+<p>something</p>
+<p>really</p>
+<p>simple</p>
+</doc>
+
+</a>
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 @@
+<a>
+ <xi:include href="../ents/something.xml" xmlns:xi="http://www.w3.org/2001/XInclude">
+ <xi:fallback>
+ <xi:include href="c.xml">
+ <xi:fallback>There is no c.xml ... </xi:fallback>
+ </xi:include>
+ </xi:fallback>
+ </xi:include>
+</a>
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 @@
+<a>
+ <xi:include href="c.xml" xmlns:xi="http://www.w3.org/2001/XInclude">
+ <xi:fallback>
+ <xi:include href="../ents/something.xml"/>
+ </xi:fallback>
+ </xi:include>
+</a>
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

View File

@ -1,58 +0,0 @@
From 1493130ef24f8af2e1e70fdf12827374f670f7bf Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
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

View File

@ -1,128 +0,0 @@
From dba82a8c0453b7d4d138167a771c1c2988b889be Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
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

View File

@ -1,28 +0,0 @@
From 50f18830e179f273c244d4969485c4154c81cc01 Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
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

View File

@ -1,37 +0,0 @@
From b215c270fa3b1436314cc56654718bd12182cfec Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
Date: Sun, 13 Sep 2020 12:19:48 +0200
Subject: [PATCH] Fix cleanup of attributes in XML reader
xml:id creates ID attributes even in documents without a DTD, so the
check in xmlTextReaderFreeProp must be changed to avoid use after free.
Found by OSS-Fuzz.
---
xmlreader.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/xmlreader.c b/xmlreader.c
index a9b9ef93..01adf74f 100644
--- a/xmlreader.c
+++ b/xmlreader.c
@@ -359,12 +359,12 @@ xmlTextReaderFreeProp(xmlTextReaderPtr reader, xmlAttrPtr cur) {
xmlDeregisterNodeDefaultValue((xmlNodePtr) cur);
/* Check for ID removal -> leading to invalid references ! */
- if ((cur->parent != NULL) && (cur->parent->doc != NULL) &&
- ((cur->parent->doc->intSubset != NULL) ||
- (cur->parent->doc->extSubset != NULL))) {
+ if ((cur->parent != NULL) && (cur->parent->doc != NULL)) {
if (xmlIsID(cur->parent->doc, cur->parent, cur))
xmlTextReaderRemoveID(cur->parent->doc, cur);
- if (xmlIsRef(cur->parent->doc, cur->parent, cur))
+ if (((cur->parent->doc->intSubset != NULL) ||
+ (cur->parent->doc->extSubset != NULL)) &&
+ (xmlIsRef(cur->parent->doc, cur->parent, cur)))
xmlTextReaderRemoveRef(cur->parent->doc, cur);
}
if (cur->children != NULL)
--
2.27.0

View File

@ -1,135 +0,0 @@
From f9ea1a24ed0fd2fd051bb01b0d08cdff60887938 Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
Date: Tue, 11 Feb 2020 16:17:34 +0100
Subject: [PATCH] Fix copying of entities in xmlParseReference
Before, reader mode would end up in a branch that didn't handle
entities with multiple children and failed to update ent->last, so the
hack copying the "extra" reader data wouldn't trigger. Consequently,
some empty nodes in entities are correctly detected now in the test
suite. (The detection of empty nodes in entities is still buggy,
though.)
---
parser.c | 64 +++++++++++++++++++++++++++------------------------------
result/att7.rde | 3 +--
result/ent9.rde | 6 ++----
3 files changed, 33 insertions(+), 40 deletions(-)
diff --git a/parser.c b/parser.c
index 1ba988c..5ff8592 100644
--- a/parser.c
+++ b/parser.c
@@ -7159,42 +7159,38 @@ xmlParseReference(xmlParserCtxtPtr ctxt) {
(ent->etype == XML_EXTERNAL_GENERAL_PARSED_ENTITY))&&
(ent->children == NULL)) {
ent->children = list;
- if (ctxt->replaceEntities) {
- /*
- * Prune it directly in the generated document
- * except for single text nodes.
- */
- if (((list->type == XML_TEXT_NODE) &&
- (list->next == NULL)) ||
- (ctxt->parseMode == XML_PARSE_READER)) {
- list->parent = (xmlNodePtr) ent;
- list = NULL;
- ent->owner = 1;
- } else {
- ent->owner = 0;
- while (list != NULL) {
- list->parent = (xmlNodePtr) ctxt->node;
- list->doc = ctxt->myDoc;
- if (list->next == NULL)
- ent->last = list;
- list = list->next;
- }
- list = ent->children;
+ /*
+ * Prune it directly in the generated document
+ * except for single text nodes.
+ */
+ if ((ctxt->replaceEntities == 0) ||
+ (ctxt->parseMode == XML_PARSE_READER) ||
+ ((list->type == XML_TEXT_NODE) &&
+ (list->next == NULL))) {
+ ent->owner = 1;
+ while (list != NULL) {
+ list->parent = (xmlNodePtr) ent;
+ xmlSetTreeDoc(list, ent->doc);
+ if (list->next == NULL)
+ ent->last = list;
+ list = list->next;
+ }
+ list = NULL;
+ } else {
+ ent->owner = 0;
+ while (list != NULL) {
+ list->parent = (xmlNodePtr) ctxt->node;
+ list->doc = ctxt->myDoc;
+ if (list->next == NULL)
+ ent->last = list;
+ list = list->next;
+ }
+ list = ent->children;
#ifdef LIBXML_LEGACY_ENABLED
- if (ent->etype == XML_EXTERNAL_GENERAL_PARSED_ENTITY)
- xmlAddEntityReference(ent, list, NULL);
+ if (ent->etype == XML_EXTERNAL_GENERAL_PARSED_ENTITY)
+ xmlAddEntityReference(ent, list, NULL);
#endif /* LIBXML_LEGACY_ENABLED */
- }
- } else {
- ent->owner = 1;
- while (list != NULL) {
- list->parent = (xmlNodePtr) ent;
- xmlSetTreeDoc(list, ent->doc);
- if (list->next == NULL)
- ent->last = list;
- list = list->next;
- }
- }
+ }
} else {
xmlFreeNodeList(list);
list = NULL;
diff --git a/result/att7.rde b/result/att7.rde
index afcef5f..6079637 100644
--- a/result/att7.rde
+++ b/result/att7.rde
@@ -5,8 +5,7 @@
1 1 test 1 0
1 14 #text 0 1
-1 1 test 0 0
-1 15 test 0 0
+1 1 test 1 0
1 14 #text 0 1
0 15 x 0 0
diff --git a/result/ent9.rde b/result/ent9.rde
index 38b9f43..2206146 100644
--- a/result/ent9.rde
+++ b/result/ent9.rde
@@ -12,8 +12,7 @@
2 1 c 0 0
2 15 c 0 0
2 3 #text 0 1 ,
-2 1 d 0 0
-2 15 d 0 0
+2 1 d 1 0
1 15 ent 0 0
1 14 #text 0 1
@@ -292,8 +291,7 @@
2 1 c 0 0
2 15 c 0 0
2 3 #text 0 1 ,
-2 1 d 0 0
-2 15 d 0 0
+2 1 d 1 0
1 15 ent 0 0
1 14 #text 0 1
--
1.8.3.1

View File

@ -1,90 +0,0 @@
From d88df4bd48ba4ce9a68040a2427b4a665d5ff891 Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
Date: Sun, 16 Aug 2020 23:38:48 +0200
Subject: [PATCH] Fix corner case with empty xi:fallback
xi:fallback could become empty after recursive expansion. Use a flag
to track whether nodes should be skipped.
---
result/XInclude/fallback6.xml | 1 +
result/XInclude/fallback6.xml.rdr | 0
test/XInclude/docs/fallback6.xml | 6 ++++++
xinclude.c | 11 ++++-------
4 files changed, 11 insertions(+), 7 deletions(-)
create mode 100644 result/XInclude/fallback6.xml
create mode 100644 result/XInclude/fallback6.xml.rdr
create mode 100644 test/XInclude/docs/fallback6.xml
diff --git a/result/XInclude/fallback6.xml b/result/XInclude/fallback6.xml
new file mode 100644
index 0000000..2b5d411
--- /dev/null
+++ b/result/XInclude/fallback6.xml
@@ -0,0 +1 @@
+<?xml version="1.0"?>
diff --git a/result/XInclude/fallback6.xml.rdr b/result/XInclude/fallback6.xml.rdr
new file mode 100644
index 0000000..e69de29
diff --git a/test/XInclude/docs/fallback6.xml b/test/XInclude/docs/fallback6.xml
new file mode 100644
index 0000000..fd00a03
--- /dev/null
+++ b/test/XInclude/docs/fallback6.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0"?>
+<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="b.xml">
+ <xi:fallback><xi:include href="c.xml">
+ <xi:fallback/>
+ </xi:include></xi:fallback>
+</xi:include>
diff --git a/xinclude.c b/xinclude.c
index ff265eb..e9d3af5 100644
--- a/xinclude.c
+++ b/xinclude.c
@@ -60,7 +60,7 @@ struct _xmlXIncludeRef {
int xml; /* xml or txt */
int count; /* how many refs use that specific doc */
xmlXPathObjectPtr xptr; /* the xpointer if needed */
- int emptyFb; /* flag to show fallback empty */
+ int skip; /* skip in case of errors */
};
struct _xmlXIncludeCtxt {
@@ -2007,7 +2007,6 @@ xmlXIncludeLoadFallback(xmlXIncludeCtxtPtr ctxt, xmlNodePtr fallback, int nr) {
fallback->children);
} else {
ctxt->incTab[nr]->inc = NULL;
- ctxt->incTab[nr]->emptyFb = 1; /* flag empty callback */
}
return(ret);
}
@@ -2164,13 +2163,13 @@ xmlXIncludeLoadNode(xmlXIncludeCtxtPtr ctxt, int nr) {
((xmlStrEqual(children->ns->href, XINCLUDE_NS)) ||
(xmlStrEqual(children->ns->href, XINCLUDE_OLD_NS)))) {
ret = xmlXIncludeLoadFallback(ctxt, children, nr);
- if (ret == 0)
- break;
+ break;
}
children = children->next;
}
}
if (ret < 0) {
+ ctxt->incTab[nr]->skip = 1;
xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
XML_XINCLUDE_NO_FALLBACK,
"could not load %s, and no fallback was found\n",
@@ -2468,9 +2467,7 @@ xmlXIncludeDoProcess(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr tree,
*
*/
for (i = ctxt->incBase;i < ctxt->incNr; i++) {
- if ((ctxt->incTab[i]->inc != NULL) ||
- (ctxt->incTab[i]->xptr != NULL) ||
- (ctxt->incTab[i]->emptyFb != 0)) /* (empty fallback) */
+ if (ctxt->incTab[i]->skip == 0)
xmlXIncludeIncludeNode(ctxt, i);
}
--
1.8.3.1

View File

@ -1,25 +0,0 @@
From 72b3c067cedbb80dbbac755cca79ff502c858ad5 Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
Date: Thu, 22 Apr 2021 19:24:50 +0200
Subject: [PATCH] Fix dangling pointer with `xmllint --dropdtd`
Reset doc->intSubset when dropping the DTD.
---
xmllint.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/xmllint.c b/xmllint.c
index dbef273..a3fe10a 100644
--- a/xmllint.c
+++ b/xmllint.c
@@ -2426,6 +2426,7 @@ static void parseAndPrintFile(char *filename, xmlParserCtxtPtr rectxt) {
dtd = xmlGetIntSubset(doc);
if (dtd != NULL) {
xmlUnlinkNode((xmlNodePtr)dtd);
+ doc->intSubset = NULL;
xmlFreeDtd(dtd);
}
}
--
1.8.3.1

View File

@ -1,29 +0,0 @@
From ba589adc2f86c6be9ad7e0d771d4c9b09d059b89 Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
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

View File

@ -1,33 +0,0 @@
From 683de7efe4a4178d62fab85d8c5f4c3bed36b984 Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
Date: Thu, 4 Mar 2021 19:06:04 +0100
Subject: [PATCH] Fix duplicate xmlStrEqual calls in htmlParseEndTag
---
HTMLparser.c | 10 ++++------
1 file changed, 4 insertions(+), 6 deletions(-)
diff --git a/HTMLparser.c b/HTMLparser.c
index e63e9b7..adefb3b 100644
--- a/HTMLparser.c
+++ b/HTMLparser.c
@@ -4207,12 +4207,10 @@ htmlParseEndTag(htmlParserCtxtPtr ctxt)
* With the exception that the autoclose may have popped stuff out
* of the stack.
*/
- if (!xmlStrEqual(name, ctxt->name)) {
- if ((ctxt->name != NULL) && (!xmlStrEqual(ctxt->name, name))) {
- htmlParseErr(ctxt, XML_ERR_TAG_NAME_MISMATCH,
- "Opening and ending tag mismatch: %s and %s\n",
- name, ctxt->name);
- }
+ if ((ctxt->name != NULL) && (!xmlStrEqual(ctxt->name, name))) {
+ htmlParseErr(ctxt, XML_ERR_TAG_NAME_MISMATCH,
+ "Opening and ending tag mismatch: %s and %s\n",
+ name, ctxt->name);
}
/*
--
1.8.3.1

View File

@ -1,91 +0,0 @@
From 2c747129779be9e3ce84a2f98ce5052a68d41098 Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
Date: Mon, 17 Aug 2020 00:54:12 +0200
Subject: [PATCH] Fix error reporting with xi:fallback
When reporting errors, don't use href of xi:include if xi:fallback
was used. I think this can only be reproduced with
"xmllint --postvalid", see the original bug report:
https://bugzilla.gnome.org/show_bug.cgi?id=152623
---
error.c | 22 +++++++++++-----------
xinclude.c | 4 ++++
2 files changed, 15 insertions(+), 11 deletions(-)
diff --git a/error.c b/error.c
index 3e41e17..9ff1c2b 100644
--- a/error.c
+++ b/error.c
@@ -557,6 +557,7 @@ __xmlRaiseError(xmlStructuredErrorFunc schannel,
* of the usual "base" (doc->URL) for the node (bug 152623).
*/
xmlNodePtr prev = baseptr;
+ char *href = NULL;
int inclcount = 0;
while (prev != NULL) {
if (prev->prev == NULL)
@@ -564,21 +565,20 @@ __xmlRaiseError(xmlStructuredErrorFunc schannel,
else {
prev = prev->prev;
if (prev->type == XML_XINCLUDE_START) {
- if (--inclcount < 0)
- break;
+ if (inclcount > 0) {
+ --inclcount;
+ } else {
+ href = (char *) xmlGetProp(prev, BAD_CAST "href");
+ if (href != NULL)
+ break;
+ }
} else if (prev->type == XML_XINCLUDE_END)
inclcount++;
}
}
- if (prev != NULL) {
- if (prev->type == XML_XINCLUDE_START) {
- prev->type = XML_ELEMENT_NODE;
- to->file = (char *) xmlGetProp(prev, BAD_CAST "href");
- prev->type = XML_XINCLUDE_START;
- } else {
- to->file = (char *) xmlGetProp(prev, BAD_CAST "href");
- }
- } else
+ if (href != NULL)
+ to->file = href;
+ else
#endif
to->file = (char *) xmlStrdup(baseptr->doc->URL);
if ((to->file == NULL) && (node != NULL) && (node->doc != NULL)) {
diff --git a/xinclude.c b/xinclude.c
index 9a65ee5..2423a93 100644
--- a/xinclude.c
+++ b/xinclude.c
@@ -61,6 +61,7 @@ struct _xmlXIncludeRef {
int count; /* how many refs use that specific doc */
xmlXPathObjectPtr xptr; /* the xpointer if needed */
int skip; /* skip in case of errors */
+ int fallback; /* fallback was loaded */
};
struct _xmlXIncludeCtxt {
@@ -2007,6 +2008,7 @@ xmlXIncludeLoadFallback(xmlXIncludeCtxtPtr ctxt, xmlNodePtr fallback, int nr) {
} else {
ctxt->incTab[nr]->inc = NULL;
}
+ ctxt->incTab[nr]->fallback = 1;
return(ret);
}
@@ -2266,6 +2268,8 @@ xmlXIncludeIncludeNode(xmlXIncludeCtxtPtr ctxt, int nr) {
* Change the current node as an XInclude start one, and add an
* XInclude end one
*/
+ if (ctxt->incTab[nr]->fallback)
+ xmlUnsetProp(cur, BAD_CAST "href");
cur->type = XML_XINCLUDE_START;
end = xmlNewDocNode(cur->doc, cur->ns, cur->name, NULL);
if (end == NULL) {
--
1.8.3.1

View File

@ -1,48 +0,0 @@
From c3fd8c429591e06eb847c11bc9273d13b3450d53 Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
Date: Sat, 13 Mar 2021 17:19:32 +0100
Subject: [PATCH] Fix exponential behavior with recursive entities
Fix another case where only recursion depth was limited, but entities
would still be expanded over and over again.
The test case discovered by fuzzing only affected parsing in recovery
mode with XML_PARSE_RECOVER.
Found by OSS-Fuzz.
---
parser.c | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/parser.c b/parser.c
index efde672..b42e604 100644
--- a/parser.c
+++ b/parser.c
@@ -2684,8 +2684,10 @@ xmlStringLenDecodeEntities(xmlParserCtxtPtr ctxt, const xmlChar *str, int len,
rep = xmlStringDecodeEntities(ctxt, ent->content, what,
0, 0, 0);
ctxt->depth--;
- if (rep == NULL)
+ if (rep == NULL) {
+ ent->content[0] = 0;
goto int_error;
+ }
current = rep;
while (*current != 0) { /* non input consuming loop */
@@ -2740,8 +2742,11 @@ xmlStringLenDecodeEntities(xmlParserCtxtPtr ctxt, const xmlChar *str, int len,
rep = xmlStringDecodeEntities(ctxt, ent->content, what,
0, 0, 0);
ctxt->depth--;
- if (rep == NULL)
+ if (rep == NULL) {
+ if (ent->content != NULL)
+ ent->content[0] = 0;
goto int_error;
+ }
current = rep;
while (*current != 0) { /* non input consuming loop */
buffer[nbchars++] = *current++;
--
1.8.3.1

View File

@ -1,317 +0,0 @@
From 1abf2967f955858764a6de5d7b7fe247cb637853 Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
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 @@
+<?xml version="1.0"?>
+<a>
+
+ <elem/>
+
+ <elem/>
+
+ <elem/>
+
+ <elem/>
+
+ <elem/>
+
+ <elem/>
+
+ <elem/>
+
+ <elem/>
+
+ <elem/>
+
+ <elem/>
+
+ <elem/>
+
+ <elem/>
+
+ <elem/>
+
+ <elem/>
+
+ <elem/>
+
+ <elem/>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+</a>
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 @@
+<a>
+ <xi:include href="a01.xml" xmlns:xi="http://www.w3.org/2001/XInclude">
+ <xi:fallback>
+ <elem/>
+ <xi:include href="a02.xml">
+ <xi:fallback>
+ <elem/>
+ <xi:include href="a03.xml">
+ <xi:fallback>
+ <elem/>
+ <xi:include href="a04.xml">
+ <xi:fallback>
+ <elem/>
+ <xi:include href="a05.xml">
+ <xi:fallback>
+ <elem/>
+ <xi:include href="a06.xml">
+ <xi:fallback>
+ <elem/>
+ <xi:include href="a07.xml">
+ <xi:fallback>
+ <elem/>
+ <xi:include href="a08.xml">
+ <xi:fallback>
+ <elem/>
+ <xi:include href="a09.xml">
+ <xi:fallback>
+ <elem/>
+ <xi:include href="a10.xml">
+ <xi:fallback>
+ <elem/>
+ <xi:include href="a11.xml">
+ <xi:fallback>
+ <elem/>
+ <xi:include href="a12.xml">
+ <xi:fallback>
+ <elem/>
+ <xi:include href="a13.xml">
+ <xi:fallback>
+ <elem/>
+ <xi:include href="a14.xml">
+ <xi:fallback>
+ <elem/>
+ <xi:include href="a15.xml">
+ <xi:fallback>
+ <elem/>
+ <xi:include href="a16.xml">
+ <xi:fallback>
+ <elem/>
+ </xi:fallback>
+ </xi:include>
+ </xi:fallback>
+ </xi:include>
+ </xi:fallback>
+ </xi:include>
+ </xi:fallback>
+ </xi:include>
+ </xi:fallback>
+ </xi:include>
+ </xi:fallback>
+ </xi:include>
+ </xi:fallback>
+ </xi:include>
+ </xi:fallback>
+ </xi:include>
+ </xi:fallback>
+ </xi:include>
+ </xi:fallback>
+ </xi:include>
+ </xi:fallback>
+ </xi:include>
+ </xi:fallback>
+ </xi:include>
+ </xi:fallback>
+ </xi:include>
+ </xi:fallback>
+ </xi:include>
+ </xi:fallback>
+ </xi:include>
+ </xi:fallback>
+ </xi:include>
+</a>
+
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

View File

@ -1,81 +0,0 @@
From 68eadabd0055cba39c4ea1acfa8931d0d10a44e5 Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
Date: Sat, 11 Jul 2020 21:32:10 +0200
Subject: [PATCH] Fix exponential runtime in xmlFARecurseDeterminism
In order to prevent visiting a state twice, states must be marked as
visited for the whole duration of graph traversal because states might
be reached by different paths. Otherwise state graphs like the
following can lead to exponential runtime:
->O-->O-->O-->O-->O->
\ / \ / \ / \ /
O O O O
Reset the "visited" flag only after the graph was traversed.
xmlFAComputesDeterminism still has massive performance problems when
handling fuzzed input. By design, it has quadratic time complexity in
the number of reachable states. Some issues might also stem from
redundant epsilon transitions. With this fix, fuzzing regexes with a
maximum length of 100 becomes feasible at least.
Found with libFuzzer.
---
xmlregexp.c | 26 +++++++++++++++++++++++++-
1 file changed, 25 insertions(+), 1 deletion(-)
diff --git a/xmlregexp.c b/xmlregexp.c
index dbf3bf2c..f971f0c8 100644
--- a/xmlregexp.c
+++ b/xmlregexp.c
@@ -2658,7 +2658,6 @@ xmlFARecurseDeterminism(xmlRegParserCtxtPtr ctxt, xmlRegStatePtr state,
state->markd = XML_REGEXP_MARK_VISITED;
res = xmlFARecurseDeterminism(ctxt, ctxt->states[t1->to],
to, atom);
- state->markd = 0;
if (res == 0) {
ret = 0;
/* t1->nd = 1; */
@@ -2676,6 +2675,30 @@ xmlFARecurseDeterminism(xmlRegParserCtxtPtr ctxt, xmlRegStatePtr state,
return(ret);
}
+/**
+ * xmlFAFinishRecurseDeterminism:
+ * @ctxt: a regexp parser context
+ *
+ * Reset flags after checking determinism.
+ */
+static void
+xmlFAFinishRecurseDeterminism(xmlRegParserCtxtPtr ctxt, xmlRegStatePtr state) {
+ int transnr, nbTrans;
+
+ if (state == NULL)
+ return;
+ if (state->markd != XML_REGEXP_MARK_VISITED)
+ return;
+ state->markd = 0;
+
+ nbTrans = state->nbTrans;
+ for (transnr = 0; transnr < nbTrans; transnr++) {
+ xmlRegTransPtr t1 = &state->trans[transnr];
+ if ((t1->atom == NULL) && (t1->to >= 0))
+ xmlFAFinishRecurseDeterminism(ctxt, ctxt->states[t1->to]);
+ }
+}
+
/**
* xmlFAComputesDeterminism:
* @ctxt: a regexp parser context
@@ -2789,6 +2812,7 @@ xmlFAComputesDeterminism(xmlRegParserCtxtPtr ctxt) {
*/
ret = xmlFARecurseDeterminism(ctxt, ctxt->states[t1->to],
t2->to, t2->atom);
+ xmlFAFinishRecurseDeterminism(ctxt, ctxt->states[t1->to]);
/* don't shortcut the computation so all non deterministic
transition get marked down
if (ret == 0)
--
2.23.0

View File

@ -1,33 +0,0 @@
From 0815302dee2b78139832c2080348086a0564836b Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
Date: Fri, 6 Dec 2019 12:27:29 +0100
Subject: [PATCH] Fix freeing of nested documents
Apparently, some libxslt RVTs can contain nested document nodes, see
issue #132. I'm not sure how this happens exactly but it can cause a
segfault in xmlFreeNodeList after the changes in commit 0762c9b6.
Make sure not to touch the (nonexistent) `content` member of xmlDocs.
---
tree.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/tree.c b/tree.c
index 070670f..0d7fc98 100644
--- a/tree.c
+++ b/tree.c
@@ -3708,6 +3708,11 @@ xmlFreeNodeList(xmlNodePtr cur) {
(cur->type != XML_XINCLUDE_START) &&
(cur->type != XML_XINCLUDE_END) &&
(cur->type != XML_ENTITY_REF_NODE) &&
+ (cur->type != XML_DOCUMENT_NODE) &&
+#ifdef LIBXML_DOCB_ENABLED
+ (cur->type != XML_DOCB_DOCUMENT_NODE) &&
+#endif
+ (cur->type != XML_HTML_DOCUMENT_NODE) &&
(cur->content != (xmlChar *) &(cur->properties))) {
DICT_FREE(cur->content)
}
--
1.8.3.1

View File

@ -1,125 +0,0 @@
From de5b624f10e9d29ff1b3bbc07358774a3725898e Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
Date: Sat, 8 May 2021 20:21:29 +0200
Subject: [PATCH] Fix handling of unexpected EOF in xmlParseContent
Readd the XML_ERR_TAG_NOT_FINISHED error on unexpected EOF which was
removed in commit 62150ed2.
This commit also introduced a regression for direct users of
xmlParseContent. Unclosed tags weren't checked.
---
parser.c | 48 +++++++++++++++++++++++++++++++++++++-------
python/tests/tstLastError.py | 4 ++--
result/errors/754947.xml.err | 2 +-
3 files changed, 44 insertions(+), 10 deletions(-)
diff --git a/parser.c b/parser.c
index c2948ca..dd58282 100644
--- a/parser.c
+++ b/parser.c
@@ -9837,16 +9837,15 @@ xmlParseCDSect(xmlParserCtxtPtr ctxt) {
}
/**
- * xmlParseContent:
+ * xmlParseContentInternal:
* @ctxt: an XML parser context
*
- * Parse a content:
- *
- * [43] content ::= (element | CharData | Reference | CDSect | PI | Comment)*
+ * Parse a content sequence. Stops at EOF or '</'. Leaves checking of
+ * unexpected EOF to the caller.
*/
-void
-xmlParseContent(xmlParserCtxtPtr ctxt) {
+static void
+xmlParseContentInternal(xmlParserCtxtPtr ctxt) {
int nameNr = ctxt->nameNr;
GROW;
@@ -9922,6 +9921,30 @@ xmlParseContent(xmlParserCtxtPtr ctxt) {
}
/**
+ * xmlParseContent:
+ * @ctxt: an XML parser context
+ *
+ * Parse a content sequence. Stops at EOF or '</'.
+ *
+ * [43] content ::= (element | CharData | Reference | CDSect | PI | Comment)*
+ */
+
+void
+xmlParseContent(xmlParserCtxtPtr ctxt) {
+ int nameNr = ctxt->nameNr;
+
+ xmlParseContentInternal(ctxt);
+
+ if ((ctxt->instate != XML_PARSER_EOF) && (ctxt->nameNr > nameNr)) {
+ const xmlChar *name = ctxt->nameTab[ctxt->nameNr - 1];
+ int line = (ptrdiff_t) ctxt->pushTab[ctxt->nameNr * 4 - 2];
+ xmlFatalErrMsgStrIntStr(ctxt, XML_ERR_TAG_NOT_FINISHED,
+ "Premature end of data in tag %s line %d\n",
+ name, line, NULL);
+ }
+}
+
+/**
* xmlParseElement:
* @ctxt: an XML parser context
*
@@ -9939,9 +9962,20 @@ void
xmlParseElement(xmlParserCtxtPtr ctxt) {
if (xmlParseElementStart(ctxt) != 0)
return;
- xmlParseContent(ctxt);
+
+ xmlParseContentInternal(ctxt);
if (ctxt->instate == XML_PARSER_EOF)
return;
+
+ if (CUR == 0) {
+ const xmlChar *name = ctxt->nameTab[ctxt->nameNr - 1];
+ int line = (ptrdiff_t) ctxt->pushTab[ctxt->nameNr * 4 - 2];
+ xmlFatalErrMsgStrIntStr(ctxt, XML_ERR_TAG_NOT_FINISHED,
+ "Premature end of data in tag %s line %d\n",
+ name, line, NULL);
+ return;
+ }
+
xmlParseElementEnd(ctxt);
}
diff --git a/python/tests/tstLastError.py b/python/tests/tstLastError.py
index 1758a9f..36ffe5f 100755
--- a/python/tests/tstLastError.py
+++ b/python/tests/tstLastError.py
@@ -71,8 +71,8 @@ class TestCase(unittest.TestCase):
(s,len(s),"dummy.xml",None,0),
libxml2.treeError,
domain=libxml2.XML_FROM_PARSER,
- code=libxml2.XML_ERR_LTSLASH_REQUIRED,
- message='EndTag: \'</\' not found\n',
+ code=libxml2.XML_ERR_TAG_NOT_FINISHED,
+ message='Premature end of data in tag x line 1\n',
level=libxml2.XML_ERR_FATAL,
file='dummy.xml',
line=3)
diff --git a/result/errors/754947.xml.err b/result/errors/754947.xml.err
index 51e9b4e..f45cb5a 100644
--- a/result/errors/754947.xml.err
+++ b/result/errors/754947.xml.err
@@ -2,6 +2,6 @@
Bytes: 0xEE 0x5D 0x5D 0x3E
<d><![CDATA[0000000000000î]]>
^
-./test/errors/754947.xml:1: parser error : EndTag: '</' not found
+./test/errors/754947.xml:1: parser error : Premature end of data in tag d line 1
<d><![CDATA[0000000000000î]]>
^
--
1.8.3.1

View File

@ -1,33 +0,0 @@
From 18425d3ad5a9bbe5c6e7fd4a9a45691e6c8862d1 Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
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

View File

@ -1,65 +0,0 @@
From 31ca4a728cf96c9a341d0bfe489d2c0ba71dc6ff Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
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

View File

@ -1,45 +0,0 @@
From b07251215ef48c70c6e56f7351406c47cfca4d5b Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
Date: Fri, 10 Jan 2020 15:55:07 +0100
Subject: [PATCH] Fix integer overflow in xmlBufferResize
Found by OSS-Fuzz.
---
tree.c | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/tree.c b/tree.c
index 0d7fc98..f43f6de 100644
--- a/tree.c
+++ b/tree.c
@@ -7424,12 +7424,17 @@ xmlBufferResize(xmlBufferPtr buf, unsigned int size)
if (size < buf->size)
return 1;
+ if (size > UINT_MAX - 10) {
+ xmlTreeErrMemory("growing buffer");
+ return 0;
+ }
+
/* figure out new size */
switch (buf->alloc){
case XML_BUFFER_ALLOC_IO:
case XML_BUFFER_ALLOC_DOUBLEIT:
/*take care of empty case*/
- newSize = (buf->size ? buf->size*2 : size + 10);
+ newSize = (buf->size ? buf->size : size + 10);
while (size > newSize) {
if (newSize > UINT_MAX / 2) {
xmlTreeErrMemory("growing buffer");
@@ -7445,7 +7450,7 @@ xmlBufferResize(xmlBufferPtr buf, unsigned int size)
if (buf->use < BASE_BUFFER_SIZE)
newSize = size;
else {
- newSize = buf->size * 2;
+ newSize = buf->size;
while (size > newSize) {
if (newSize > UINT_MAX / 2) {
xmlTreeErrMemory("growing buffer");
--
1.8.3.1

View File

@ -1,44 +0,0 @@
From 1e7851b5aea4b2d8b9a6b6c02187fc4786f7a8b7 Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
Date: Thu, 25 Jun 2020 12:17:50 +0200
Subject: [PATCH] Fix integer overflow in xmlFAParseQuantExact
Found by OSS-Fuzz.
---
xmlregexp.c | 15 +++++++++++++--
1 file changed, 13 insertions(+), 2 deletions(-)
diff --git a/xmlregexp.c b/xmlregexp.c
index 53fa145c..0272dcab 100644
--- a/xmlregexp.c
+++ b/xmlregexp.c
@@ -5211,13 +5211,24 @@ static int
xmlFAParseQuantExact(xmlRegParserCtxtPtr ctxt) {
int ret = 0;
int ok = 0;
+ int overflow = 0;
while ((CUR >= '0') && (CUR <= '9')) {
- ret = ret * 10 + (CUR - '0');
+ if (ret > INT_MAX / 10) {
+ overflow = 1;
+ } else {
+ int digit = CUR - '0';
+
+ ret *= 10;
+ if (ret > INT_MAX - digit)
+ overflow = 1;
+ else
+ ret += digit;
+ }
ok = 1;
NEXT;
}
- if (ok != 1) {
+ if ((ok != 1) || (overflow == 1)) {
return(-1);
}
return(ret);
--
2.23.0

View File

@ -1,41 +0,0 @@
From 8e7c20a1af8776677d7890f30b7a180567701a49 Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
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

View File

@ -1,55 +0,0 @@
From 070d635e771a24f33e8480fa60689a881c9fa636 Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
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

View File

@ -1,162 +0,0 @@
From 3e80560d4bbf2768c90b9a017743ec45f26c3c1c Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
Date: Fri, 7 May 2021 10:51:38 +0200
Subject: [PATCH] Fix line numbers in error messages for mismatched tags
Commit 62150ed2 introduced a small regression in the error messages for
mismatched tags. This typically only affected messages after the first
mismatch, but with custom SAX handlers all line numbers would be off.
This also fixes line numbers in the SAX push parser which were never
handled correctly.
---
parser.c | 38 +++++++++++++++++++++++---------------
python/tests/ctxterror.py | 2 +-
result/errors/759398.xml.err | 4 ++--
3 files changed, 26 insertions(+), 18 deletions(-)
diff --git a/parser.c b/parser.c
index 73c27ed..c2948ca 100644
--- a/parser.c
+++ b/parser.c
@@ -1838,6 +1838,8 @@ nodePop(xmlParserCtxtPtr ctxt)
* @value: the element name
* @prefix: the element prefix
* @URI: the element namespace name
+ * @line: the current line number for error messages
+ * @nsNr: the number of namespaces pushed on the namespace table
*
* Pushes a new element name/prefix/URL on top of the name stack
*
@@ -1845,7 +1847,7 @@ nodePop(xmlParserCtxtPtr ctxt)
*/
static int
nameNsPush(xmlParserCtxtPtr ctxt, const xmlChar * value,
- const xmlChar *prefix, const xmlChar *URI, int nsNr)
+ const xmlChar *prefix, const xmlChar *URI, int line, int nsNr)
{
if (ctxt->nameNr >= ctxt->nameMax) {
const xmlChar * *tmp;
@@ -1860,7 +1862,7 @@ nameNsPush(xmlParserCtxtPtr ctxt, const xmlChar * value,
}
ctxt->nameTab = tmp;
tmp2 = (void **) xmlRealloc((void * *)ctxt->pushTab,
- ctxt->nameMax * 3 *
+ ctxt->nameMax * 4 *
sizeof(ctxt->pushTab[0]));
if (tmp2 == NULL) {
ctxt->nameMax /= 2;
@@ -1868,16 +1870,17 @@ nameNsPush(xmlParserCtxtPtr ctxt, const xmlChar * value,
}
ctxt->pushTab = tmp2;
} else if (ctxt->pushTab == NULL) {
- ctxt->pushTab = (void **) xmlMalloc(ctxt->nameMax * 3 *
+ ctxt->pushTab = (void **) xmlMalloc(ctxt->nameMax * 4 *
sizeof(ctxt->pushTab[0]));
if (ctxt->pushTab == NULL)
goto mem_error;
}
ctxt->nameTab[ctxt->nameNr] = value;
ctxt->name = value;
- ctxt->pushTab[ctxt->nameNr * 3] = (void *) prefix;
- ctxt->pushTab[ctxt->nameNr * 3 + 1] = (void *) URI;
- ctxt->pushTab[ctxt->nameNr * 3 + 2] = (void *) (ptrdiff_t) nsNr;
+ ctxt->pushTab[ctxt->nameNr * 4] = (void *) prefix;
+ ctxt->pushTab[ctxt->nameNr * 4 + 1] = (void *) URI;
+ ctxt->pushTab[ctxt->nameNr * 4 + 2] = (void *) (ptrdiff_t) line;
+ ctxt->pushTab[ctxt->nameNr * 4 + 3] = (void *) (ptrdiff_t) nsNr;
return (ctxt->nameNr++);
mem_error:
xmlErrMemory(ctxt, NULL);
@@ -9998,7 +10001,7 @@ xmlParseElementStart(xmlParserCtxtPtr ctxt) {
return(-1);
}
if (ctxt->sax2)
- nameNsPush(ctxt, name, prefix, URI, ctxt->nsNr - nsNr);
+ nameNsPush(ctxt, name, prefix, URI, line, ctxt->nsNr - nsNr);
#ifdef LIBXML_SAX1_ENABLED
else
namePush(ctxt, name);
@@ -10095,10 +10098,11 @@ xmlParseElementEnd(xmlParserCtxtPtr ctxt) {
* parse the end of tag: '</' should be here.
*/
if (ctxt->sax2) {
- const xmlChar *prefix = ctxt->pushTab[ctxt->nameNr * 3 - 3];
- const xmlChar *URI = ctxt->pushTab[ctxt->nameNr * 3 - 2];
- int nsNr = (ptrdiff_t) ctxt->pushTab[ctxt->nameNr * 3 - 1];
- xmlParseEndTag2(ctxt, prefix, URI, 0, nsNr, 0);
+ const xmlChar *prefix = ctxt->pushTab[ctxt->nameNr * 4 - 4];
+ const xmlChar *URI = ctxt->pushTab[ctxt->nameNr * 4 - 3];
+ int line = (ptrdiff_t) ctxt->pushTab[ctxt->nameNr * 4 - 2];
+ int nsNr = (ptrdiff_t) ctxt->pushTab[ctxt->nameNr * 4 - 1];
+ xmlParseEndTag2(ctxt, prefix, URI, line, nsNr, 0);
namePop(ctxt);
}
#ifdef LIBXML_SAX1_ENABLED
@@ -11373,6 +11377,7 @@ xmlParseTryOrFinish(xmlParserCtxtPtr ctxt, int terminate) {
const xmlChar *name;
const xmlChar *prefix = NULL;
const xmlChar *URI = NULL;
+ int line = ctxt->input->line;
int nsNr = ctxt->nsNr;
if ((avail < 2) && (ctxt->inputNr == 1))
@@ -11471,7 +11476,8 @@ xmlParseTryOrFinish(xmlParserCtxtPtr ctxt, int terminate) {
spacePop(ctxt);
}
if (ctxt->sax2)
- nameNsPush(ctxt, name, prefix, URI, ctxt->nsNr - nsNr);
+ nameNsPush(ctxt, name, prefix, URI, line,
+ ctxt->nsNr - nsNr);
#ifdef LIBXML_SAX1_ENABLED
else
namePush(ctxt, name);
@@ -11593,10 +11599,12 @@ xmlParseTryOrFinish(xmlParserCtxtPtr ctxt, int terminate) {
}
if (ctxt->sax2) {
xmlParseEndTag2(ctxt,
- (void *) ctxt->pushTab[ctxt->nameNr * 3 - 3],
- (void *) ctxt->pushTab[ctxt->nameNr * 3 - 2], 0,
+ (void *) ctxt->pushTab[ctxt->nameNr * 4 - 4],
+ (void *) ctxt->pushTab[ctxt->nameNr * 4 - 3],
+ (int) (ptrdiff_t)
+ ctxt->pushTab[ctxt->nameNr * 4 - 2],
(int) (ptrdiff_t)
- ctxt->pushTab[ctxt->nameNr * 3 - 1], 0);
+ ctxt->pushTab[ctxt->nameNr * 4 - 1], 0);
nameNsPop(ctxt);
}
#ifdef LIBXML_SAX1_ENABLED
diff --git a/python/tests/ctxterror.py b/python/tests/ctxterror.py
index 416e384..ac64624 100755
--- a/python/tests/ctxterror.py
+++ b/python/tests/ctxterror.py
@@ -10,7 +10,7 @@ import libxml2
libxml2.debugMemory(1)
expect="""--> (3) xmlns: URI foo is not absolute
---> (4) Opening and ending tag mismatch: x line 0 and y
+--> (4) Opening and ending tag mismatch: x line 1 and y
"""
err=""
diff --git a/result/errors/759398.xml.err b/result/errors/759398.xml.err
index bc9e5e0..f6036a3 100644
--- a/result/errors/759398.xml.err
+++ b/result/errors/759398.xml.err
@@ -1,10 +1,10 @@
./test/errors/759398.xml:210: parser error : StartTag: invalid element name
need to worry about parsers whi<! don't expand PErefs finding
^
-./test/errors/759398.xml:309: parser error : Opening and ending tag mismatch: №№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№m line 205 and termdef
+./test/errors/759398.xml:309: parser error : Opening and ending tag mismatch: №№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№m line 308 and termdef
and provide access to their content and structure.</termdef> <termdef
^
-./test/errors/759398.xml:314: parser error : Opening and ending tag mismatch: spec line 205 and p
+./test/errors/759398.xml:314: parser error : Opening and ending tag mismatch: spec line 50 and p
data and the information it must provide to the application.</p>
^
./test/errors/759398.xml:316: parser error : Extra content at the end of the document
--
1.8.3.1

View File

@ -1,67 +0,0 @@
From d5f2f74d0f0e7906eabb32c57e09a13ac3e578a2 Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
Date: Mon, 11 Nov 2019 11:27:40 +0100
Subject: [PATCH] Fix memory leak in error path of XPath expr parser
Also propagate memory errors.
Found by OSS-Fuzz.
---
xpath.c | 20 ++++++++++++++++----
1 file changed, 16 insertions(+), 4 deletions(-)
diff --git a/xpath.c b/xpath.c
index 9f64ab9..ff1137f 100644
--- a/xpath.c
+++ b/xpath.c
@@ -10088,6 +10088,7 @@ xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
int ok = 0;
int exponent = 0;
int is_exponent_negative = 0;
+ xmlXPathObjectPtr num;
#ifdef __GNUC__
unsigned long tmp = 0;
double temp;
@@ -10160,8 +10161,13 @@ xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
exponent = -exponent;
ret *= pow(10.0, (double) exponent);
}
- PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
- xmlXPathCacheNewFloat(ctxt->context, ret), NULL);
+ num = xmlXPathCacheNewFloat(ctxt->context, ret);
+ if (num == NULL) {
+ ctxt->error = XPATH_MEMORY_ERROR;
+ } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0, num,
+ NULL) == -1) {
+ xmlXPathReleaseObject(ctxt->context, num);
+ }
}
/**
@@ -10223,6 +10229,7 @@ static void
xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
const xmlChar *q;
xmlChar *ret = NULL;
+ xmlXPathObjectPtr lit;
if (CUR == '"') {
NEXT;
@@ -10250,8 +10257,13 @@ xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
XP_ERROR(XPATH_START_LITERAL_ERROR);
}
if (ret == NULL) return;
- PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
- xmlXPathCacheNewString(ctxt->context, ret), NULL);
+ lit = xmlXPathCacheNewString(ctxt->context, ret);
+ if (lit == NULL) {
+ ctxt->error = XPATH_MEMORY_ERROR;
+ } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0, lit,
+ NULL) == -1) {
+ xmlXPathReleaseObject(ctxt->context, lit);
+ }
xmlFree(ret);
}
--
1.8.3.1

View File

@ -1,37 +0,0 @@
From e1c2d0adf02692fd668cfbb7025db437f1f5490b Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
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

View File

@ -1,52 +0,0 @@
From fbb7fa9a9ad8269834d32ff872b1477ff7b9c705 Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
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

View File

@ -1,33 +0,0 @@
From 5725c1153a74d997aa8ea8547574c049b040d5cb Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
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

View File

@ -1,33 +0,0 @@
From ff009f991314ce8711f8a6a7f99107c10fb0a807 Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
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

View File

@ -1,40 +0,0 @@
From c7c526d6d0f605ed090f8fc1bbede9e439d3185c Mon Sep 17 00:00:00 2001
From: Kevin Puetz <PuetzKevinA@JohnDeere.com>
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

View File

@ -1,102 +0,0 @@
From 46837d47d59c7b8c9bd1d08a6a717a90a7f1ceb6 Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
Date: Sat, 3 Oct 2020 01:13:35 +0200
Subject: [PATCH] Fix memory leaks in XPointer string-range function
Found by OSS-Fuzz.
---
xpointer.c | 41 +++++++++++++++++++++++++++--------------
1 file changed, 27 insertions(+), 14 deletions(-)
diff --git a/xpointer.c b/xpointer.c
index 53def72..ad2c288 100644
--- a/xpointer.c
+++ b/xpointer.c
@@ -2706,10 +2706,10 @@ static void
xmlXPtrStringRangeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
int i, startindex, endindex = 0, fendindex;
xmlNodePtr start, end = 0, fend;
- xmlXPathObjectPtr set;
+ xmlXPathObjectPtr set = NULL;
xmlLocationSetPtr oldset;
- xmlLocationSetPtr newset;
- xmlXPathObjectPtr string;
+ xmlLocationSetPtr newset = NULL;
+ xmlXPathObjectPtr string = NULL;
xmlXPathObjectPtr position = NULL;
xmlXPathObjectPtr number = NULL;
int found, pos = 0, num = 0;
@@ -2721,29 +2721,39 @@ xmlXPtrStringRangeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
XP_ERROR(XPATH_INVALID_ARITY);
if (nargs >= 4) {
- CHECK_TYPE(XPATH_NUMBER);
+ if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_NUMBER)) {
+ xmlXPathErr(ctxt, XPATH_INVALID_TYPE);
+ goto error;
+ }
number = valuePop(ctxt);
if (number != NULL)
num = (int) number->floatval;
}
if (nargs >= 3) {
- CHECK_TYPE(XPATH_NUMBER);
+ if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_NUMBER)) {
+ xmlXPathErr(ctxt, XPATH_INVALID_TYPE);
+ goto error;
+ }
position = valuePop(ctxt);
if (position != NULL)
pos = (int) position->floatval;
}
- CHECK_TYPE(XPATH_STRING);
+ if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_STRING)) {
+ xmlXPathErr(ctxt, XPATH_INVALID_TYPE);
+ goto error;
+ }
string = valuePop(ctxt);
if ((ctxt->value == NULL) ||
((ctxt->value->type != XPATH_LOCATIONSET) &&
- (ctxt->value->type != XPATH_NODESET)))
- XP_ERROR(XPATH_INVALID_TYPE)
-
+ (ctxt->value->type != XPATH_NODESET))) {
+ xmlXPathErr(ctxt, XPATH_INVALID_TYPE);
+ goto error;
+ }
set = valuePop(ctxt);
newset = xmlXPtrLocationSetCreate(NULL);
if (newset == NULL) {
- xmlXPathFreeObject(set);
- XP_ERROR(XPATH_MEMORY_ERROR);
+ xmlXPathErr(ctxt, XPATH_MEMORY_ERROR);
+ goto error;
}
if (set->nodesetval == NULL) {
goto error;
@@ -2756,8 +2766,10 @@ xmlXPtrStringRangeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
*/
tmp = xmlXPtrNewLocationSetNodeSet(set->nodesetval);
xmlXPathFreeObject(set);
- if (tmp == NULL)
- XP_ERROR(XPATH_MEMORY_ERROR)
+ if (tmp == NULL) {
+ xmlXPathErr(ctxt, XPATH_MEMORY_ERROR);
+ goto error;
+ }
set = tmp;
}
oldset = (xmlLocationSetPtr) set->user;
@@ -2830,7 +2842,8 @@ xmlXPtrStringRangeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
* Save the new value and cleanup
*/
error:
- valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
+ if (newset != NULL)
+ valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
xmlXPathFreeObject(set);
xmlXPathFreeObject(string);
if (position) xmlXPathFreeObject(position);
--
1.8.3.1

View File

@ -1,79 +0,0 @@
From 42942066e1f6422e26cd162a6014b19ac215083f Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
Date: Mon, 11 Nov 2019 13:49:11 +0100
Subject: [PATCH] Fix memory leaks of encoding handlers in xmlsave.c
Fix leak of iconv/ICU encoding handler in xmlSaveToBuffer.
Fix leaks of iconv/ICU encoding handlers in xmlSaveTo* error paths.
Closes #127.
---
xmlsave.c | 26 ++++++++------------------
1 file changed, 8 insertions(+), 18 deletions(-)
diff --git a/xmlsave.c b/xmlsave.c
index fa00915..7158c26 100644
--- a/xmlsave.c
+++ b/xmlsave.c
@@ -1802,6 +1802,7 @@ xmlSaveToFd(int fd, const char *encoding, int options)
if (ret == NULL) return(NULL);
ret->buf = xmlOutputBufferCreateFd(fd, ret->handler);
if (ret->buf == NULL) {
+ xmlCharEncCloseFunc(ret->handler);
xmlFreeSaveCtxt(ret);
return(NULL);
}
@@ -1831,6 +1832,7 @@ xmlSaveToFilename(const char *filename, const char *encoding, int options)
ret->buf = xmlOutputBufferCreateFilename(filename, ret->handler,
compression);
if (ret->buf == NULL) {
+ xmlCharEncCloseFunc(ret->handler);
xmlFreeSaveCtxt(ret);
return(NULL);
}
@@ -1853,28 +1855,15 @@ xmlSaveCtxtPtr
xmlSaveToBuffer(xmlBufferPtr buffer, const char *encoding, int options)
{
xmlSaveCtxtPtr ret;
- xmlOutputBufferPtr out_buff;
- xmlCharEncodingHandlerPtr handler;
ret = xmlNewSaveCtxt(encoding, options);
if (ret == NULL) return(NULL);
-
- if (encoding != NULL) {
- handler = xmlFindCharEncodingHandler(encoding);
- if (handler == NULL) {
- xmlFree(ret);
- return(NULL);
- }
- } else
- handler = NULL;
- out_buff = xmlOutputBufferCreateBuffer(buffer, handler);
- if (out_buff == NULL) {
- xmlFree(ret);
- if (handler) xmlCharEncCloseFunc(handler);
- return(NULL);
+ ret->buf = xmlOutputBufferCreateBuffer(buffer, ret->handler);
+ if (ret->buf == NULL) {
+ xmlCharEncCloseFunc(ret->handler);
+ xmlFreeSaveCtxt(ret);
+ return(NULL);
}
-
- ret->buf = out_buff;
return(ret);
}
@@ -1902,6 +1891,7 @@ xmlSaveToIO(xmlOutputWriteCallback iowrite,
if (ret == NULL) return(NULL);
ret->buf = xmlOutputBufferCreateIO(iowrite, ioclose, ioctx, ret->handler);
if (ret->buf == NULL) {
+ xmlCharEncCloseFunc(ret->handler);
xmlFreeSaveCtxt(ret);
return(NULL);
}
--
1.8.3.1

View File

@ -1,76 +0,0 @@
From 2c80fc911678adc9dcf252b3bc71cce101c8728e Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
Date: Mon, 2 Dec 2019 11:30:30 +0100
Subject: [PATCH] Fix more memory leaks in error paths of XPath parser
Found by OSS-Fuzz.
---
xpath.c | 24 +++++++++++++++---------
1 file changed, 15 insertions(+), 9 deletions(-)
diff --git a/xpath.c b/xpath.c
index ff1137f..030bab3 100644
--- a/xpath.c
+++ b/xpath.c
@@ -10300,8 +10300,10 @@ xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
XP_ERROR(XPATH_VARIABLE_REF_ERROR);
}
ctxt->comp->last = -1;
- PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
- name, prefix);
+ if (PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0, name, prefix) == -1) {
+ xmlFree(prefix);
+ xmlFree(name);
+ }
SKIP_BLANKS;
if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
@@ -10408,8 +10410,10 @@ xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
SKIP_BLANKS;
}
}
- PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
- name, prefix);
+ if (PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0, name, prefix) == -1) {
+ xmlFree(prefix);
+ xmlFree(name);
+ }
NEXT;
SKIP_BLANKS;
}
@@ -11050,7 +11054,7 @@ xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
*/
static xmlChar *
xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
- xmlXPathTypeVal *type, const xmlChar **prefix,
+ xmlXPathTypeVal *type, xmlChar **prefix,
xmlChar *name) {
int blanks;
@@ -11281,7 +11285,7 @@ xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
SKIP_BLANKS;
} else {
xmlChar *name = NULL;
- const xmlChar *prefix = NULL;
+ xmlChar *prefix = NULL;
xmlXPathTestVal test = (xmlXPathTestVal) 0;
xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
@@ -11391,9 +11395,11 @@ eval_predicates:
PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
} else
#endif
- PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
- test, type, (void *)prefix, (void *)name);
-
+ if (PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
+ test, type, (void *)prefix, (void *)name) == -1) {
+ xmlFree(prefix);
+ xmlFree(name);
+ }
}
#ifdef DEBUG_STEP
xmlGenericError(xmlGenericErrorContext, "Step : ");
--
1.8.3.1

View File

@ -1,57 +0,0 @@
From 3da8d947df1f84e54b12145ca2cfa1ff6456f532 Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
Date: Thu, 9 Jul 2020 16:08:38 +0200
Subject: [PATCH] Fix more quadratic runtime issues in HTML push parser
Make sure that checkIndex is set when returning without match from
inside a comment. Also track parser state in htmlParseLookupChars.
Found by OSS-Fuzz.
diff --git a/HTMLparser.c b/HTMLparser.c
index 366c19b..9b12dd1 100644
--- a/HTMLparser.c
+++ b/HTMLparser.c
@@ -5205,7 +5205,7 @@ htmlParseLookupSequence(htmlParserCtxtPtr ctxt, xmlChar first,
}
if (incomment) {
if (base + 3 > len)
- return (-1);
+ break;
if ((buf[base] == '-') && (buf[base + 1] == '-') &&
(buf[base + 2] == '>')) {
incomment = 0;
@@ -5294,8 +5294,11 @@ htmlParseLookupChars(htmlParserCtxtPtr ctxt, const xmlChar * stop,
if (base < 0)
return (-1);
- if (ctxt->checkIndex > base)
+ if (ctxt->checkIndex > base) {
base = ctxt->checkIndex;
+ /* Abuse hasPErefs member to restore current state. */
+ incomment = ctxt->hasPErefs & 1 ? 1 : 0;
+ }
if (in->buf == NULL) {
buf = in->base;
@@ -5316,7 +5319,7 @@ htmlParseLookupChars(htmlParserCtxtPtr ctxt, const xmlChar * stop,
}
if (incomment) {
if (base + 3 > len)
- return (-1);
+ break;
if ((buf[base] == '-') && (buf[base + 1] == '-') &&
(buf[base + 2] == '>')) {
incomment = 0;
@@ -5332,6 +5335,8 @@ htmlParseLookupChars(htmlParserCtxtPtr ctxt, const xmlChar * stop,
}
}
ctxt->checkIndex = base;
+ /* Abuse hasPErefs member to track current state. */
+ ctxt->hasPErefs = incomment;
return (-1);
}
--
1.8.3.1

View File

@ -1,120 +0,0 @@
From e6ec58ecf7adf73335cfb40f0d5bc673681f766b Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
Date: Mon, 21 Sep 2020 12:49:36 +0200
Subject: [PATCH] Fix null deref in XPointer expression error path
Make sure that the filter functions introduced with commit c2f4da1a
return node-sets without NULL pointers also in the error case.
Found by OSS-Fuzz.
---
xpath.c | 38 +++++++++++++++++++-------------------
1 file changed, 19 insertions(+), 19 deletions(-)
diff --git a/xpath.c b/xpath.c
index 311997fe..6ee7e57e 100644
--- a/xpath.c
+++ b/xpath.c
@@ -11677,11 +11677,11 @@ xmlXPathNodeSetFilter(xmlXPathParserContextPtr ctxt,
res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
if (ctxt->error != XPATH_EXPRESSION_OK)
- goto exit;
+ break;
if (res < 0) {
/* Shouldn't happen */
xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
- goto exit;
+ break;
}
if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
@@ -11700,15 +11700,7 @@ xmlXPathNodeSetFilter(xmlXPathParserContextPtr ctxt,
if (res != 0) {
if (pos == maxPos) {
- /* Clear remaining nodes and exit loop. */
- if (hasNsNodes) {
- for (i++; i < set->nodeNr; i++) {
- node = set->nodeTab[i];
- if ((node != NULL) &&
- (node->type == XML_NAMESPACE_DECL))
- xmlXPathNodeSetFreeNs((xmlNsPtr) node);
- }
- }
+ i += 1;
break;
}
@@ -11716,6 +11708,15 @@ xmlXPathNodeSetFilter(xmlXPathParserContextPtr ctxt,
}
}
+ /* Free remaining nodes. */
+ if (hasNsNodes) {
+ for (; i < set->nodeNr; i++) {
+ xmlNodePtr node = set->nodeTab[i];
+ if ((node != NULL) && (node->type == XML_NAMESPACE_DECL))
+ xmlXPathNodeSetFreeNs((xmlNsPtr) node);
+ }
+ }
+
set->nodeNr = j;
/* If too many elements were removed, shrink table to preserve memory. */
@@ -11736,7 +11737,6 @@ xmlXPathNodeSetFilter(xmlXPathParserContextPtr ctxt,
}
}
-exit:
xpctxt->node = oldnode;
xpctxt->doc = olddoc;
xpctxt->contextSize = oldcs;
@@ -11801,11 +11801,11 @@ xmlXPathLocationSetFilter(xmlXPathParserContextPtr ctxt,
res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
if (ctxt->error != XPATH_EXPRESSION_OK)
- goto exit;
+ break;
if (res < 0) {
/* Shouldn't happen */
xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
- goto exit;
+ break;
}
if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
@@ -11823,10 +11823,7 @@ xmlXPathLocationSetFilter(xmlXPathParserContextPtr ctxt,
if (res != 0) {
if (pos == maxPos) {
- /* Clear remaining nodes and exit loop. */
- for (i++; i < locset->locNr; i++) {
- xmlXPathFreeObject(locset->locTab[i]);
- }
+ i += 1;
break;
}
@@ -11834,6 +11831,10 @@ xmlXPathLocationSetFilter(xmlXPathParserContextPtr ctxt,
}
}
+ /* Free remaining nodes. */
+ for (; i < locset->locNr; i++)
+ xmlXPathFreeObject(locset->locTab[i]);
+
locset->locNr = j;
/* If too many elements were removed, shrink table to preserve memory. */
@@ -11854,7 +11855,6 @@ xmlXPathLocationSetFilter(xmlXPathParserContextPtr ctxt,
}
}
-exit:
xpctxt->node = oldnode;
xpctxt->doc = olddoc;
xpctxt->contextSize = oldcs;
--
2.27.0

View File

@ -1,54 +0,0 @@
From bfd2f4300fb348a0fb8265a17546a0eb8bdec719 Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
Date: Sun, 9 May 2021 18:56:57 +0200
Subject: [PATCH] Fix null deref in legacy SAX1 parser
Always call nameNsPush instead of namePush. The latter is unused now
and should probably be removed from the public API. I can't see how
it could be used reasonably from client code and the unprefixed name
has always polluted the global namespace.
Fixes a null pointer dereference introduced with de5b624f when parsing
in SAX1 mode.
Found by OSS-Fuzz.
---
parser.c | 15 ++-------------
1 file changed, 2 insertions(+), 13 deletions(-)
diff --git a/parser.c b/parser.c
index 9bda945..f5e5e16 100644
--- a/parser.c
+++ b/parser.c
@@ -10025,12 +10025,7 @@ xmlParseElementStart(xmlParserCtxtPtr ctxt) {
spacePop(ctxt);
return(-1);
}
- if (ctxt->sax2)
- nameNsPush(ctxt, name, prefix, URI, line, ctxt->nsNr - nsNr);
-#ifdef LIBXML_SAX1_ENABLED
- else
- namePush(ctxt, name);
-#endif /* LIBXML_SAX1_ENABLED */
+ nameNsPush(ctxt, name, prefix, URI, line, ctxt->nsNr - nsNr);
ret = ctxt->node;
#ifdef LIBXML_VALID_ENABLED
@@ -11496,13 +11491,7 @@ xmlParseTryOrFinish(xmlParserCtxtPtr ctxt, int terminate) {
nodePop(ctxt);
spacePop(ctxt);
}
- if (ctxt->sax2)
- nameNsPush(ctxt, name, prefix, URI, line,
- ctxt->nsNr - nsNr);
-#ifdef LIBXML_SAX1_ENABLED
- else
- namePush(ctxt, name);
-#endif /* LIBXML_SAX1_ENABLED */
+ nameNsPush(ctxt, name, prefix, URI, line, ctxt->nsNr - nsNr);
ctxt->instate = XML_PARSER_CONTENT;
ctxt->progressive = 1;
--
1.8.3.1

View File

@ -1,41 +0,0 @@
From a218ff0ec0ca6da74236b1419e841848a249f011 Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
Date: Sun, 6 Dec 2020 17:26:36 +0100
Subject: [PATCH] Fix null pointer deref in xmlXPtrRangeInsideFunction
Found by OSS-Fuzz.
---
xpointer.c | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/xpointer.c b/xpointer.c
index ad2c288..3e3c8b8 100644
--- a/xpointer.c
+++ b/xpointer.c
@@ -2200,7 +2200,6 @@ xmlXPtrRangeInsideFunction(xmlXPathParserContextPtr ctxt, int nargs) {
XP_ERROR(XPATH_MEMORY_ERROR)
set = tmp;
}
- oldset = (xmlLocationSetPtr) set->user;
/*
* The loop is to compute the covering range for each item and add it
@@ -2210,9 +2209,12 @@ xmlXPtrRangeInsideFunction(xmlXPathParserContextPtr ctxt, int nargs) {
xmlXPathFreeObject(set);
XP_ERROR(XPATH_MEMORY_ERROR);
}
- for (i = 0;i < oldset->locNr;i++) {
- xmlXPtrLocationSetAdd(newset,
- xmlXPtrInsideRange(ctxt, oldset->locTab[i]));
+ oldset = (xmlLocationSetPtr) set->user;
+ if (oldset != NULL) {
+ for (i = 0;i < oldset->locNr;i++) {
+ xmlXPtrLocationSetAdd(newset,
+ xmlXPtrInsideRange(ctxt, oldset->locTab[i]));
+ }
}
/*
--
1.8.3.1

View File

@ -1,29 +0,0 @@
From c9faa29259ac23b5fbf945f61056288e413dae81 Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
Date: Thu, 2 Jan 2020 14:12:39 +0100
Subject: [PATCH] Fix overflow check in xmlNodeDump
Store return value of xmlBufNodeDump in a size_t before checking for
integer overflow.
Found by lgtm.com
---
xmlsave.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/xmlsave.c b/xmlsave.c
index 7158c26..b06e24d 100644
--- a/xmlsave.c
+++ b/xmlsave.c
@@ -2187,7 +2187,7 @@ xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
int format)
{
xmlBufPtr buffer;
- int ret;
+ size_t ret;
if ((buf == NULL) || (cur == NULL))
return(-1);
--
1.8.3.1

View File

@ -1,34 +0,0 @@
From bf2e96173d4f78f564015a925970077501586fbe Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
Date: Thu, 7 Nov 2019 12:54:01 +0100
Subject: [PATCH] Fix overflow handling in xmlBufBackToBuffer
Don't overwrite 'use' and 'size' members after clamping to INT_MAX.
Thanks to Ranier Vilela for pointing this out in merge request !56.
---
buf.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/buf.c b/buf.c
index d46da36..3b212fc 100644
--- a/buf.c
+++ b/buf.c
@@ -1233,10 +1233,12 @@ xmlBufBackToBuffer(xmlBufPtr buf) {
* Keep the buffer but provide a truncated size value.
*/
xmlBufOverflowError(buf, "Allocated size too big for xmlBuffer");
+ ret->use = (int) buf->use;
ret->size = INT_MAX;
+ } else {
+ ret->use = (int) buf->use;
+ ret->size = (int) buf->size;
}
- ret->use = (int) buf->use;
- ret->size = (int) buf->size;
ret->alloc = buf->alloc;
ret->content = buf->content;
ret->contentIO = buf->contentIO;
--
1.8.3.1

View File

@ -1,44 +0,0 @@
From 688b41a0fb06cf1ab5173308f6a8db5089ba6e14 Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
Date: Mon, 1 Mar 2021 14:17:42 +0100
Subject: [PATCH] Fix quadratic behavior when looking up xml:* attributes
Add a special case for the predefined XML namespace when looking up DTD
attribute defaults in xmlGetPropNodeInternal to avoid calling
xmlGetNsList.
This fixes quadratic behavior in
- xmlNodeGetBase
- xmlNodeGetLang
- xmlNodeGetSpacePreserve
Found by OSS-Fuzz.
---
tree.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/tree.c b/tree.c
index d6ea704..617e818 100644
--- a/tree.c
+++ b/tree.c
@@ -6589,6 +6589,16 @@ xmlGetPropNodeInternal(const xmlNode *node, const xmlChar *name,
attrDecl = xmlGetDtdQAttrDesc(doc->extSubset,
elemQName, name, NULL);
}
+ } else if (xmlStrEqual(nsName, XML_XML_NAMESPACE)) {
+ /*
+ * The XML namespace must be bound to prefix 'xml'.
+ */
+ attrDecl = xmlGetDtdQAttrDesc(doc->intSubset,
+ elemQName, name, BAD_CAST "xml");
+ if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
+ attrDecl = xmlGetDtdQAttrDesc(doc->extSubset,
+ elemQName, name, BAD_CAST "xml");
+ }
} else {
xmlNsPtr *nsList, *cur;
--
1.8.3.1

View File

@ -1,63 +0,0 @@
From 27119ec33c9f6b9830efa1e0da0acfa353dfa55a Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
Date: Mon, 17 Aug 2020 00:05:19 +0200
Subject: [PATCH] Fix quadratic runtime in xi:fallback processing
Copying the tree would lead to runtime quadratic in nested fallback
depth, similar to naive string concatenation.
---
xinclude.c | 23 +++++++++++------------
1 file changed, 11 insertions(+), 12 deletions(-)
diff --git a/xinclude.c b/xinclude.c
index e9d3af5..9a65ee5 100644
--- a/xinclude.c
+++ b/xinclude.c
@@ -2003,8 +2003,7 @@ xmlXIncludeLoadFallback(xmlXIncludeCtxtPtr ctxt, xmlNodePtr fallback, int nr) {
ret = -1;
xmlXIncludeFreeContext(newctxt);
- ctxt->incTab[nr]->inc = xmlDocCopyNodeList(ctxt->doc,
- fallback->children);
+ ctxt->incTab[nr]->inc = fallback->children;
} else {
ctxt->incTab[nr]->inc = NULL;
}
@@ -2268,12 +2267,6 @@ xmlXIncludeIncludeNode(xmlXIncludeCtxtPtr ctxt, int nr) {
* 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,
@@ -2289,11 +2282,17 @@ xmlXIncludeIncludeNode(xmlXIncludeCtxtPtr ctxt, int nr) {
* Add the list of nodes
*/
while (list != NULL) {
- cur = list;
- list = list->next;
-
- xmlAddPrevSibling(end, cur);
+ next = list->next;
+ xmlAddPrevSibling(end, list);
+ list = next;
}
+
+ /* Remove fallback node */
+ for (child = cur->children; child != NULL; child = next) {
+ next = child->next;
+ xmlUnlinkNode(child);
+ xmlFreeNode(child);
+ }
}
--
1.8.3.1

View File

@ -1,62 +0,0 @@
From 500789224b59fa70d6837be5cd1edb8e2f1eccb6 Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
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

View File

@ -1,97 +0,0 @@
From 87d20b554c6a90e7ece1cc7391c005089bf85b78 Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
Date: Wed, 19 Aug 2020 13:52:08 +0200
Subject: [PATCH] Fix regression introduced with commit 74dcc10b
The code wasn't dead after all, but I can see no reason in delaying
the XPointer evaluation. This could lead to nodes included earlier
appearing in XPointer results.
---
result/XInclude/ns1.xml | 10 ++++++++++
result/XInclude/ns1.xml.rdr | 23 +++++++++++++++++++++++
test/XInclude/docs/ns1.xml | 12 ++++++++++++
xinclude.c | 2 +-
4 files changed, 46 insertions(+), 1 deletion(-)
create mode 100644 result/XInclude/ns1.xml
create mode 100644 result/XInclude/ns1.xml.rdr
create mode 100644 test/XInclude/docs/ns1.xml
diff --git a/result/XInclude/ns1.xml b/result/XInclude/ns1.xml
new file mode 100644
index 0000000..ab41fb7
--- /dev/null
+++ b/result/XInclude/ns1.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0"?>
+<doc xmlns:xi="http://www.w3.org/2001/XInclude">
+ <ns:elem xmlns:ns="urn:foo" xml:id="a"/>
+ <elem xmlns:ns="urn:foo">
+ <ns:elem xml:id="a"/>
+ </elem>
+
+ <ns:elem xmlns:ns="urn:bar"/>
+
+</doc>
diff --git a/result/XInclude/ns1.xml.rdr b/result/XInclude/ns1.xml.rdr
new file mode 100644
index 0000000..f23702f
--- /dev/null
+++ b/result/XInclude/ns1.xml.rdr
@@ -0,0 +1,23 @@
+0 1 doc 0 0
+1 14 #text 0 1
+
+1 1 ns:elem 1 0
+1 14 #text 0 1
+
+1 1 elem 0 0
+2 14 #text 0 1
+
+2 1 ns:elem 1 0
+2 14 #text 0 1
+
+1 15 elem 0 0
+1 14 #text 0 1
+
+1 14 #text 0 1
+
+1 1 ns:elem 1 0
+1 14 #text 0 1
+
+1 14 #text 0 1
+
+0 15 doc 0 0
diff --git a/test/XInclude/docs/ns1.xml b/test/XInclude/docs/ns1.xml
new file mode 100644
index 0000000..7523f4a
--- /dev/null
+++ b/test/XInclude/docs/ns1.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0"?>
+<doc xmlns:xi="http://www.w3.org/2001/XInclude">
+ <xi:include href="#a"/>
+ <elem xmlns:ns="urn:foo">
+ <ns:elem xml:id="a"/>
+ </elem>
+ <xi:include href="b.xml">
+ <xi:fallback xmlns:ns="urn:bar">
+ <ns:elem/>
+ </xi:fallback>
+ </xi:include>
+</doc>
diff --git a/xinclude.c b/xinclude.c
index aac30d5..c92b32b 100644
--- a/xinclude.c
+++ b/xinclude.c
@@ -1464,7 +1464,7 @@ xmlXIncludeLoadDoc(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, int nr) {
*/
if ((URL[0] == 0) || (URL[0] == '#') ||
((ctxt->doc != NULL) && (xmlStrEqual(URL, ctxt->doc->URL)))) {
- doc = NULL;
+ doc = ctxt->doc;
goto loaded;
}
--
1.8.3.1

View File

@ -1,67 +0,0 @@
From 3fcf319378f9396a9ca840cd63b96a441818e1f1 Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
Date: Sat, 22 Aug 2020 00:43:18 +0200
Subject: [PATCH] Fix regression introduced with commit d88df4b
Revert the commit and use a different approach.
Found by OSS-Fuzz.
---
xinclude.c | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/xinclude.c b/xinclude.c
index c92b32b..f48e0af 100644
--- a/xinclude.c
+++ b/xinclude.c
@@ -59,8 +59,8 @@ struct _xmlXIncludeRef {
xmlNodePtr inc; /* the included copy */
int xml; /* xml or txt */
int count; /* how many refs use that specific doc */
- int skip; /* skip in case of errors */
int fallback; /* fallback was loaded */
+ int emptyFb; /* flag to show fallback empty */
};
struct _xmlXIncludeCtxt {
@@ -1988,8 +1988,11 @@ xmlXIncludeLoadFallback(xmlXIncludeCtxtPtr ctxt, xmlNodePtr fallback, int nr) {
ctxt->incTab[nr]->inc = xmlDocCopyNodeList(ctxt->doc,
fallback->children);
+ if (ctxt->incTab[nr]->inc == NULL)
+ ctxt->incTab[nr]->emptyFb = 1;
} else {
ctxt->incTab[nr]->inc = NULL;
+ ctxt->incTab[nr]->emptyFb = 1; /* flag empty callback */
}
ctxt->incTab[nr]->fallback = 1;
return(ret);
@@ -2153,7 +2156,6 @@ xmlXIncludeLoadNode(xmlXIncludeCtxtPtr ctxt, int nr) {
}
}
if (ret < 0) {
- ctxt->incTab[nr]->skip = 1;
xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
XML_XINCLUDE_NO_FALLBACK,
"could not load %s, and no fallback was found\n",
@@ -2197,6 +2199,7 @@ xmlXIncludeIncludeNode(xmlXIncludeCtxtPtr ctxt, int nr) {
list = ctxt->incTab[nr]->inc;
ctxt->incTab[nr]->inc = NULL;
+ ctxt->incTab[nr]->emptyFb = 0;
/*
* Check against the risk of generating a multi-rooted document
@@ -2459,7 +2462,8 @@ xmlXIncludeDoProcess(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr tree,
*
*/
for (i = ctxt->incBase;i < ctxt->incNr; i++) {
- if (ctxt->incTab[i]->skip == 0)
+ if ((ctxt->incTab[i]->inc != NULL) ||
+ (ctxt->incTab[i]->emptyFb != 0)) /* (empty fallback) */
xmlXIncludeIncludeNode(ctxt, i);
}
--
1.8.3.1

View File

@ -1,27 +0,0 @@
From 487871b0e39bcc69ec0c1f69c30e2697712c6829 Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
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

View File

@ -1,112 +0,0 @@
From 847a3a1181d59dc49c1b446d646d344d0543af3e Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
Date: Mon, 28 Sep 2020 12:28:29 +0200
Subject: [PATCH] Fix use-after-free when XIncluding text from Reader
The XML Reader can free text nodes coming from the XInclude engine
before parsing has finished. Cache a copy of the text string, not the
included node to avoid use after free.
Found by OSS-Fuzz.
---
xinclude.c | 31 ++++++++++++++++++-------------
1 file changed, 18 insertions(+), 13 deletions(-)
diff --git a/xinclude.c b/xinclude.c
index f48e0af5..1636caff 100644
--- a/xinclude.c
+++ b/xinclude.c
@@ -72,7 +72,7 @@ struct _xmlXIncludeCtxt {
int txtNr; /* number of unparsed documents */
int txtMax; /* size of unparsed documents tab */
- xmlNodePtr *txtTab; /* array of unparsed text nodes */
+ xmlChar * *txtTab; /* array of unparsed text strings */
xmlURL *txturlTab; /* array of unparsed text URLs */
xmlChar * url; /* the current URL processed */
@@ -393,18 +393,22 @@ xmlXIncludeFreeContext(xmlXIncludeCtxtPtr ctxt) {
if (ctxt->incTab[i] != NULL)
xmlXIncludeFreeRef(ctxt->incTab[i]);
}
+ if (ctxt->incTab != NULL)
+ xmlFree(ctxt->incTab);
+ if (ctxt->txtTab != NULL) {
+ for (i = 0;i < ctxt->txtNr;i++) {
+ if (ctxt->txtTab[i] != NULL)
+ xmlFree(ctxt->txtTab[i]);
+ }
+ xmlFree(ctxt->txtTab);
+ }
if (ctxt->txturlTab != NULL) {
for (i = 0;i < ctxt->txtNr;i++) {
if (ctxt->txturlTab[i] != NULL)
xmlFree(ctxt->txturlTab[i]);
}
- }
- if (ctxt->incTab != NULL)
- xmlFree(ctxt->incTab);
- if (ctxt->txtTab != NULL)
- xmlFree(ctxt->txtTab);
- if (ctxt->txturlTab != NULL)
xmlFree(ctxt->txturlTab);
+ }
if (ctxt->base != NULL) {
xmlFree(ctxt->base);
}
@@ -764,13 +768,14 @@ xmlXIncludeRecurseDoc(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc,
* Add a new text node to the list
*/
static void
-xmlXIncludeAddTxt(xmlXIncludeCtxtPtr ctxt, xmlNodePtr txt, const xmlURL url) {
+xmlXIncludeAddTxt(xmlXIncludeCtxtPtr ctxt, const xmlChar *txt,
+ const xmlURL url) {
#ifdef DEBUG_XINCLUDE
xmlGenericError(xmlGenericErrorContext, "Adding text %s\n", url);
#endif
if (ctxt->txtMax == 0) {
ctxt->txtMax = 4;
- ctxt->txtTab = (xmlNodePtr *) xmlMalloc(ctxt->txtMax *
+ ctxt->txtTab = (xmlChar **) xmlMalloc(ctxt->txtMax *
sizeof(ctxt->txtTab[0]));
if (ctxt->txtTab == NULL) {
xmlXIncludeErrMemory(ctxt, NULL, "processing text");
@@ -785,7 +790,7 @@ xmlXIncludeAddTxt(xmlXIncludeCtxtPtr ctxt, xmlNodePtr txt, const xmlURL url) {
}
if (ctxt->txtNr >= ctxt->txtMax) {
ctxt->txtMax *= 2;
- ctxt->txtTab = (xmlNodePtr *) xmlRealloc(ctxt->txtTab,
+ ctxt->txtTab = (xmlChar **) xmlRealloc(ctxt->txtTab,
ctxt->txtMax * sizeof(ctxt->txtTab[0]));
if (ctxt->txtTab == NULL) {
xmlXIncludeErrMemory(ctxt, NULL, "processing text");
@@ -798,7 +803,7 @@ xmlXIncludeAddTxt(xmlXIncludeCtxtPtr ctxt, xmlNodePtr txt, const xmlURL url) {
return;
}
}
- ctxt->txtTab[ctxt->txtNr] = txt;
+ ctxt->txtTab[ctxt->txtNr] = xmlStrdup(txt);
ctxt->txturlTab[ctxt->txtNr] = xmlStrdup(url);
ctxt->txtNr++;
}
@@ -1845,7 +1850,7 @@ xmlXIncludeLoadTxt(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, int nr) {
*/
for (i = 0; i < ctxt->txtNr; i++) {
if (xmlStrEqual(URL, ctxt->txturlTab[i])) {
- node = xmlCopyNode(ctxt->txtTab[i], 1);
+ node = xmlNewText(ctxt->txtTab[i]);
goto loaded;
}
}
@@ -1935,7 +1940,7 @@ xinclude_multibyte_fallback:
xmlBufShrink(buf->buffer, len);
}
xmlFreeParserCtxt(pctxt);
- xmlXIncludeAddTxt(ctxt, node, URL);
+ xmlXIncludeAddTxt(ctxt, node->content, URL);
xmlFreeInputStream(inputStream);
loaded:
--
2.27.0

View File

@ -1,91 +0,0 @@
From 2af3c2a8b974cb5896cd3beb74561ba979de9f34 Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
Date: Mon, 8 Jun 2020 12:49:51 +0200
Subject: [PATCH] Fix use-after-free with validating reader
Just like IDs, IDREF attributes must be removed from the document's
refs table when they're freed by a reader. This bug is often hidden
because xmlAttr structs are reused and strings are stored in a
dictionary unless XML_PARSE_NODICT is specified.
Found by OSS-Fuzz.
---
xmlreader.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 55 insertions(+)
diff --git a/xmlreader.c b/xmlreader.c
index 3fd9aa4c0..6ae6e9229 100644
--- a/xmlreader.c
+++ b/xmlreader.c
@@ -278,6 +278,59 @@ xmlTextReaderRemoveID(xmlDocPtr doc, xmlAttrPtr attr) {
return(0);
}
+/**
+ * xmlTextReaderWalkRemoveRef:
+ * @data: Contents of current link
+ * @user: Value supplied by the user
+ *
+ * Returns 0 to abort the walk or 1 to continue
+ */
+static int
+xmlTextReaderWalkRemoveRef(const void *data, void *user)
+{
+ xmlRefPtr ref = (xmlRefPtr)data;
+ xmlAttrPtr attr = (xmlAttrPtr)user;
+
+ if (ref->attr == attr) { /* Matched: remove and terminate walk */
+ ref->name = xmlStrdup(attr->name);
+ ref->attr = NULL;
+ return 0;
+ }
+ return 1;
+}
+
+/**
+ * xmlTextReaderRemoveRef:
+ * @doc: the document
+ * @attr: the attribute
+ *
+ * Remove the given attribute from the Ref table maintained internally.
+ *
+ * Returns -1 if the lookup failed and 0 otherwise
+ */
+static int
+xmlTextReaderRemoveRef(xmlDocPtr doc, xmlAttrPtr attr) {
+ xmlListPtr ref_list;
+ xmlRefTablePtr table;
+ xmlChar *ID;
+
+ if (doc == NULL) return(-1);
+ if (attr == NULL) return(-1);
+ table = (xmlRefTablePtr) doc->refs;
+ if (table == NULL)
+ return(-1);
+
+ ID = xmlNodeListGetString(doc, attr->children, 1);
+ if (ID == NULL)
+ return(-1);
+ ref_list = xmlHashLookup(table, ID);
+ xmlFree(ID);
+ if(ref_list == NULL)
+ return (-1);
+ xmlListWalk(ref_list, xmlTextReaderWalkRemoveRef, attr);
+ return(0);
+}
+
/**
* xmlTextReaderFreeProp:
* @reader: the xmlTextReaderPtr used
@@ -304,6 +357,8 @@ xmlTextReaderFreeProp(xmlTextReaderPtr reader, xmlAttrPtr cur) {
(cur->parent->doc->extSubset != NULL))) {
if (xmlIsID(cur->parent->doc, cur->parent, cur))
xmlTextReaderRemoveID(cur->parent->doc, cur);
+ if (xmlIsRef(cur->parent->doc, cur->parent, cur))
+ xmlTextReaderRemoveRef(cur->parent->doc, cur);
}
if (cur->children != NULL)
xmlTextReaderFreeNodeList(reader, cur->children);
--
GitLab

View File

@ -1,31 +0,0 @@
From 1358d157d0bd83be1dfe356a69213df9fac0b539 Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
Date: Wed, 21 Apr 2021 13:23:27 +0200
Subject: [PATCH] Fix use-after-free with `xmllint --html --push`
Call htmlCtxtUseOptions to make sure that names aren't stored in
dictionaries.
Note that this issue only affects xmllint using the HTML push parser.
Fixes #230.
---
xmllint.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/xmllint.c b/xmllint.c
index 6ca1bf5..dbef273 100644
--- a/xmllint.c
+++ b/xmllint.c
@@ -2213,7 +2213,7 @@ static void parseAndPrintFile(char *filename, xmlParserCtxtPtr rectxt) {
if (res > 0) {
ctxt = htmlCreatePushParserCtxt(NULL, NULL,
chars, res, filename, XML_CHAR_ENCODING_NONE);
- xmlCtxtUseOptions(ctxt, options);
+ htmlCtxtUseOptions(ctxt, options);
while ((res = fread(chars, 1, pushsize, f)) > 0) {
htmlParseChunk(ctxt, chars, res, 0);
}
--
1.8.3.1

View File

@ -1,35 +0,0 @@
From e20c9c148c725e2933efa143ee6a543a5cae4204 Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
Date: Sat, 13 Mar 2021 18:41:47 +0100
Subject: [PATCH] Fix xmlGetNodePath with invalid node types
Make xmlGetNodePath return NULL instead of invalid XPath when hitting
unsupported node types like DTD content.
Reported here:
https://mail.gnome.org/archives/xml/2021-January/msg00012.html
Original report:
https://bugs.php.net/bug.php?id=80680
---
tree.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/tree.c b/tree.c
index dbc87aa..c707f59 100644
--- a/tree.c
+++ b/tree.c
@@ -4893,7 +4893,9 @@ xmlGetNodePath(const xmlNode *node)
}
next = ((xmlAttrPtr) cur)->parent;
} else {
- next = cur->parent;
+ xmlFree(buf);
+ xmlFree(buffer);
+ return (NULL);
}
/*
--
1.8.3.1

View File

@ -1,65 +0,0 @@
From 6c128fd58a0e4641c23a345d413672494622db1b Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
Date: Fri, 5 Jun 2020 13:43:45 +0200
Subject: [PATCH 111/139] Fuzz XInclude engine
---
xinclude.c | 15 +++++++++++++++
1 files changed, 15 insertions(+)
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

View File

@ -1,108 +0,0 @@
From 6f1470a5d6e3e369fe93f52d5760ba7c947f0cd1 Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
Date: Tue, 25 Aug 2020 18:50:45 +0200
Subject: [PATCH] Hardcode maximum XPath recursion depth
Always limit nested functions calls to 5000. This avoids call stack
overflows with deeply nested expressions.
The expression parser produces about 10 nested function calls when
parsing a subexpression in parentheses, so the effective nesting limit
is about 500 which should be more than enough.
Use a lower limit when fuzzing to account for increased memory usage
when using sanitizers.
Conflict:delete contents of fuzz/xpath.c
---
xpath.c | 25 +++++++++++++++++--------
1 file changed, 17 insertions(+), 8 deletions(-)
diff --git a/xpath.c b/xpath.c
index c018d03..2850a1a 100644
--- a/xpath.c
+++ b/xpath.c
@@ -136,6 +136,17 @@
#define XPATH_MAX_NODESET_LENGTH 10000000
/*
+ * XPATH_MAX_RECRUSION_DEPTH:
+ * Maximum amount of nested functions calls when parsing or evaluating
+ * expressions
+ */
+#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+#define XPATH_MAX_RECURSION_DEPTH 500
+#else
+#define XPATH_MAX_RECURSION_DEPTH 5000
+#endif
+
+/*
* TODO:
* There are a few spots where some tests are done which depend upon ascii
* data. These should be enhanced for full UTF8 support (see particularly
@@ -6118,8 +6129,6 @@ xmlXPathNewContext(xmlDocPtr doc) {
ret->contextSize = -1;
ret->proximityPosition = -1;
- ret->maxDepth = INT_MAX;
-
#ifdef XP_DEFAULT_CACHE_ON
if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
xmlXPathFreeContext(ret);
@@ -10947,7 +10956,7 @@ xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
xmlXPathContextPtr xpctxt = ctxt->context;
if (xpctxt != NULL) {
- if (xpctxt->depth >= xpctxt->maxDepth)
+ if (xpctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
/*
* Parsing a single '(' pushes about 10 functions on the call stack
@@ -11883,7 +11892,7 @@ xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
"xmlXPathCompOpEvalPredicate: Expected a predicate\n");
XP_ERROR(XPATH_INVALID_OPERAND);
}
- if (ctxt->context->depth >= ctxt->context->maxDepth)
+ if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
ctxt->context->depth += 1;
xmlXPathCompOpEvalPredicate(ctxt, &comp->steps[op->ch1], set,
@@ -12599,7 +12608,7 @@ xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
CHECK_ERROR0;
if (OP_LIMIT_EXCEEDED(ctxt, 1))
return(0);
- if (ctxt->context->depth >= ctxt->context->maxDepth)
+ if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
ctxt->context->depth += 1;
comp = ctxt->comp;
@@ -12740,7 +12749,7 @@ xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
CHECK_ERROR0;
if (OP_LIMIT_EXCEEDED(ctxt, 1))
return(0);
- if (ctxt->context->depth >= ctxt->context->maxDepth)
+ if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
ctxt->context->depth += 1;
comp = ctxt->comp;
@@ -12958,7 +12967,7 @@ xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
CHECK_ERROR0;
if (OP_LIMIT_EXCEEDED(ctxt, 1))
return(0);
- if (ctxt->context->depth >= ctxt->context->maxDepth)
+ if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
ctxt->context->depth += 1;
comp = ctxt->comp;
@@ -14192,7 +14201,7 @@ xmlXPathOptimizeExpression(xmlXPathParserContextPtr pctxt,
/* Recurse */
ctxt = pctxt->context;
if (ctxt != NULL) {
- if (ctxt->depth >= ctxt->maxDepth)
+ if (ctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
return;
ctxt->depth += 1;
}
--
1.8.3.1

View File

@ -1,50 +0,0 @@
From fc842f6eba81f3b630e1ff1ffea69c6f4dd66ccc Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
Date: Mon, 6 Jul 2020 15:22:12 +0200
Subject: [PATCH] Limit regexp nesting depth
Enforce a maximum nesting depth of 50 for regular expressions. Avoids
stack overflows with deeply nested regexes.
Found by OSS-Fuzz.
---
xmlregexp.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/xmlregexp.c b/xmlregexp.c
index 687290e2..dbf3bf2c 100644
--- a/xmlregexp.c
+++ b/xmlregexp.c
@@ -273,6 +273,8 @@ struct _xmlAutomata {
int determinist;
int negs;
int flags;
+
+ int depth;
};
struct _xmlRegexp {
@@ -5330,6 +5332,10 @@ xmlFAParseAtom(xmlRegParserCtxtPtr ctxt) {
xmlRegStatePtr start, oldend, start0;
NEXT;
+ if (ctxt->depth >= 50) {
+ ERROR("xmlFAParseAtom: maximum nesting depth exceeded");
+ return(-1);
+ }
/*
* this extra Epsilon transition is needed if we count with 0 allowed
* unfortunately this can't be known at that point
@@ -5341,7 +5347,9 @@ xmlFAParseAtom(xmlRegParserCtxtPtr ctxt) {
oldend = ctxt->end;
ctxt->end = NULL;
ctxt->atom = NULL;
+ ctxt->depth++;
xmlFAParseRegExp(ctxt, 0);
+ ctxt->depth--;
if (CUR == ')') {
NEXT;
} else {
--
2.23.0

View File

@ -1,60 +0,0 @@
From f0fd1b67fc883a24cdd039abb3d4fe4696104d72 Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
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

View File

@ -1,470 +0,0 @@
From b79ab6e6d9270666c5dcd2fd85e4c8563d13f922 Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
Date: Tue, 28 Jul 2020 02:42:37 +0200
Subject: [PATCH] Make htmlNodeDumpFormatOutput non-recursive
Fixes stack overflow with deeply nested HTML documents.
Found by OSS-Fuzz.
---
HTMLtree.c | 410 ++++++++++++++++++++++++++++---------------------------------
1 file changed, 185 insertions(+), 225 deletions(-)
diff --git a/HTMLtree.c b/HTMLtree.c
index fe5d086..8d236bb 100644
--- a/HTMLtree.c
+++ b/HTMLtree.c
@@ -760,50 +760,6 @@ htmlAttrDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur,
}
/**
- * htmlAttrListDumpOutput:
- * @buf: the HTML buffer output
- * @doc: the document
- * @cur: the first attribute pointer
- * @encoding: the encoding string
- *
- * Dump a list of HTML attributes
- */
-static void
-htmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur, const char *encoding) {
- if (cur == NULL) {
- return;
- }
- while (cur != NULL) {
- htmlAttrDumpOutput(buf, doc, cur, encoding);
- cur = cur->next;
- }
-}
-
-
-
-/**
- * htmlNodeListDumpOutput:
- * @buf: the HTML buffer output
- * @doc: the document
- * @cur: the first node
- * @encoding: the encoding string
- * @format: should formatting spaces been added
- *
- * Dump an HTML node list, recursive behaviour,children are printed too.
- */
-static void
-htmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
- xmlNodePtr cur, const char *encoding, int format) {
- if (cur == NULL) {
- return;
- }
- while (cur != NULL) {
- htmlNodeDumpFormatOutput(buf, doc, cur, encoding, format);
- cur = cur->next;
- }
-}
-
-/**
* htmlNodeDumpFormatOutput:
* @buf: the HTML buffer output
* @doc: the document
@@ -816,6 +772,8 @@ htmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
void
htmlNodeDumpFormatOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
xmlNodePtr cur, const char *encoding, int format) {
+ xmlNodePtr root;
+ xmlAttrPtr attr;
const htmlElemDesc * info;
xmlInitParser();
@@ -823,172 +781,193 @@ htmlNodeDumpFormatOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
if ((cur == NULL) || (buf == NULL)) {
return;
}
- /*
- * Special cases.
- */
- if (cur->type == XML_DTD_NODE)
- return;
- if ((cur->type == XML_HTML_DOCUMENT_NODE) ||
- (cur->type == XML_DOCUMENT_NODE)){
- htmlDocContentDumpOutput(buf, (xmlDocPtr) cur, encoding);
- return;
- }
- if (cur->type == XML_ATTRIBUTE_NODE) {
- htmlAttrDumpOutput(buf, doc, (xmlAttrPtr) cur, encoding);
- return;
- }
- if (cur->type == HTML_TEXT_NODE) {
- if (cur->content != NULL) {
- if (((cur->name == (const xmlChar *)xmlStringText) ||
- (cur->name != (const xmlChar *)xmlStringTextNoenc)) &&
- ((cur->parent == NULL) ||
- ((xmlStrcasecmp(cur->parent->name, BAD_CAST "script")) &&
- (xmlStrcasecmp(cur->parent->name, BAD_CAST "style"))))) {
- xmlChar *buffer;
-
- buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
- if (buffer != NULL) {
- xmlOutputBufferWriteString(buf, (const char *)buffer);
- xmlFree(buffer);
- }
- } else {
- xmlOutputBufferWriteString(buf, (const char *)cur->content);
- }
- }
- return;
- }
- if (cur->type == HTML_COMMENT_NODE) {
- if (cur->content != NULL) {
- xmlOutputBufferWriteString(buf, "<!--");
- xmlOutputBufferWriteString(buf, (const char *)cur->content);
- xmlOutputBufferWriteString(buf, "-->");
- }
- return;
- }
- if (cur->type == HTML_PI_NODE) {
- if (cur->name == NULL)
- return;
- xmlOutputBufferWriteString(buf, "<?");
- xmlOutputBufferWriteString(buf, (const char *)cur->name);
- if (cur->content != NULL) {
- xmlOutputBufferWriteString(buf, " ");
- xmlOutputBufferWriteString(buf, (const char *)cur->content);
- }
- xmlOutputBufferWriteString(buf, ">");
- return;
- }
- if (cur->type == HTML_ENTITY_REF_NODE) {
- xmlOutputBufferWriteString(buf, "&");
- xmlOutputBufferWriteString(buf, (const char *)cur->name);
- xmlOutputBufferWriteString(buf, ";");
- return;
- }
- if (cur->type == HTML_PRESERVE_NODE) {
- if (cur->content != NULL) {
- xmlOutputBufferWriteString(buf, (const char *)cur->content);
- }
- return;
- }
- /*
- * Get specific HTML info for that node.
- */
- if (cur->ns == NULL)
- info = htmlTagLookup(cur->name);
- else
- info = NULL;
+ root = cur;
+ while (1) {
+ switch (cur->type) {
+ case XML_HTML_DOCUMENT_NODE:
+ case XML_DOCUMENT_NODE:
+ if (((xmlDocPtr) cur)->intSubset != NULL) {
+ htmlDtdDumpOutput(buf, (xmlDocPtr) cur, NULL);
+ }
+ if (cur->children != NULL) {
+ cur = cur->children;
+ continue;
+ }
+ break;
- xmlOutputBufferWriteString(buf, "<");
- if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
- xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
- xmlOutputBufferWriteString(buf, ":");
- }
- xmlOutputBufferWriteString(buf, (const char *)cur->name);
- if (cur->nsDef)
- xmlNsListDumpOutput(buf, cur->nsDef);
- if (cur->properties != NULL)
- htmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
-
- if ((info != NULL) && (info->empty)) {
- xmlOutputBufferWriteString(buf, ">");
- if ((format) && (!info->isinline) && (cur->next != NULL)) {
- if ((cur->next->type != HTML_TEXT_NODE) &&
- (cur->next->type != HTML_ENTITY_REF_NODE) &&
- (cur->parent != NULL) &&
- (cur->parent->name != NULL) &&
- (cur->parent->name[0] != 'p')) /* p, pre, param */
- xmlOutputBufferWriteString(buf, "\n");
- }
- return;
- }
- if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) &&
- (cur->children == NULL)) {
- if ((info != NULL) && (info->saveEndTag != 0) &&
- (xmlStrcmp(BAD_CAST info->name, BAD_CAST "html")) &&
- (xmlStrcmp(BAD_CAST info->name, BAD_CAST "body"))) {
- xmlOutputBufferWriteString(buf, ">");
- } else {
- xmlOutputBufferWriteString(buf, "></");
+ case XML_ELEMENT_NODE:
+ /*
+ * Get specific HTML info for that node.
+ */
+ if (cur->ns == NULL)
+ info = htmlTagLookup(cur->name);
+ else
+ info = NULL;
+
+ xmlOutputBufferWriteString(buf, "<");
if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
xmlOutputBufferWriteString(buf, ":");
}
- xmlOutputBufferWriteString(buf, (const char *)cur->name);
- xmlOutputBufferWriteString(buf, ">");
- }
- if ((format) && (cur->next != NULL) &&
- (info != NULL) && (!info->isinline)) {
- if ((cur->next->type != HTML_TEXT_NODE) &&
- (cur->next->type != HTML_ENTITY_REF_NODE) &&
- (cur->parent != NULL) &&
- (cur->parent->name != NULL) &&
- (cur->parent->name[0] != 'p')) /* p, pre, param */
- xmlOutputBufferWriteString(buf, "\n");
- }
- return;
- }
- xmlOutputBufferWriteString(buf, ">");
- if ((cur->type != XML_ELEMENT_NODE) &&
- (cur->content != NULL)) {
- /*
- * Uses the OutputBuffer property to automatically convert
- * invalids to charrefs
- */
-
- xmlOutputBufferWriteString(buf, (const char *) cur->content);
- }
- if (cur->children != NULL) {
- if ((format) && (info != NULL) && (!info->isinline) &&
- (cur->children->type != HTML_TEXT_NODE) &&
- (cur->children->type != HTML_ENTITY_REF_NODE) &&
- (cur->children != cur->last) &&
- (cur->name != NULL) &&
- (cur->name[0] != 'p')) /* p, pre, param */
- xmlOutputBufferWriteString(buf, "\n");
- htmlNodeListDumpOutput(buf, doc, cur->children, encoding, format);
- if ((format) && (info != NULL) && (!info->isinline) &&
- (cur->last->type != HTML_TEXT_NODE) &&
- (cur->last->type != HTML_ENTITY_REF_NODE) &&
- (cur->children != cur->last) &&
- (cur->name != NULL) &&
- (cur->name[0] != 'p')) /* p, pre, param */
- xmlOutputBufferWriteString(buf, "\n");
- }
- xmlOutputBufferWriteString(buf, "</");
- if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
- xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
- xmlOutputBufferWriteString(buf, ":");
- }
- xmlOutputBufferWriteString(buf, (const char *)cur->name);
- xmlOutputBufferWriteString(buf, ">");
- if ((format) && (info != NULL) && (!info->isinline) &&
- (cur->next != NULL)) {
- if ((cur->next->type != HTML_TEXT_NODE) &&
- (cur->next->type != HTML_ENTITY_REF_NODE) &&
- (cur->parent != NULL) &&
- (cur->parent->name != NULL) &&
- (cur->parent->name[0] != 'p')) /* p, pre, param */
- xmlOutputBufferWriteString(buf, "\n");
+ xmlOutputBufferWriteString(buf, (const char *)cur->name);
+ if (cur->nsDef)
+ xmlNsListDumpOutput(buf, cur->nsDef);
+ attr = cur->properties;
+ while (attr != NULL) {
+ htmlAttrDumpOutput(buf, doc, attr, encoding);
+ attr = attr->next;
+ }
+
+ if ((info != NULL) && (info->empty)) {
+ xmlOutputBufferWriteString(buf, ">");
+ } else if (cur->children == NULL) {
+ if ((info != NULL) && (info->saveEndTag != 0) &&
+ (xmlStrcmp(BAD_CAST info->name, BAD_CAST "html")) &&
+ (xmlStrcmp(BAD_CAST info->name, BAD_CAST "body"))) {
+ xmlOutputBufferWriteString(buf, ">");
+ } else {
+ xmlOutputBufferWriteString(buf, "></");
+ if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
+ xmlOutputBufferWriteString(buf,
+ (const char *)cur->ns->prefix);
+ xmlOutputBufferWriteString(buf, ":");
+ }
+ xmlOutputBufferWriteString(buf, (const char *)cur->name);
+ xmlOutputBufferWriteString(buf, ">");
+ }
+ } else {
+ xmlOutputBufferWriteString(buf, ">");
+ if ((format) && (info != NULL) && (!info->isinline) &&
+ (cur->children->type != HTML_TEXT_NODE) &&
+ (cur->children->type != HTML_ENTITY_REF_NODE) &&
+ (cur->children != cur->last) &&
+ (cur->name != NULL) &&
+ (cur->name[0] != 'p')) /* p, pre, param */
+ xmlOutputBufferWriteString(buf, "\n");
+ cur = cur->children;
+ continue;
+ }
+
+ if ((format) && (cur->next != NULL) &&
+ (info != NULL) && (!info->isinline)) {
+ if ((cur->next->type != HTML_TEXT_NODE) &&
+ (cur->next->type != HTML_ENTITY_REF_NODE) &&
+ (cur->parent != NULL) &&
+ (cur->parent->name != NULL) &&
+ (cur->parent->name[0] != 'p')) /* p, pre, param */
+ xmlOutputBufferWriteString(buf, "\n");
+ }
+
+ break;
+
+ case XML_ATTRIBUTE_NODE:
+ htmlAttrDumpOutput(buf, doc, (xmlAttrPtr) cur, encoding);
+ break;
+
+ case HTML_TEXT_NODE:
+ if (cur->content == NULL)
+ break;
+ if (((cur->name == (const xmlChar *)xmlStringText) ||
+ (cur->name != (const xmlChar *)xmlStringTextNoenc)) &&
+ ((cur->parent == NULL) ||
+ ((xmlStrcasecmp(cur->parent->name, BAD_CAST "script")) &&
+ (xmlStrcasecmp(cur->parent->name, BAD_CAST "style"))))) {
+ xmlChar *buffer;
+
+ buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
+ if (buffer != NULL) {
+ xmlOutputBufferWriteString(buf, (const char *)buffer);
+ xmlFree(buffer);
+ }
+ } else {
+ xmlOutputBufferWriteString(buf, (const char *)cur->content);
+ }
+ break;
+
+ case HTML_COMMENT_NODE:
+ if (cur->content != NULL) {
+ xmlOutputBufferWriteString(buf, "<!--");
+ xmlOutputBufferWriteString(buf, (const char *)cur->content);
+ xmlOutputBufferWriteString(buf, "-->");
+ }
+ break;
+
+ case HTML_PI_NODE:
+ if (cur->name != NULL) {
+ xmlOutputBufferWriteString(buf, "<?");
+ xmlOutputBufferWriteString(buf, (const char *)cur->name);
+ if (cur->content != NULL) {
+ xmlOutputBufferWriteString(buf, " ");
+ xmlOutputBufferWriteString(buf,
+ (const char *)cur->content);
+ }
+ xmlOutputBufferWriteString(buf, ">");
+ }
+ break;
+
+ case HTML_ENTITY_REF_NODE:
+ xmlOutputBufferWriteString(buf, "&");
+ xmlOutputBufferWriteString(buf, (const char *)cur->name);
+ xmlOutputBufferWriteString(buf, ";");
+ break;
+
+ case HTML_PRESERVE_NODE:
+ if (cur->content != NULL) {
+ xmlOutputBufferWriteString(buf, (const char *)cur->content);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ while (1) {
+ if (cur == root)
+ return;
+ if (cur->next != NULL) {
+ cur = cur->next;
+ break;
+ }
+
+ cur = cur->parent;
+
+ if ((cur->type == XML_HTML_DOCUMENT_NODE) ||
+ (cur->type == XML_DOCUMENT_NODE)) {
+ xmlOutputBufferWriteString(buf, "\n");
+ } else {
+ if ((format) && (cur->ns == NULL))
+ info = htmlTagLookup(cur->name);
+ else
+ info = NULL;
+
+ if ((format) && (info != NULL) && (!info->isinline) &&
+ (cur->last->type != HTML_TEXT_NODE) &&
+ (cur->last->type != HTML_ENTITY_REF_NODE) &&
+ (cur->children != cur->last) &&
+ (cur->name != NULL) &&
+ (cur->name[0] != 'p')) /* p, pre, param */
+ xmlOutputBufferWriteString(buf, "\n");
+
+ xmlOutputBufferWriteString(buf, "</");
+ if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
+ xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
+ xmlOutputBufferWriteString(buf, ":");
+ }
+ xmlOutputBufferWriteString(buf, (const char *)cur->name);
+ xmlOutputBufferWriteString(buf, ">");
+
+ if ((format) && (info != NULL) && (!info->isinline) &&
+ (cur->next != NULL)) {
+ if ((cur->next->type != HTML_TEXT_NODE) &&
+ (cur->next->type != HTML_ENTITY_REF_NODE) &&
+ (cur->parent != NULL) &&
+ (cur->parent->name != NULL) &&
+ (cur->parent->name[0] != 'p')) /* p, pre, param */
+ xmlOutputBufferWriteString(buf, "\n");
+ }
+ }
+ }
}
}
@@ -1020,26 +999,7 @@ htmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
void
htmlDocContentDumpFormatOutput(xmlOutputBufferPtr buf, xmlDocPtr cur,
const char *encoding, int format) {
- int type;
-
- xmlInitParser();
-
- if ((buf == NULL) || (cur == NULL))
- return;
-
- /*
- * force to output the stuff as HTML, especially for entities
- */
- type = cur->type;
- cur->type = XML_HTML_DOCUMENT_NODE;
- if (cur->intSubset != NULL) {
- htmlDtdDumpOutput(buf, cur, NULL);
- }
- if (cur->children != NULL) {
- htmlNodeListDumpOutput(buf, cur, cur->children, encoding, format);
- }
- xmlOutputBufferWriteString(buf, "\n");
- cur->type = (xmlElementType) type;
+ htmlNodeDumpFormatOutput(buf, cur, (xmlNodePtr) cur, encoding, format);
}
/**
@@ -1053,7 +1013,7 @@ htmlDocContentDumpFormatOutput(xmlOutputBufferPtr buf, xmlDocPtr cur,
void
htmlDocContentDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr cur,
const char *encoding) {
- htmlDocContentDumpFormatOutput(buf, cur, encoding, 1);
+ htmlNodeDumpFormatOutput(buf, cur, (xmlNodePtr) cur, encoding, 1);
}
/************************************************************************
--
1.8.3.1

View File

@ -1,550 +0,0 @@
From dc6f009280e6108fe25f4c4ce32e18fb69cf496e Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
Date: Tue, 28 Jul 2020 19:07:19 +0200
Subject: [PATCH] Make xmlNodeDumpOutputInternal non-recursive
Fixes stack overflow with deeply nested documents.
---
xmlsave.c | 470 ++++++++++++++++++++++++++++++++------------------------------
1 file changed, 240 insertions(+), 230 deletions(-)
diff --git a/xmlsave.c b/xmlsave.c
index cf32d69..2235c8f 100644
--- a/xmlsave.c
+++ b/xmlsave.c
@@ -590,7 +590,6 @@ static int xmlSaveClearEncoding(xmlSaveCtxtPtr ctxt) {
static void
xhtmlNodeDumpOutput(xmlSaveCtxtPtr ctxt, xmlNodePtr cur);
#endif
-static void xmlNodeListDumpOutput(xmlSaveCtxtPtr ctxt, xmlNodePtr cur);
static void xmlNodeDumpOutputInternal(xmlSaveCtxtPtr ctxt, xmlNodePtr cur);
void xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur);
static int xmlDocContentDumpOutput(xmlSaveCtxtPtr ctxt, xmlDocPtr cur);
@@ -705,6 +704,7 @@ xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
static void
xmlDtdDumpOutput(xmlSaveCtxtPtr ctxt, xmlDtdPtr dtd) {
xmlOutputBufferPtr buf;
+ xmlNodePtr cur;
int format, level;
if (dtd == NULL) return;
@@ -742,7 +742,9 @@ xmlDtdDumpOutput(xmlSaveCtxtPtr ctxt, xmlDtdPtr dtd) {
level = ctxt->level;
ctxt->format = 0;
ctxt->level = -1;
- xmlNodeListDumpOutput(ctxt, dtd->children);
+ for (cur = dtd->children; cur != NULL; cur = cur->next) {
+ xmlNodeDumpOutputInternal(ctxt, cur);
+ }
ctxt->format = format;
ctxt->level = level;
xmlOutputBufferWrite(buf, 2, "]>");
@@ -776,58 +778,9 @@ xmlAttrDumpOutput(xmlSaveCtxtPtr ctxt, xmlAttrPtr cur) {
xmlOutputBufferWrite(buf, 1, "\"");
}
-/**
- * xmlAttrListDumpOutput:
- * @buf: the XML buffer output
- * @doc: the document
- * @cur: the first attribute pointer
- * @encoding: an optional encoding string
- *
- * Dump a list of XML attributes
- */
-static void
-xmlAttrListDumpOutput(xmlSaveCtxtPtr ctxt, xmlAttrPtr cur) {
- if (cur == NULL) return;
- while (cur != NULL) {
- xmlAttrDumpOutput(ctxt, cur);
- cur = cur->next;
- }
-}
-
-
-
-/**
- * xmlNodeListDumpOutput:
- * @cur: the first node
- *
- * Dump an XML node list, recursive behaviour, children are printed too.
- */
-static void
-xmlNodeListDumpOutput(xmlSaveCtxtPtr ctxt, xmlNodePtr cur) {
- xmlOutputBufferPtr buf;
-
- if (cur == NULL) return;
- buf = ctxt->buf;
- while (cur != NULL) {
- if ((ctxt->format == 1) && (xmlIndentTreeOutput) &&
- ((cur->type == XML_ELEMENT_NODE) ||
- (cur->type == XML_COMMENT_NODE) ||
- (cur->type == XML_PI_NODE)))
- xmlOutputBufferWrite(buf, ctxt->indent_size *
- (ctxt->level > ctxt->indent_nr ?
- ctxt->indent_nr : ctxt->level),
- ctxt->indent);
- xmlNodeDumpOutputInternal(ctxt, cur);
- if (ctxt->format == 1) {
- xmlOutputBufferWrite(buf, 1, "\n");
- }
- cur = cur->next;
- }
-}
-
#ifdef LIBXML_HTML_ENABLED
/**
- * xmlNodeDumpOutputInternal:
+ * htmlNodeDumpOutputInternal:
* @cur: the current node
*
* Dump an HTML node, recursive behaviour, children are printed too.
@@ -893,57 +846,111 @@ htmlNodeDumpOutputInternal(xmlSaveCtxtPtr ctxt, xmlNodePtr cur) {
*/
static void
xmlNodeDumpOutputInternal(xmlSaveCtxtPtr ctxt, xmlNodePtr cur) {
- int format;
- xmlNodePtr tmp;
+ int format = ctxt->format;
+ xmlNodePtr tmp, root, unformattedNode = NULL;
+ xmlAttrPtr attr;
xmlChar *start, *end;
xmlOutputBufferPtr buf;
if (cur == NULL) return;
buf = ctxt->buf;
- if (cur->type == XML_XINCLUDE_START)
- return;
- if (cur->type == XML_XINCLUDE_END)
- return;
- if ((cur->type == XML_DOCUMENT_NODE) ||
- (cur->type == XML_HTML_DOCUMENT_NODE)) {
- xmlDocContentDumpOutput(ctxt, (xmlDocPtr) cur);
- return;
- }
-#ifdef LIBXML_HTML_ENABLED
- if (ctxt->options & XML_SAVE_XHTML) {
- xhtmlNodeDumpOutput(ctxt, cur);
- return;
- }
- if (((cur->type != XML_NAMESPACE_DECL) && (cur->doc != NULL) &&
- (cur->doc->type == XML_HTML_DOCUMENT_NODE) &&
- ((ctxt->options & XML_SAVE_AS_XML) == 0)) ||
- (ctxt->options & XML_SAVE_AS_HTML)) {
- htmlNodeDumpOutputInternal(ctxt, cur);
- return;
- }
-#endif
- if (cur->type == XML_DTD_NODE) {
- xmlDtdDumpOutput(ctxt, (xmlDtdPtr) cur);
- return;
- }
- if (cur->type == XML_DOCUMENT_FRAG_NODE) {
- xmlNodeListDumpOutput(ctxt, cur->children);
- return;
- }
- if (cur->type == XML_ELEMENT_DECL) {
- xmlBufDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
- return;
- }
- if (cur->type == XML_ATTRIBUTE_DECL) {
- xmlBufDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
- return;
- }
- if (cur->type == XML_ENTITY_DECL) {
- xmlBufDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
- return;
- }
- if (cur->type == XML_TEXT_NODE) {
- if (cur->content != NULL) {
+
+ root = cur;
+ while (1) {
+ switch (cur->type) {
+ case XML_DOCUMENT_NODE:
+ case XML_HTML_DOCUMENT_NODE:
+ xmlDocContentDumpOutput(ctxt, (xmlDocPtr) cur);
+ break;
+
+ case XML_DTD_NODE:
+ xmlDtdDumpOutput(ctxt, (xmlDtdPtr) cur);
+ break;
+
+ case XML_DOCUMENT_FRAG_NODE:
+ if (cur->children != NULL) {
+ cur = cur->children;
+ continue;
+ }
+ break;
+
+ case XML_ELEMENT_DECL:
+ xmlBufDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
+ break;
+
+ case XML_ATTRIBUTE_DECL:
+ xmlBufDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
+ break;
+
+ case XML_ENTITY_DECL:
+ xmlBufDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
+ break;
+
+ case XML_ELEMENT_NODE:
+ if ((cur != root) && (ctxt->format == 1) && (xmlIndentTreeOutput))
+ xmlOutputBufferWrite(buf, ctxt->indent_size *
+ (ctxt->level > ctxt->indent_nr ?
+ ctxt->indent_nr : ctxt->level),
+ ctxt->indent);
+
+ xmlOutputBufferWrite(buf, 1, "<");
+ if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
+ xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
+ xmlOutputBufferWrite(buf, 1, ":");
+ }
+ xmlOutputBufferWriteString(buf, (const char *)cur->name);
+ if (cur->nsDef)
+ xmlNsListDumpOutputCtxt(ctxt, cur->nsDef);
+ for (attr = cur->properties; attr != NULL; attr = attr->next)
+ xmlAttrDumpOutput(ctxt, attr);
+
+ if (cur->children == NULL) {
+ if ((ctxt->options & XML_SAVE_NO_EMPTY) == 0) {
+ if (ctxt->format == 2)
+ xmlOutputBufferWriteWSNonSig(ctxt, 0);
+ xmlOutputBufferWrite(buf, 2, "/>");
+ } else {
+ if (ctxt->format == 2)
+ xmlOutputBufferWriteWSNonSig(ctxt, 1);
+ xmlOutputBufferWrite(buf, 3, "></");
+ if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
+ xmlOutputBufferWriteString(buf,
+ (const char *)cur->ns->prefix);
+ xmlOutputBufferWrite(buf, 1, ":");
+ }
+ xmlOutputBufferWriteString(buf, (const char *)cur->name);
+ if (ctxt->format == 2)
+ xmlOutputBufferWriteWSNonSig(ctxt, 0);
+ xmlOutputBufferWrite(buf, 1, ">");
+ }
+ } else {
+ if (ctxt->format == 1) {
+ tmp = cur->children;
+ while (tmp != NULL) {
+ if ((tmp->type == XML_TEXT_NODE) ||
+ (tmp->type == XML_CDATA_SECTION_NODE) ||
+ (tmp->type == XML_ENTITY_REF_NODE)) {
+ ctxt->format = 0;
+ unformattedNode = cur;
+ break;
+ }
+ tmp = tmp->next;
+ }
+ }
+ if (ctxt->format == 2)
+ xmlOutputBufferWriteWSNonSig(ctxt, 1);
+ xmlOutputBufferWrite(buf, 1, ">");
+ if (ctxt->format == 1) xmlOutputBufferWrite(buf, 1, "\n");
+ if (ctxt->level >= 0) ctxt->level++;
+ cur = cur->children;
+ continue;
+ }
+
+ break;
+
+ case XML_TEXT_NODE:
+ if (cur->content == NULL)
+ break;
if (cur->name != xmlStringTextNoenc) {
xmlOutputBufferWriteEscape(buf, cur->content, ctxt->escape);
} else {
@@ -952,139 +959,129 @@ xmlNodeDumpOutputInternal(xmlSaveCtxtPtr ctxt, xmlNodePtr cur) {
*/
xmlOutputBufferWriteString(buf, (const char *) cur->content);
}
- }
+ break;
- return;
- }
- if (cur->type == XML_PI_NODE) {
- if (cur->content != NULL) {
- xmlOutputBufferWrite(buf, 2, "<?");
- xmlOutputBufferWriteString(buf, (const char *)cur->name);
- if (cur->content != NULL) {
- if (ctxt->format == 2)
- xmlOutputBufferWriteWSNonSig(ctxt, 0);
- else
- xmlOutputBufferWrite(buf, 1, " ");
- xmlOutputBufferWriteString(buf, (const char *)cur->content);
- }
- xmlOutputBufferWrite(buf, 2, "?>");
- } else {
- xmlOutputBufferWrite(buf, 2, "<?");
- xmlOutputBufferWriteString(buf, (const char *)cur->name);
- if (ctxt->format == 2)
- xmlOutputBufferWriteWSNonSig(ctxt, 0);
- xmlOutputBufferWrite(buf, 2, "?>");
- }
- return;
- }
- if (cur->type == XML_COMMENT_NODE) {
- if (cur->content != NULL) {
- xmlOutputBufferWrite(buf, 4, "<!--");
- xmlOutputBufferWriteString(buf, (const char *)cur->content);
- xmlOutputBufferWrite(buf, 3, "-->");
- }
- return;
- }
- if (cur->type == XML_ENTITY_REF_NODE) {
- xmlOutputBufferWrite(buf, 1, "&");
- xmlOutputBufferWriteString(buf, (const char *)cur->name);
- xmlOutputBufferWrite(buf, 1, ";");
- return;
- }
- if (cur->type == XML_CDATA_SECTION_NODE) {
- if (cur->content == NULL || *cur->content == '\0') {
- xmlOutputBufferWrite(buf, 12, "<![CDATA[]]>");
- } else {
- start = end = cur->content;
- while (*end != '\0') {
- if ((*end == ']') && (*(end + 1) == ']') &&
- (*(end + 2) == '>')) {
- end = end + 2;
- xmlOutputBufferWrite(buf, 9, "<![CDATA[");
- xmlOutputBufferWrite(buf, end - start, (const char *)start);
- xmlOutputBufferWrite(buf, 3, "]]>");
- start = end;
- }
- end++;
- }
- if (start != end) {
- xmlOutputBufferWrite(buf, 9, "<![CDATA[");
- xmlOutputBufferWriteString(buf, (const char *)start);
- xmlOutputBufferWrite(buf, 3, "]]>");
- }
- }
- return;
- }
- if (cur->type == XML_ATTRIBUTE_NODE) {
- xmlAttrDumpOutput(ctxt, (xmlAttrPtr) cur);
- return;
- }
- if (cur->type == XML_NAMESPACE_DECL) {
- xmlNsDumpOutputCtxt(ctxt, (xmlNsPtr) cur);
- return;
- }
+ case XML_PI_NODE:
+ if ((cur != root) && (ctxt->format == 1) && (xmlIndentTreeOutput))
+ xmlOutputBufferWrite(buf, ctxt->indent_size *
+ (ctxt->level > ctxt->indent_nr ?
+ ctxt->indent_nr : ctxt->level),
+ ctxt->indent);
- format = ctxt->format;
- if (format == 1) {
- tmp = cur->children;
- while (tmp != NULL) {
- if ((tmp->type == XML_TEXT_NODE) ||
- (tmp->type == XML_CDATA_SECTION_NODE) ||
- (tmp->type == XML_ENTITY_REF_NODE)) {
- ctxt->format = 0;
- break;
- }
- tmp = tmp->next;
- }
- }
- xmlOutputBufferWrite(buf, 1, "<");
- if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
- xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
- xmlOutputBufferWrite(buf, 1, ":");
- }
+ if (cur->content != NULL) {
+ xmlOutputBufferWrite(buf, 2, "<?");
+ xmlOutputBufferWriteString(buf, (const char *)cur->name);
+ if (cur->content != NULL) {
+ if (ctxt->format == 2)
+ xmlOutputBufferWriteWSNonSig(ctxt, 0);
+ else
+ xmlOutputBufferWrite(buf, 1, " ");
+ xmlOutputBufferWriteString(buf,
+ (const char *)cur->content);
+ }
+ xmlOutputBufferWrite(buf, 2, "?>");
+ } else {
+ xmlOutputBufferWrite(buf, 2, "<?");
+ xmlOutputBufferWriteString(buf, (const char *)cur->name);
+ if (ctxt->format == 2)
+ xmlOutputBufferWriteWSNonSig(ctxt, 0);
+ xmlOutputBufferWrite(buf, 2, "?>");
+ }
+ break;
- xmlOutputBufferWriteString(buf, (const char *)cur->name);
- if (cur->nsDef)
- xmlNsListDumpOutputCtxt(ctxt, cur->nsDef);
- if (cur->properties != NULL)
- xmlAttrListDumpOutput(ctxt, cur->properties);
-
- if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) &&
- (cur->children == NULL) && ((ctxt->options & XML_SAVE_NO_EMPTY) == 0)) {
- if (ctxt->format == 2)
- xmlOutputBufferWriteWSNonSig(ctxt, 0);
- xmlOutputBufferWrite(buf, 2, "/>");
- ctxt->format = format;
- return;
- }
- if (ctxt->format == 2)
- xmlOutputBufferWriteWSNonSig(ctxt, 1);
- xmlOutputBufferWrite(buf, 1, ">");
- if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
- xmlOutputBufferWriteEscape(buf, cur->content, ctxt->escape);
- }
- if (cur->children != NULL) {
- if (ctxt->format == 1) xmlOutputBufferWrite(buf, 1, "\n");
- if (ctxt->level >= 0) ctxt->level++;
- xmlNodeListDumpOutput(ctxt, cur->children);
- if (ctxt->level > 0) ctxt->level--;
- if ((xmlIndentTreeOutput) && (ctxt->format == 1))
- xmlOutputBufferWrite(buf, ctxt->indent_size *
- (ctxt->level > ctxt->indent_nr ?
- ctxt->indent_nr : ctxt->level),
- ctxt->indent);
- }
- xmlOutputBufferWrite(buf, 2, "</");
- if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
- xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
- xmlOutputBufferWrite(buf, 1, ":");
- }
+ case XML_COMMENT_NODE:
+ if ((cur != root) && (ctxt->format == 1) && (xmlIndentTreeOutput))
+ xmlOutputBufferWrite(buf, ctxt->indent_size *
+ (ctxt->level > ctxt->indent_nr ?
+ ctxt->indent_nr : ctxt->level),
+ ctxt->indent);
- xmlOutputBufferWriteString(buf, (const char *)cur->name);
- if (ctxt->format == 2)
- xmlOutputBufferWriteWSNonSig(ctxt, 0);
- xmlOutputBufferWrite(buf, 1, ">");
- ctxt->format = format;
+ if (cur->content != NULL) {
+ xmlOutputBufferWrite(buf, 4, "<!--");
+ xmlOutputBufferWriteString(buf, (const char *)cur->content);
+ xmlOutputBufferWrite(buf, 3, "-->");
+ }
+ break;
+
+ case XML_ENTITY_REF_NODE:
+ xmlOutputBufferWrite(buf, 1, "&");
+ xmlOutputBufferWriteString(buf, (const char *)cur->name);
+ xmlOutputBufferWrite(buf, 1, ";");
+ break;
+
+ case XML_CDATA_SECTION_NODE:
+ if (cur->content == NULL || *cur->content == '\0') {
+ xmlOutputBufferWrite(buf, 12, "<![CDATA[]]>");
+ } else {
+ start = end = cur->content;
+ while (*end != '\0') {
+ if ((*end == ']') && (*(end + 1) == ']') &&
+ (*(end + 2) == '>')) {
+ end = end + 2;
+ xmlOutputBufferWrite(buf, 9, "<![CDATA[");
+ xmlOutputBufferWrite(buf, end - start,
+ (const char *)start);
+ xmlOutputBufferWrite(buf, 3, "]]>");
+ start = end;
+ }
+ end++;
+ }
+ if (start != end) {
+ xmlOutputBufferWrite(buf, 9, "<![CDATA[");
+ xmlOutputBufferWriteString(buf, (const char *)start);
+ xmlOutputBufferWrite(buf, 3, "]]>");
+ }
+ }
+ break;
+
+ case XML_ATTRIBUTE_NODE:
+ xmlAttrDumpOutput(ctxt, (xmlAttrPtr) cur);
+ break;
+
+ case XML_NAMESPACE_DECL:
+ xmlNsDumpOutputCtxt(ctxt, (xmlNsPtr) cur);
+ break;
+
+ default:
+ break;
+ }
+
+ while (1) {
+ if (cur == root)
+ return;
+ if (ctxt->format == 1) {
+ xmlOutputBufferWrite(buf, 1, "\n");
+ }
+ if (cur->next != NULL) {
+ cur = cur->next;
+ break;
+ }
+
+ cur = cur->parent;
+
+ if (ctxt->level > 0) ctxt->level--;
+ if ((xmlIndentTreeOutput) && (ctxt->format == 1))
+ xmlOutputBufferWrite(buf, ctxt->indent_size *
+ (ctxt->level > ctxt->indent_nr ?
+ ctxt->indent_nr : ctxt->level),
+ ctxt->indent);
+ if (cur == unformattedNode) {
+ ctxt->format = format;
+ unformattedNode = NULL;
+ }
+
+ xmlOutputBufferWrite(buf, 2, "</");
+ if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
+ xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
+ xmlOutputBufferWrite(buf, 1, ":");
+ }
+
+ xmlOutputBufferWriteString(buf, (const char *)cur->name);
+ if (ctxt->format == 2)
+ xmlOutputBufferWriteWSNonSig(ctxt, 0);
+ xmlOutputBufferWrite(buf, 1, ">");
+ }
+ }
}
/**
@@ -1865,12 +1862,25 @@ xmlSaveDoc(xmlSaveCtxtPtr ctxt, xmlDocPtr doc)
* Returns the number of byte written or -1 in case of error
*/
long
-xmlSaveTree(xmlSaveCtxtPtr ctxt, xmlNodePtr node)
+xmlSaveTree(xmlSaveCtxtPtr ctxt, xmlNodePtr cur)
{
long ret = 0;
- if ((ctxt == NULL) || (node == NULL)) return(-1);
- xmlNodeDumpOutputInternal(ctxt, node);
+ if ((ctxt == NULL) || (cur == NULL)) return(-1);
+#ifdef LIBXML_HTML_ENABLED
+ if (ctxt->options & XML_SAVE_XHTML) {
+ xhtmlNodeDumpOutput(ctxt, cur);
+ return(ret);
+ }
+ if (((cur->type != XML_NAMESPACE_DECL) && (cur->doc != NULL) &&
+ (cur->doc->type == XML_HTML_DOCUMENT_NODE) &&
+ ((ctxt->options & XML_SAVE_AS_XML) == 0)) ||
+ (ctxt->options & XML_SAVE_AS_HTML)) {
+ htmlNodeDumpOutputInternal(ctxt, cur);
+ return(ret);
+ }
+#endif
+ xmlNodeDumpOutputInternal(ctxt, cur);
return(ret);
}
--
1.8.3.1

View File

@ -1,361 +0,0 @@
From 1a3e584a5af0f6ffc6f80a3caa192eb8c0389611 Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
Date: Tue, 21 Jan 2020 22:12:42 +0100
Subject: [PATCH] Merge code paths loading external entities
Merge xmlParseCtxtExternalEntity into xmlParseExternalEntityPrivate.
---
parser.c | 282 ++++++++++++++++-----------------------------------------------
1 file changed, 72 insertions(+), 210 deletions(-)
diff --git a/parser.c b/parser.c
index 5ff8592..0ca58e8 100644
--- a/parser.c
+++ b/parser.c
@@ -12891,189 +12891,21 @@ xmlParseDTD(const xmlChar *ExternalID, const xmlChar *SystemID) {
int
xmlParseCtxtExternalEntity(xmlParserCtxtPtr ctx, const xmlChar *URL,
const xmlChar *ID, xmlNodePtr *lst) {
- xmlParserCtxtPtr ctxt;
- xmlDocPtr newDoc;
- xmlNodePtr newRoot;
- xmlSAXHandlerPtr oldsax = NULL;
- int ret = 0;
- xmlChar start[4];
- xmlCharEncoding enc;
+ void *userData;
if (ctx == NULL) return(-1);
-
- if (((ctx->depth > 40) && ((ctx->options & XML_PARSE_HUGE) == 0)) ||
- (ctx->depth > 1024)) {
- return(XML_ERR_ENTITY_LOOP);
- }
-
- if (lst != NULL)
- *lst = NULL;
- if ((URL == NULL) && (ID == NULL))
- return(-1);
- if (ctx->myDoc == NULL) /* @@ relax but check for dereferences */
- return(-1);
-
- ctxt = xmlCreateEntityParserCtxtInternal(URL, ID, NULL, ctx);
- if (ctxt == NULL) {
- return(-1);
- }
-
- oldsax = ctxt->sax;
- ctxt->sax = ctx->sax;
- xmlDetectSAX2(ctxt);
- newDoc = xmlNewDoc(BAD_CAST "1.0");
- if (newDoc == NULL) {
- xmlFreeParserCtxt(ctxt);
- return(-1);
- }
- newDoc->properties = XML_DOC_INTERNAL;
- if (ctx->myDoc->dict) {
- newDoc->dict = ctx->myDoc->dict;
- xmlDictReference(newDoc->dict);
- }
- if (ctx->myDoc != NULL) {
- newDoc->intSubset = ctx->myDoc->intSubset;
- newDoc->extSubset = ctx->myDoc->extSubset;
- }
- if (ctx->myDoc->URL != NULL) {
- newDoc->URL = xmlStrdup(ctx->myDoc->URL);
- }
- newRoot = xmlNewDocNode(newDoc, NULL, BAD_CAST "pseudoroot", NULL);
- if (newRoot == NULL) {
- ctxt->sax = oldsax;
- xmlFreeParserCtxt(ctxt);
- newDoc->intSubset = NULL;
- newDoc->extSubset = NULL;
- xmlFreeDoc(newDoc);
- return(-1);
- }
- xmlAddChild((xmlNodePtr) newDoc, newRoot);
- nodePush(ctxt, newDoc->children);
- if (ctx->myDoc == NULL) {
- ctxt->myDoc = newDoc;
- } else {
- ctxt->myDoc = ctx->myDoc;
- newDoc->children->doc = ctx->myDoc;
- }
-
/*
- * Get the 4 first bytes and decode the charset
- * if enc != XML_CHAR_ENCODING_NONE
- * plug some encoding conversion routines.
- */
- GROW
- if ((ctxt->input->end - ctxt->input->cur) >= 4) {
- start[0] = RAW;
- start[1] = NXT(1);
- start[2] = NXT(2);
- start[3] = NXT(3);
- enc = xmlDetectCharEncoding(start, 4);
- if (enc != XML_CHAR_ENCODING_NONE) {
- xmlSwitchEncoding(ctxt, enc);
- }
- }
-
- /*
- * Parse a possible text declaration first
- */
- if ((CMP5(CUR_PTR, '<', '?', 'x', 'm', 'l')) && (IS_BLANK_CH(NXT(5)))) {
- xmlParseTextDecl(ctxt);
- /*
- * An XML-1.0 document can't reference an entity not XML-1.0
- */
- if ((xmlStrEqual(ctx->version, BAD_CAST "1.0")) &&
- (!xmlStrEqual(ctxt->input->version, BAD_CAST "1.0"))) {
- xmlFatalErrMsg(ctxt, XML_ERR_VERSION_MISMATCH,
- "Version mismatch between document and entity\n");
- }
- }
-
- /*
- * If the user provided its own SAX callbacks then reuse the
- * useData callback field, otherwise the expected setup in a
+ * If the user provided their own SAX callbacks, then reuse the
+ * userData callback field, otherwise the expected setup in a
* DOM builder is to have userData == ctxt
*/
if (ctx->userData == ctx)
- ctxt->userData = ctxt;
+ userData = NULL;
else
- ctxt->userData = ctx->userData;
-
- /*
- * Doing validity checking on chunk doesn't make sense
- */
- ctxt->instate = XML_PARSER_CONTENT;
- ctxt->validate = ctx->validate;
- ctxt->valid = ctx->valid;
- ctxt->loadsubset = ctx->loadsubset;
- ctxt->depth = ctx->depth + 1;
- ctxt->replaceEntities = ctx->replaceEntities;
- if (ctxt->validate) {
- ctxt->vctxt.error = ctx->vctxt.error;
- ctxt->vctxt.warning = ctx->vctxt.warning;
- } else {
- ctxt->vctxt.error = NULL;
- ctxt->vctxt.warning = NULL;
- }
- ctxt->vctxt.nodeTab = NULL;
- ctxt->vctxt.nodeNr = 0;
- ctxt->vctxt.nodeMax = 0;
- ctxt->vctxt.node = NULL;
- if (ctxt->dict != NULL) xmlDictFree(ctxt->dict);
- ctxt->dict = ctx->dict;
- ctxt->str_xml = xmlDictLookup(ctxt->dict, BAD_CAST "xml", 3);
- ctxt->str_xmlns = xmlDictLookup(ctxt->dict, BAD_CAST "xmlns", 5);
- ctxt->str_xml_ns = xmlDictLookup(ctxt->dict, XML_XML_NAMESPACE, 36);
- ctxt->dictNames = ctx->dictNames;
- ctxt->attsDefault = ctx->attsDefault;
- ctxt->attsSpecial = ctx->attsSpecial;
- ctxt->linenumbers = ctx->linenumbers;
-
- xmlParseContent(ctxt);
-
- ctx->validate = ctxt->validate;
- ctx->valid = ctxt->valid;
- if ((RAW == '<') && (NXT(1) == '/')) {
- xmlFatalErr(ctxt, XML_ERR_NOT_WELL_BALANCED, NULL);
- } else if (RAW != 0) {
- xmlFatalErr(ctxt, XML_ERR_EXTRA_CONTENT, NULL);
- }
- if (ctxt->node != newDoc->children) {
- xmlFatalErr(ctxt, XML_ERR_NOT_WELL_BALANCED, NULL);
- }
-
- if (!ctxt->wellFormed) {
- if (ctxt->errNo == 0)
- ret = 1;
- else
- ret = ctxt->errNo;
- } else {
- if (lst != NULL) {
- xmlNodePtr cur;
-
- /*
- * Return the newly created nodeset after unlinking it from
- * they pseudo parent.
- */
- cur = newDoc->children->children;
- *lst = cur;
- while (cur != NULL) {
- cur->parent = NULL;
- cur = cur->next;
- }
- newDoc->children->children = NULL;
- }
- ret = 0;
- }
- ctxt->sax = oldsax;
- ctxt->dict = NULL;
- ctxt->attsDefault = NULL;
- ctxt->attsSpecial = NULL;
- xmlFreeParserCtxt(ctxt);
- newDoc->intSubset = NULL;
- newDoc->extSubset = NULL;
- xmlFreeDoc(newDoc);
-
- return(ret);
+ userData = ctx->userData;
+ return xmlParseExternalEntityPrivate(ctx->myDoc, ctx, ctx->sax,
+ userData, ctx->depth + 1,
+ URL, ID, lst);
}
/**
@@ -13123,25 +12955,6 @@ xmlParseExternalEntityPrivate(xmlDocPtr doc, xmlParserCtxtPtr oldctxt,
ctxt = xmlCreateEntityParserCtxtInternal(URL, ID, NULL, oldctxt);
if (ctxt == NULL) return(XML_WAR_UNDECLARED_ENTITY);
ctxt->userData = ctxt;
- if (oldctxt != NULL) {
- ctxt->_private = oldctxt->_private;
- ctxt->loadsubset = oldctxt->loadsubset;
- ctxt->validate = oldctxt->validate;
- ctxt->external = oldctxt->external;
- ctxt->record_info = oldctxt->record_info;
- ctxt->node_seq.maximum = oldctxt->node_seq.maximum;
- ctxt->node_seq.length = oldctxt->node_seq.length;
- ctxt->node_seq.buffer = oldctxt->node_seq.buffer;
- } else {
- /*
- * Doing validity checking on chunk without context
- * doesn't make sense
- */
- ctxt->_private = NULL;
- ctxt->validate = 0;
- ctxt->external = 2;
- ctxt->loadsubset = 0;
- }
if (sax != NULL) {
oldsax = ctxt->sax;
ctxt->sax = sax;
@@ -13151,28 +12964,25 @@ xmlParseExternalEntityPrivate(xmlDocPtr doc, xmlParserCtxtPtr oldctxt,
xmlDetectSAX2(ctxt);
newDoc = xmlNewDoc(BAD_CAST "1.0");
if (newDoc == NULL) {
- ctxt->node_seq.maximum = 0;
- ctxt->node_seq.length = 0;
- ctxt->node_seq.buffer = NULL;
xmlFreeParserCtxt(ctxt);
return(XML_ERR_INTERNAL_ERROR);
}
newDoc->properties = XML_DOC_INTERNAL;
- newDoc->intSubset = doc->intSubset;
- newDoc->extSubset = doc->extSubset;
- newDoc->dict = doc->dict;
- xmlDictReference(newDoc->dict);
-
- if (doc->URL != NULL) {
- newDoc->URL = xmlStrdup(doc->URL);
+ if (doc) {
+ newDoc->intSubset = doc->intSubset;
+ newDoc->extSubset = doc->extSubset;
+ if (doc->dict) {
+ newDoc->dict = doc->dict;
+ xmlDictReference(newDoc->dict);
+ }
+ if (doc->URL != NULL) {
+ newDoc->URL = xmlStrdup(doc->URL);
+ }
}
newRoot = xmlNewDocNode(newDoc, NULL, BAD_CAST "pseudoroot", NULL);
if (newRoot == NULL) {
if (sax != NULL)
ctxt->sax = oldsax;
- ctxt->node_seq.maximum = 0;
- ctxt->node_seq.length = 0;
- ctxt->node_seq.buffer = NULL;
xmlFreeParserCtxt(ctxt);
newDoc->intSubset = NULL;
newDoc->extSubset = NULL;
@@ -13181,8 +12991,12 @@ xmlParseExternalEntityPrivate(xmlDocPtr doc, xmlParserCtxtPtr oldctxt,
}
xmlAddChild((xmlNodePtr) newDoc, newRoot);
nodePush(ctxt, newDoc->children);
- ctxt->myDoc = doc;
- newRoot->doc = doc;
+ if (doc == NULL) {
+ ctxt->myDoc = newDoc;
+ } else {
+ ctxt->myDoc = doc;
+ newRoot->doc = doc;
+ }
/*
* Get the 4 first bytes and decode the charset
@@ -13206,10 +13020,53 @@ xmlParseExternalEntityPrivate(xmlDocPtr doc, xmlParserCtxtPtr oldctxt,
*/
if ((CMP5(CUR_PTR, '<', '?', 'x', 'm', 'l')) && (IS_BLANK_CH(NXT(5)))) {
xmlParseTextDecl(ctxt);
+ /*
+ * An XML-1.0 document can't reference an entity not XML-1.0
+ */
+ if ((xmlStrEqual(oldctxt->version, BAD_CAST "1.0")) &&
+ (!xmlStrEqual(ctxt->input->version, BAD_CAST "1.0"))) {
+ xmlFatalErrMsg(ctxt, XML_ERR_VERSION_MISMATCH,
+ "Version mismatch between document and entity\n");
+ }
}
ctxt->instate = XML_PARSER_CONTENT;
ctxt->depth = depth;
+ if (oldctxt != NULL) {
+ ctxt->_private = oldctxt->_private;
+ ctxt->loadsubset = oldctxt->loadsubset;
+ ctxt->validate = oldctxt->validate;
+ ctxt->valid = oldctxt->valid;
+ ctxt->replaceEntities = oldctxt->replaceEntities;
+ if (oldctxt->validate) {
+ ctxt->vctxt.error = oldctxt->vctxt.error;
+ ctxt->vctxt.warning = oldctxt->vctxt.warning;
+ ctxt->vctxt.userData = oldctxt->vctxt.userData;
+ }
+ ctxt->external = oldctxt->external;
+ if (ctxt->dict) xmlDictFree(ctxt->dict);
+ ctxt->dict = oldctxt->dict;
+ ctxt->str_xml = xmlDictLookup(ctxt->dict, BAD_CAST "xml", 3);
+ ctxt->str_xmlns = xmlDictLookup(ctxt->dict, BAD_CAST "xmlns", 5);
+ ctxt->str_xml_ns = xmlDictLookup(ctxt->dict, XML_XML_NAMESPACE, 36);
+ ctxt->dictNames = oldctxt->dictNames;
+ ctxt->attsDefault = oldctxt->attsDefault;
+ ctxt->attsSpecial = oldctxt->attsSpecial;
+ ctxt->linenumbers = oldctxt->linenumbers;
+ ctxt->record_info = oldctxt->record_info;
+ ctxt->node_seq.maximum = oldctxt->node_seq.maximum;
+ ctxt->node_seq.length = oldctxt->node_seq.length;
+ ctxt->node_seq.buffer = oldctxt->node_seq.buffer;
+ } else {
+ /*
+ * Doing validity checking on chunk without context
+ * doesn't make sense
+ */
+ ctxt->_private = NULL;
+ ctxt->validate = 0;
+ ctxt->external = 2;
+ ctxt->loadsubset = 0;
+ }
xmlParseContent(ctxt);
@@ -13269,6 +13126,11 @@ xmlParseExternalEntityPrivate(xmlDocPtr doc, xmlParserCtxtPtr oldctxt,
if (sax != NULL)
ctxt->sax = oldsax;
if (oldctxt != NULL) {
+ ctxt->dict = NULL;
+ ctxt->attsDefault = NULL;
+ ctxt->attsSpecial = NULL;
+ oldctxt->validate = ctxt->validate;
+ oldctxt->valid = ctxt->valid;
oldctxt->node_seq.maximum = ctxt->node_seq.maximum;
oldctxt->node_seq.length = ctxt->node_seq.length;
oldctxt->node_seq.buffer = ctxt->node_seq.buffer;
--
1.8.3.1

View File

@ -1,70 +0,0 @@
From a28f7d8789e63f5e2ac63b42083754cba58f1a0e Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
Date: Wed, 10 Jun 2020 13:41:13 +0200
Subject: [PATCH] Never expand parameter entities in text declaration
When parsing the text declaration of external DTDs or entities, make
sure that parameter entities are not expanded. This also fixes a memory
leak in certain error cases.
The change to xmlSkipBlankChars assumes that the parser state is
maintained correctly when parsing external DTDs or parameter entities,
and might expose bugs in the code that were hidden previously.
Found by OSS-Fuzz.
---
parser.c | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/parser.c b/parser.c
index 046f1cec3..3559aaaec 100644
--- a/parser.c
+++ b/parser.c
@@ -2156,7 +2156,7 @@ xmlSkipBlankChars(xmlParserCtxtPtr ctxt) {
* It's Okay to use CUR/NEXT here since all the blanks are on
* the ASCII range.
*/
- if ((ctxt->inputNr == 1) && (ctxt->instate != XML_PARSER_DTD)) {
+ if (ctxt->instate != XML_PARSER_DTD) {
const xmlChar *cur;
/*
* if we are in the document content, go really fast
@@ -6852,6 +6852,7 @@ void
xmlParseTextDecl(xmlParserCtxtPtr ctxt) {
xmlChar *version;
const xmlChar *encoding;
+ int oldstate;
/*
* We know that '<?xml' is here.
@@ -6863,6 +6864,10 @@ xmlParseTextDecl(xmlParserCtxtPtr ctxt) {
return;
}
+ /* Avoid expansion of parameter entities when skipping blanks. */
+ oldstate = ctxt->instate;
+ ctxt->instate = XML_PARSER_START;
+
if (SKIP_BLANKS == 0) {
xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED,
"Space needed after '<?xml'\n");
@@ -6890,6 +6895,7 @@ xmlParseTextDecl(xmlParserCtxtPtr ctxt) {
/*
* The XML REC instructs us to stop parsing right here
*/
+ ctxt->instate = oldstate;
return;
}
if ((encoding == NULL) && (ctxt->errNo == XML_ERR_OK)) {
@@ -6909,6 +6915,8 @@ xmlParseTextDecl(xmlParserCtxtPtr ctxt) {
MOVETO_ENDTAG(CUR_PTR);
NEXT;
}
+
+ ctxt->instate = oldstate;
}
/**
--
GitLab

View File

@ -1,77 +0,0 @@
From d724861536f3cfb82750176aa45e655634bbbbcc Mon Sep 17 00:00:00 2001
From: raniervf <ranier_gyn@hotmail.com>
Date: Mon, 4 Nov 2019 23:19:28 -0300
Subject: [PATCH] Null pointer handling in catalog.c
Fix potential deferencing potential null pointers;
Small optimizations.
Closes #123.
---
catalog.c | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/catalog.c b/catalog.c
index 7328fd3..b471e8a 100644
--- a/catalog.c
+++ b/catalog.c
@@ -924,7 +924,7 @@ xmlParseCatalogFile(const char *filename) {
xmlBufResetInput(buf->buffer, inputStream);
inputPush(ctxt, inputStream);
- if ((ctxt->directory == NULL) && (directory == NULL))
+ if (ctxt->directory == NULL)
directory = xmlParserGetDirectory(filename);
if ((ctxt->directory == NULL) && (directory != NULL))
ctxt->directory = directory;
@@ -2069,8 +2069,7 @@ xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
ret = xmlCatalogXMLResolve(catal->children, pubID, sysID);
if (ret != NULL) {
break;
- } else if ((catal->children != NULL) &&
- (catal->children->depth > MAX_CATAL_DEPTH)) {
+ } else if (catal->children->depth > MAX_CATAL_DEPTH) {
ret = NULL;
break;
}
@@ -2353,7 +2352,7 @@ xmlParseSGMLCatalog(xmlCatalogPtr catal, const xmlChar *value,
xmlCatalogEntryType type = XML_CATA_NONE;
cur = xmlParseSGMLCatalogName(cur, &name);
- if (name == NULL) {
+ if (cur == NULL || name == NULL) {
/* error */
break;
}
@@ -3254,6 +3253,7 @@ xmlLoadCatalogs(const char *pathss) {
while ((*cur != 0) && (*cur != PATH_SEPARATOR) && (!xmlIsBlank_ch(*cur)))
cur++;
path = xmlStrndup((const xmlChar *)paths, cur - paths);
+ if (path != NULL) {
#ifdef _WIN32
iLen = strlen((const char*)path);
for(i = 0; i < iLen; i++) {
@@ -3262,7 +3262,6 @@ xmlLoadCatalogs(const char *pathss) {
}
}
#endif
- if (path != NULL) {
xmlLoadCatalog((const char *) path);
xmlFree(path);
}
@@ -3427,9 +3426,10 @@ xmlCatalogAdd(const xmlChar *type, const xmlChar *orig, const xmlChar *replace)
(xmlStrEqual(type, BAD_CAST "catalog"))) {
xmlDefaultCatalog = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE,
xmlCatalogDefaultPrefer);
- xmlDefaultCatalog->xml = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
+ if (xmlDefaultCatalog != NULL) {
+ xmlDefaultCatalog->xml = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
orig, NULL, xmlCatalogDefaultPrefer, NULL);
-
+ }
xmlRMutexUnlock(xmlCatalogMutex);
return(0);
}
--
1.8.3.1

View File

@ -1,103 +0,0 @@
From 74dcc10b556cc4d1088a2496f7e93f8a8040447e Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
Date: Mon, 17 Aug 2020 03:24:56 +0200
Subject: [PATCH] Remove dead code in xinclude.c
'doc' is checked for NULL in xmlXIncludeLoadDoc, so several code
paths can be eliminated.
---
xinclude.c | 43 ++++++-------------------------------------
1 file changed, 6 insertions(+), 37 deletions(-)
diff --git a/xinclude.c b/xinclude.c
index 2423a93..36bdfae 100644
--- a/xinclude.c
+++ b/xinclude.c
@@ -59,7 +59,6 @@ struct _xmlXIncludeRef {
xmlNodePtr inc; /* the included copy */
int xml; /* xml or txt */
int count; /* how many refs use that specific doc */
- xmlXPathObjectPtr xptr; /* the xpointer if needed */
int skip; /* skip in case of errors */
int fallback; /* fallback was loaded */
};
@@ -211,8 +210,6 @@ xmlXIncludeFreeRef(xmlXIncludeRefPtr ref) {
xmlFree(ref->URI);
if (ref->fragment != NULL)
xmlFree(ref->fragment);
- if (ref->xptr != NULL)
- xmlXPathFreeObject(ref->xptr);
xmlFree(ref);
}
@@ -1557,15 +1554,8 @@ loaded:
/*
* Add the top children list as the replacement copy.
*/
- if (doc == NULL)
- {
- /* Hopefully a DTD declaration won't be copied from
- * the same document */
- ctxt->incTab[nr]->inc = xmlCopyNodeList(ctxt->doc->children);
- } else {
- ctxt->incTab[nr]->inc = xmlXIncludeCopyNodeList(ctxt, ctxt->doc,
- doc, doc->children);
- }
+ ctxt->incTab[nr]->inc = xmlXIncludeCopyNodeList(ctxt, ctxt->doc,
+ doc, doc->children);
}
#ifdef LIBXML_XPTR_ENABLED
else {
@@ -1577,12 +1567,7 @@ loaded:
xmlXPathContextPtr xptrctxt;
xmlNodeSetPtr set;
- if (doc == NULL) {
- xptrctxt = xmlXPtrNewContext(ctxt->doc, ctxt->incTab[nr]->ref,
- NULL);
- } else {
- xptrctxt = xmlXPtrNewContext(doc, NULL, NULL);
- }
+ xptrctxt = xmlXPtrNewContext(doc, NULL, NULL);
if (xptrctxt == NULL) {
xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
XML_XINCLUDE_XPTR_FAILED,
@@ -1686,14 +1671,9 @@ loaded:
}
}
}
- if (doc == NULL) {
- ctxt->incTab[nr]->xptr = xptr;
- ctxt->incTab[nr]->inc = NULL;
- } else {
- ctxt->incTab[nr]->inc =
- xmlXIncludeCopyXPointer(ctxt, ctxt->doc, doc, xptr);
- xmlXPathFreeObject(xptr);
- }
+ ctxt->incTab[nr]->inc =
+ xmlXIncludeCopyXPointer(ctxt, ctxt->doc, doc, xptr);
+ xmlXPathFreeObject(xptr);
xmlXPathFreeContext(xptrctxt);
xmlFree(fragment);
}
@@ -2212,17 +2192,6 @@ xmlXIncludeIncludeNode(xmlXIncludeCtxtPtr ctxt, int nr) {
if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
return(-1);
- /*
- * If we stored an XPointer a late computation may be needed
- */
- if ((ctxt->incTab[nr]->inc == NULL) &&
- (ctxt->incTab[nr]->xptr != NULL)) {
- ctxt->incTab[nr]->inc =
- xmlXIncludeCopyXPointer(ctxt, ctxt->doc, ctxt->doc,
- ctxt->incTab[nr]->xptr);
- xmlXPathFreeObject(ctxt->incTab[nr]->xptr);
- ctxt->incTab[nr]->xptr = NULL;
- }
list = ctxt->incTab[nr]->inc;
ctxt->incTab[nr]->inc = NULL;
--
1.8.3.1

View File

@ -1,26 +0,0 @@
From f8329fdc234a43b858271acc75ea70881e35fcae Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
Date: Thu, 2 Jul 2020 11:51:31 +0200
Subject: [PATCH] Report error for invalid regexp quantifiers
---
xmlregexp.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/xmlregexp.c b/xmlregexp.c
index 0272dcab..687290e2 100644
--- a/xmlregexp.c
+++ b/xmlregexp.c
@@ -5268,6 +5268,9 @@ xmlFAParseQuantifier(xmlRegParserCtxtPtr ctxt) {
cur = xmlFAParseQuantExact(ctxt);
if (cur >= 0)
min = cur;
+ else {
+ ERROR("Improper quantifier");
+ }
if (CUR == ',') {
NEXT;
if (CUR == '}')
--
2.23.0

View File

@ -1,49 +0,0 @@
From 3f18e7486d5feb8ae41911ce3c122e05641a4c3d Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
Date: Sat, 11 Jul 2020 14:34:57 +0200
Subject: [PATCH] Reset HTML parser input before reporting error
Avoid use-after-free, similar to 13ba5b61. Also make sure that
xmlBufSetInputBaseCur sets valid pointers in case of buffer errors.
Found by OSS-Fuzz.
diff --git a/HTMLparser.c b/HTMLparser.c
index 9b12dd1..1dea794 100644
--- a/HTMLparser.c
+++ b/HTMLparser.c
@@ -6150,12 +6150,12 @@ htmlParseChunk(htmlParserCtxtPtr ctxt, const char *chunk, int size,
int res;
res = xmlParserInputBufferPush(ctxt->input->buf, size, chunk);
+ xmlBufSetInputBaseCur(ctxt->input->buf->buffer, ctxt->input, base, cur);
if (res < 0) {
ctxt->errNo = XML_PARSER_EOF;
ctxt->disableSAX = 1;
return (XML_PARSER_EOF);
}
- xmlBufSetInputBaseCur(ctxt->input->buf->buffer, ctxt->input, base, cur);
#ifdef DEBUG_PUSH
xmlGenericError(xmlGenericErrorContext, "HPP: pushed %d\n", size);
#endif
diff --git a/buf.c b/buf.c
index 8ad18a1..24368d3 100644
--- a/buf.c
+++ b/buf.c
@@ -1334,8 +1334,12 @@ xmlBufGetInputBase(xmlBufPtr buf, xmlParserInputPtr input) {
int
xmlBufSetInputBaseCur(xmlBufPtr buf, xmlParserInputPtr input,
size_t base, size_t cur) {
- if ((input == NULL) || (buf == NULL) || (buf->error))
+ if (input == NULL)
+ return(-1);
+ if ((buf == NULL) || (buf->error)) {
+ input->base = input->cur = input->end = BAD_CAST "";
return(-1);
+ }
CHECK_COMPAT(buf)
input->base = &buf->content[base];
input->cur = input->base + cur;
--
1.8.3.1

View File

@ -1,67 +0,0 @@
From 19cae17f5a2acfbd5554d145bb87cd6bf2de244f Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
Date: Wed, 19 Aug 2020 13:07:28 +0200
Subject: [PATCH] Revert "Fix quadratic runtime in xi:fallback processing"
This reverts commit 27119ec33c9f6b9830efa1e0da0acfa353dfa55a.
Not copying fallback children didn't fix up namespaces and could lead
to use-after-free errors.
Found by OSS-Fuzz.
---
xinclude.c | 23 ++++++++++++-----------
1 file changed, 12 insertions(+), 11 deletions(-)
diff --git a/xinclude.c b/xinclude.c
index 3c810ca..9024535 100644
--- a/xinclude.c
+++ b/xinclude.c
@@ -1984,7 +1984,8 @@ xmlXIncludeLoadFallback(xmlXIncludeCtxtPtr ctxt, xmlNodePtr fallback, int nr) {
ret = -1;
xmlXIncludeFreeContext(newctxt);
- ctxt->incTab[nr]->inc = fallback->children;
+ ctxt->incTab[nr]->inc = xmlDocCopyNodeList(ctxt->doc,
+ fallback->children);
} else {
ctxt->incTab[nr]->inc = NULL;
}
@@ -2240,6 +2241,12 @@ xmlXIncludeIncludeNode(xmlXIncludeCtxtPtr ctxt, int nr) {
if (ctxt->incTab[nr]->fallback)
xmlUnsetProp(cur, BAD_CAST "href");
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,
@@ -2255,17 +2262,11 @@ xmlXIncludeIncludeNode(xmlXIncludeCtxtPtr ctxt, int nr) {
* Add the list of nodes
*/
while (list != NULL) {
- next = list->next;
- xmlAddPrevSibling(end, list);
- list = next;
- }
+ cur = list;
+ list = list->next;
- /* Remove fallback node */
- for (child = cur->children; child != NULL; child = next) {
- next = child->next;
- xmlUnlinkNode(child);
- xmlFreeNode(child);
- }
+ xmlAddPrevSibling(end, cur);
+ }
}
--
1.8.3.1

View File

@ -1,54 +0,0 @@
From a6e6498fb1d11f08c394ecbf69add6cfff815db0 Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
Date: Tue, 2 Mar 2021 13:09:06 +0100
Subject: [PATCH] Stop checking attributes for UTF-8 validity
I can't see a reason to check attribute content for UTF-8 validity.
Other parts of the API like xmlNewText have always assumed valid UTF-8
as extra checks only slow down processing.
Besides, setting doc->encoding to "ISO-8859-1" seems pointless, and not
freeing the old encoding would cause a memory leak.
Note that this was last changed in 2008 with commit 6f8611fd which
removed unnecessary encoding/decoding steps. Setting attributes should
be even faster now.
Found by OSS-Fuzz.
---
tree.c | 12 ------------
1 file changed, 12 deletions(-)
diff --git a/tree.c b/tree.c
index 617e818..17db445 100644
--- a/tree.c
+++ b/tree.c
@@ -1901,12 +1901,6 @@ xmlNewPropInternal(xmlNodePtr node, xmlNsPtr ns,
if (value != NULL) {
xmlNodePtr tmp;
- if(!xmlCheckUTF8(value)) {
- xmlTreeErr(XML_TREE_NOT_UTF8, (xmlNodePtr) doc,
- NULL);
- if (doc != NULL)
- doc->encoding = xmlStrdup(BAD_CAST "ISO-8859-1");
- }
cur->children = xmlNewDocText(doc, value);
cur->last = NULL;
tmp = cur->children;
@@ -6945,12 +6939,6 @@ xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
if (value != NULL) {
xmlNodePtr tmp;
- if(!xmlCheckUTF8(value)) {
- xmlTreeErr(XML_TREE_NOT_UTF8, (xmlNodePtr) node->doc,
- NULL);
- if (node->doc != NULL)
- node->doc->encoding = xmlStrdup(BAD_CAST "ISO-8859-1");
- }
prop->children = xmlNewDocText(node->doc, value);
prop->last = NULL;
tmp = prop->children;
--
1.8.3.1

View File

@ -1,43 +0,0 @@
From 804c52978fef3f18b8a634280bc5cc79a390c141 Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
Date: Mon, 17 Aug 2020 03:37:18 +0200
Subject: [PATCH] Stop using maxParserDepth in xpath.c
Only use a single maxDepth value.
Conflict:delete contents of fuzz/xpath.c
---
xpath.c | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/xpath.c b/xpath.c
index 673482a..c018d03 100644
--- a/xpath.c
+++ b/xpath.c
@@ -6119,7 +6119,6 @@ xmlXPathNewContext(xmlDocPtr doc) {
ret->proximityPosition = -1;
ret->maxDepth = INT_MAX;
- ret->maxParserDepth = INT_MAX;
#ifdef XP_DEFAULT_CACHE_ON
if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
@@ -10948,9 +10947,13 @@ xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
xmlXPathContextPtr xpctxt = ctxt->context;
if (xpctxt != NULL) {
- if (xpctxt->depth >= xpctxt->maxParserDepth)
+ if (xpctxt->depth >= xpctxt->maxDepth)
XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
- xpctxt->depth += 1;
+ /*
+ * Parsing a single '(' pushes about 10 functions on the call stack
+ * before recursing!
+ */
+ xpctxt->depth += 10;
}
xmlXPathCompAndExpr(ctxt);
--
1.8.3.1

View File

@ -1,27 +0,0 @@
From 3c8a3e9922cb1203ab5998ec542ce1e4c7fd085a Mon Sep 17 00:00:00 2001
From: Ranier Vilela <ranier_gyn@hotmail.com>
Date: Thu, 7 Nov 2019 12:59:10 +0000
Subject: [PATCH] Use random seed in xmlDictComputeFastKey
xmlDictComputeFastKey is only used for small tables, so this shouldn't
be a security problem.
---
dict.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dict.c b/dict.c
index 336e046..26ce516 100644
--- a/dict.c
+++ b/dict.c
@@ -452,7 +452,7 @@ xmlDictComputeFastKey(const xmlChar *name, int namelen, int seed) {
unsigned long value = seed;
if (name == NULL) return(0);
- value = *name;
+ value += *name;
value <<= 5;
if (namelen > 10) {
value += name[namelen - 1];
--
1.8.3.1

View File

@ -1,306 +0,0 @@
From 32cb5dccda6d9c72aaa1717d7100277b755cca94 Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
Date: Tue, 11 Feb 2020 13:16:10 +0100
Subject: [PATCH] Add test case for recursive external parsed entities
---
result/errors/rec_ext_ent.xml | 5 +
result/errors/rec_ext_ent.xml.ent | 243 ++++++++++++++++++++++++++++++
result/errors/rec_ext_ent.xml.err | 0
result/errors/rec_ext_ent.xml.str | 0
test/errors/rec_ext.ent | 1 +
test/errors/rec_ext_ent.xml | 4 +
6 files changed, 253 insertions(+)
create mode 100644 result/errors/rec_ext_ent.xml
create mode 100644 result/errors/rec_ext_ent.xml.ent
create mode 100644 result/errors/rec_ext_ent.xml.err
create mode 100644 result/errors/rec_ext_ent.xml.str
create mode 100644 test/errors/rec_ext.ent
create mode 100644 test/errors/rec_ext_ent.xml
diff --git a/result/errors/rec_ext_ent.xml b/result/errors/rec_ext_ent.xml
new file mode 100644
index 00000000..6a196cb5
--- /dev/null
+++ b/result/errors/rec_ext_ent.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0"?>
+<!DOCTYPE doc [
+<!ENTITY e SYSTEM "rec_ext.ent">
+]>
+<doc>&e; &e; &e; &e;</doc>
diff --git a/result/errors/rec_ext_ent.xml.ent b/result/errors/rec_ext_ent.xml.ent
new file mode 100644
index 00000000..30dd2854
--- /dev/null
+++ b/result/errors/rec_ext_ent.xml.ent
@@ -0,0 +1,243 @@
+test/errors/rec_ext.ent:1: parser error : Detected an entity reference loop
+<ent>&e; &e; &e; &e;</ent>
+ ^
+test/errors/rec_ext.ent:2: parser error : chunk is not well balanced
+
+^
+test/errors/rec_ext.ent:1: parser error : Entity 'e' failed to parse
+<ent>&e; &e; &e; &e;</ent>
+ ^
+test/errors/rec_ext.ent:2: parser error : chunk is not well balanced
+
+^
+test/errors/rec_ext.ent:1: parser error : Entity 'e' failed to parse
+<ent>&e; &e; &e; &e;</ent>
+ ^
+test/errors/rec_ext.ent:2: parser error : chunk is not well balanced
+
+^
+test/errors/rec_ext.ent:1: parser error : Entity 'e' failed to parse
+<ent>&e; &e; &e; &e;</ent>
+ ^
+test/errors/rec_ext.ent:2: parser error : chunk is not well balanced
+
+^
+test/errors/rec_ext.ent:1: parser error : Entity 'e' failed to parse
+<ent>&e; &e; &e; &e;</ent>
+ ^
+test/errors/rec_ext.ent:2: parser error : chunk is not well balanced
+
+^
+test/errors/rec_ext.ent:1: parser error : Entity 'e' failed to parse
+<ent>&e; &e; &e; &e;</ent>
+ ^
+test/errors/rec_ext.ent:2: parser error : chunk is not well balanced
+
+^
+test/errors/rec_ext.ent:1: parser error : Entity 'e' failed to parse
+<ent>&e; &e; &e; &e;</ent>
+ ^
+test/errors/rec_ext.ent:2: parser error : chunk is not well balanced
+
+^
+test/errors/rec_ext.ent:1: parser error : Entity 'e' failed to parse
+<ent>&e; &e; &e; &e;</ent>
+ ^
+test/errors/rec_ext.ent:2: parser error : chunk is not well balanced
+
+^
+test/errors/rec_ext.ent:1: parser error : Entity 'e' failed to parse
+<ent>&e; &e; &e; &e;</ent>
+ ^
+test/errors/rec_ext.ent:2: parser error : chunk is not well balanced
+
+^
+test/errors/rec_ext.ent:1: parser error : Entity 'e' failed to parse
+<ent>&e; &e; &e; &e;</ent>
+ ^
+test/errors/rec_ext.ent:2: parser error : chunk is not well balanced
+
+^
+test/errors/rec_ext.ent:1: parser error : Entity 'e' failed to parse
+<ent>&e; &e; &e; &e;</ent>
+ ^
+test/errors/rec_ext.ent:2: parser error : chunk is not well balanced
+
+^
+test/errors/rec_ext.ent:1: parser error : Entity 'e' failed to parse
+<ent>&e; &e; &e; &e;</ent>
+ ^
+test/errors/rec_ext.ent:2: parser error : chunk is not well balanced
+
+^
+test/errors/rec_ext.ent:1: parser error : Entity 'e' failed to parse
+<ent>&e; &e; &e; &e;</ent>
+ ^
+test/errors/rec_ext.ent:2: parser error : chunk is not well balanced
+
+^
+test/errors/rec_ext.ent:1: parser error : Entity 'e' failed to parse
+<ent>&e; &e; &e; &e;</ent>
+ ^
+test/errors/rec_ext.ent:2: parser error : chunk is not well balanced
+
+^
+test/errors/rec_ext.ent:1: parser error : Entity 'e' failed to parse
+<ent>&e; &e; &e; &e;</ent>
+ ^
+test/errors/rec_ext.ent:2: parser error : chunk is not well balanced
+
+^
+test/errors/rec_ext.ent:1: parser error : Entity 'e' failed to parse
+<ent>&e; &e; &e; &e;</ent>
+ ^
+test/errors/rec_ext.ent:2: parser error : chunk is not well balanced
+
+^
+test/errors/rec_ext.ent:1: parser error : Entity 'e' failed to parse
+<ent>&e; &e; &e; &e;</ent>
+ ^
+test/errors/rec_ext.ent:2: parser error : chunk is not well balanced
+
+^
+test/errors/rec_ext.ent:1: parser error : Entity 'e' failed to parse
+<ent>&e; &e; &e; &e;</ent>
+ ^
+test/errors/rec_ext.ent:2: parser error : chunk is not well balanced
+
+^
+test/errors/rec_ext.ent:1: parser error : Entity 'e' failed to parse
+<ent>&e; &e; &e; &e;</ent>
+ ^
+test/errors/rec_ext.ent:2: parser error : chunk is not well balanced
+
+^
+test/errors/rec_ext.ent:1: parser error : Entity 'e' failed to parse
+<ent>&e; &e; &e; &e;</ent>
+ ^
+test/errors/rec_ext.ent:2: parser error : chunk is not well balanced
+
+^
+test/errors/rec_ext.ent:1: parser error : Entity 'e' failed to parse
+<ent>&e; &e; &e; &e;</ent>
+ ^
+test/errors/rec_ext.ent:2: parser error : chunk is not well balanced
+
+^
+test/errors/rec_ext.ent:1: parser error : Entity 'e' failed to parse
+<ent>&e; &e; &e; &e;</ent>
+ ^
+test/errors/rec_ext.ent:2: parser error : chunk is not well balanced
+
+^
+test/errors/rec_ext.ent:1: parser error : Entity 'e' failed to parse
+<ent>&e; &e; &e; &e;</ent>
+ ^
+test/errors/rec_ext.ent:2: parser error : chunk is not well balanced
+
+^
+test/errors/rec_ext.ent:1: parser error : Entity 'e' failed to parse
+<ent>&e; &e; &e; &e;</ent>
+ ^
+test/errors/rec_ext.ent:2: parser error : chunk is not well balanced
+
+^
+test/errors/rec_ext.ent:1: parser error : Entity 'e' failed to parse
+<ent>&e; &e; &e; &e;</ent>
+ ^
+test/errors/rec_ext.ent:2: parser error : chunk is not well balanced
+
+^
+test/errors/rec_ext.ent:1: parser error : Entity 'e' failed to parse
+<ent>&e; &e; &e; &e;</ent>
+ ^
+test/errors/rec_ext.ent:2: parser error : chunk is not well balanced
+
+^
+test/errors/rec_ext.ent:1: parser error : Entity 'e' failed to parse
+<ent>&e; &e; &e; &e;</ent>
+ ^
+test/errors/rec_ext.ent:2: parser error : chunk is not well balanced
+
+^
+test/errors/rec_ext.ent:1: parser error : Entity 'e' failed to parse
+<ent>&e; &e; &e; &e;</ent>
+ ^
+test/errors/rec_ext.ent:2: parser error : chunk is not well balanced
+
+^
+test/errors/rec_ext.ent:1: parser error : Entity 'e' failed to parse
+<ent>&e; &e; &e; &e;</ent>
+ ^
+test/errors/rec_ext.ent:2: parser error : chunk is not well balanced
+
+^
+test/errors/rec_ext.ent:1: parser error : Detected an entity reference loop
+<ent>&e; &e; &e; &e;</ent>
+ ^
+test/errors/rec_ext.ent:2: parser error : chunk is not well balanced
+
+^
+test/errors/rec_ext.ent:1: parser error : Detected an entity reference loop
+<ent>&e; &e; &e; &e;</ent>
+ ^
+test/errors/rec_ext.ent:2: parser error : chunk is not well balanced
+
+^
+test/errors/rec_ext.ent:1: parser error : Detected an entity reference loop
+<ent>&e; &e; &e; &e;</ent>
+ ^
+test/errors/rec_ext.ent:2: parser error : chunk is not well balanced
+
+^
+test/errors/rec_ext.ent:1: parser error : Detected an entity reference loop
+<ent>&e; &e; &e; &e;</ent>
+ ^
+test/errors/rec_ext.ent:2: parser error : chunk is not well balanced
+
+^
+test/errors/rec_ext.ent:1: parser error : Detected an entity reference loop
+<ent>&e; &e; &e; &e;</ent>
+ ^
+test/errors/rec_ext.ent:2: parser error : chunk is not well balanced
+
+^
+test/errors/rec_ext.ent:1: parser error : Detected an entity reference loop
+<ent>&e; &e; &e; &e;</ent>
+ ^
+test/errors/rec_ext.ent:2: parser error : chunk is not well balanced
+
+^
+test/errors/rec_ext.ent:1: parser error : Detected an entity reference loop
+<ent>&e; &e; &e; &e;</ent>
+ ^
+test/errors/rec_ext.ent:2: parser error : chunk is not well balanced
+
+^
+test/errors/rec_ext.ent:1: parser error : Detected an entity reference loop
+<ent>&e; &e; &e; &e;</ent>
+ ^
+test/errors/rec_ext.ent:2: parser error : chunk is not well balanced
+
+^
+test/errors/rec_ext.ent:1: parser error : Detected an entity reference loop
+<ent>&e; &e; &e; &e;</ent>
+ ^
+test/errors/rec_ext.ent:2: parser error : chunk is not well balanced
+
+^
+test/errors/rec_ext.ent:1: parser error : Detected an entity reference loop
+<ent>&e; &e; &e; &e;</ent>
+ ^
+test/errors/rec_ext.ent:2: parser error : chunk is not well balanced
+
+^
+test/errors/rec_ext.ent:1: parser error : Detected an entity reference loop
+<ent>&e; &e; &e; &e;</ent>
+ ^
+test/errors/rec_ext.ent:2: parser error : chunk is not well balanced
+
+^
+./test/errors/rec_ext_ent.xml:4: parser error : Entity 'e' failed to parse
+<doc>&e; &e; &e; &e;</doc>
+ ^
diff --git a/result/errors/rec_ext_ent.xml.err b/result/errors/rec_ext_ent.xml.err
new file mode 100644
index 00000000..e69de29b
diff --git a/result/errors/rec_ext_ent.xml.str b/result/errors/rec_ext_ent.xml.str
new file mode 100644
index 00000000..e69de29b
diff --git a/test/errors/rec_ext.ent b/test/errors/rec_ext.ent
new file mode 100644
index 00000000..345f836f
--- /dev/null
+++ b/test/errors/rec_ext.ent
@@ -0,0 +1 @@
+<ent>&e; &e; &e; &e;</ent>
diff --git a/test/errors/rec_ext_ent.xml b/test/errors/rec_ext_ent.xml
new file mode 100644
index 00000000..b4e7e749
--- /dev/null
+++ b/test/errors/rec_ext_ent.xml
@@ -0,0 +1,4 @@
+<!DOCTYPE doc [
+ <!ENTITY e SYSTEM "rec_ext.ent">
+]>
+<doc>&e; &e; &e; &e;</doc>
--
2.27.0

View File

@ -1,34 +0,0 @@
From 31c6ce3b63f8a494ad9e31ca65187a73d8ad3508 Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
Date: Mon, 9 Nov 2020 17:55:44 +0100
Subject: [PATCH] Avoid call stack overflow with XML reader and recursive
XIncludes
Don't process XIncludes in the result of another inclusion to avoid
infinite recursion resulting in a call stack overflow.
This is something the XInclude engine shouldn't allow but correct
handling of intra-document includes would require major changes.
Found by OSS-Fuzz.
---
xmlreader.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/xmlreader.c b/xmlreader.c
index 01adf74f..72e40b03 100644
--- a/xmlreader.c
+++ b/xmlreader.c
@@ -1585,7 +1585,8 @@ node_found:
/*
* Handle XInclude if asked for
*/
- if ((reader->xinclude) && (reader->node != NULL) &&
+ if ((reader->xinclude) && (reader->in_xinclude == 0) &&
+ (reader->node != NULL) &&
(reader->node->type == XML_ELEMENT_NODE) &&
(reader->node->ns != NULL) &&
((xmlStrEqual(reader->node->ns->href, XINCLUDE_NS)) ||
--
2.27.0

View File

@ -1,48 +0,0 @@
From babe75030c7f64a37826bb3342317134568bef61 Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
Date: Sat, 1 May 2021 16:53:33 +0200
Subject: [PATCH] Propagate error in xmlParseElementChildrenContentDeclPriv
Check return value of recursive calls to
xmlParseElementChildrenContentDeclPriv and return immediately in case
of errors. Otherwise, struct xmlElementContent could contain unexpected
null pointers, leading to a null deref when post-validating documents
which aren't well-formed and parsed in recovery mode.
Fixes #243.
Reference:https://github.com/GNOME/libxml2/commit/babe75030c7f64a37826bb3342317134568bef61
Conflict:NA
---
parser.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/parser.c b/parser.c
index b42e604..73c27ed 100644
--- a/parser.c
+++ b/parser.c
@@ -6208,6 +6208,8 @@ xmlParseElementChildrenContentDeclPriv(xmlParserCtxtPtr ctxt, int inputchk,
SKIP_BLANKS;
cur = ret = xmlParseElementChildrenContentDeclPriv(ctxt, inputid,
depth + 1);
+ if (cur == NULL)
+ return(NULL);
SKIP_BLANKS;
GROW;
} else {
@@ -6341,6 +6343,11 @@ xmlParseElementChildrenContentDeclPriv(xmlParserCtxtPtr ctxt, int inputchk,
SKIP_BLANKS;
last = xmlParseElementChildrenContentDeclPriv(ctxt, inputid,
depth + 1);
+ if (last == NULL) {
+ if (ret != NULL)
+ xmlFreeDocElementContent(ctxt->myDoc, ret);
+ return(NULL);
+ }
SKIP_BLANKS;
} else {
elem = xmlParseName(ctxt);
--
1.8.3.1

View File

@ -1,286 +0,0 @@
From 8e219b154e9b938af84c4b009aefa692020103f9 Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
Date: Sun, 12 Jul 2020 21:43:44 +0200
Subject: [PATCH] Fix HTML push parser lookahead
The parsing rules when looking for terminating chars or sequences in
the push parser differed from the actual parsing code. This could
result in the lookahead to overshoot and data being rescanned,
potentially leading to quadratic runtime.
Comments must never be handled during lookahead. Attribute values must
only be skipped for start tags and doctype declarations, not for end
tags, comments, PIs and script content.
---
HTMLparser.c | 88 +++++++++++++---------------------------------------
1 file changed, 21 insertions(+), 67 deletions(-)
diff --git a/HTMLparser.c b/HTMLparser.c
index 06d8c602..d10cf11f 100644
--- a/HTMLparser.c
+++ b/HTMLparser.c
@@ -5136,7 +5136,7 @@ htmlCreateDocParserCtxt(const xmlChar *cur, const char *encoding) {
* @first: the first char to lookup
* @next: the next char to lookup or zero
* @third: the next char to lookup or zero
- * @comment: flag to force checking inside comments
+ * @ignoreattrval: skip over attribute values
*
* Try to find if a sequence (first, next, third) or just (first next) or
* (first) is available in the input stream.
@@ -5150,13 +5150,11 @@ htmlCreateDocParserCtxt(const xmlChar *cur, const char *encoding) {
*/
static int
htmlParseLookupSequence(htmlParserCtxtPtr ctxt, xmlChar first,
- xmlChar next, xmlChar third, int iscomment,
- int ignoreattrval)
+ xmlChar next, xmlChar third, int ignoreattrval)
{
int base, len;
htmlParserInputPtr in;
const xmlChar *buf;
- int incomment = 0;
int invalue = 0;
char valdellim = 0x0;
@@ -5171,8 +5169,7 @@ htmlParseLookupSequence(htmlParserCtxtPtr ctxt, xmlChar first,
if (ctxt->checkIndex > base) {
base = ctxt->checkIndex;
/* Abuse hasPErefs member to restore current state. */
- incomment = ctxt->hasPErefs & 1 ? 1 : 0;
- invalue = ctxt->hasPErefs & 2 ? 1 : 0;
+ invalue = ctxt->hasPErefs & 1 ? 1 : 0;
}
if (in->buf == NULL) {
@@ -5189,14 +5186,6 @@ htmlParseLookupSequence(htmlParserCtxtPtr ctxt, xmlChar first,
else if (next)
len--;
for (; base < len; base++) {
- if ((!incomment) && (base + 4 < len) && (!iscomment)) {
- if ((buf[base] == '<') && (buf[base + 1] == '!') &&
- (buf[base + 2] == '-') && (buf[base + 3] == '-')) {
- incomment = 1;
- /* do not increment past <! - some people use <!--> */
- base += 2;
- }
- }
if (ignoreattrval) {
if (buf[base] == '"' || buf[base] == '\'') {
if (invalue) {
@@ -5213,16 +5202,6 @@ htmlParseLookupSequence(htmlParserCtxtPtr ctxt, xmlChar first,
continue;
}
}
- if (incomment) {
- if (base + 3 > len)
- break;
- if ((buf[base] == '-') && (buf[base + 1] == '-') &&
- (buf[base + 2] == '>')) {
- incomment = 0;
- base += 2;
- }
- continue;
- }
if (buf[base] == first) {
if (third != 0) {
if ((buf[base + 1] != next) || (buf[base + 2] != third))
@@ -5251,11 +5230,10 @@ htmlParseLookupSequence(htmlParserCtxtPtr ctxt, xmlChar first,
}
ctxt->checkIndex = base;
/* Abuse hasPErefs member to track current state. */
- ctxt->hasPErefs = 0;
- if (incomment)
- ctxt->hasPErefs |= 1;
if (invalue)
- ctxt->hasPErefs |= 2;
+ ctxt->hasPErefs |= 1;
+ else
+ ctxt->hasPErefs &= ~1;
#ifdef DEBUG_PUSH
if (next == 0)
xmlGenericError(xmlGenericErrorContext,
@@ -5293,7 +5271,6 @@ htmlParseLookupChars(htmlParserCtxtPtr ctxt, const xmlChar * stop,
int base, len;
htmlParserInputPtr in;
const xmlChar *buf;
- int incomment = 0;
int i;
in = ctxt->input;
@@ -5304,11 +5281,8 @@ htmlParseLookupChars(htmlParserCtxtPtr ctxt, const xmlChar * stop,
if (base < 0)
return (-1);
- if (ctxt->checkIndex > base) {
+ if (ctxt->checkIndex > base)
base = ctxt->checkIndex;
- /* Abuse hasPErefs member to restore current state. */
- incomment = ctxt->hasPErefs & 1 ? 1 : 0;
- }
if (in->buf == NULL) {
buf = in->base;
@@ -5319,24 +5293,6 @@ htmlParseLookupChars(htmlParserCtxtPtr ctxt, const xmlChar * stop,
}
for (; base < len; base++) {
- if (!incomment && (base + 4 < len)) {
- if ((buf[base] == '<') && (buf[base + 1] == '!') &&
- (buf[base + 2] == '-') && (buf[base + 3] == '-')) {
- incomment = 1;
- /* do not increment past <! - some people use <!--> */
- base += 2;
- }
- }
- if (incomment) {
- if (base + 3 > len)
- break;
- if ((buf[base] == '-') && (buf[base + 1] == '-') &&
- (buf[base + 2] == '>')) {
- incomment = 0;
- base += 2;
- }
- continue;
- }
for (i = 0; i < stopLen; ++i) {
if (buf[base] == stop[i]) {
ctxt->checkIndex = 0;
@@ -5345,8 +5301,6 @@ htmlParseLookupChars(htmlParserCtxtPtr ctxt, const xmlChar * stop,
}
}
ctxt->checkIndex = base;
- /* Abuse hasPErefs member to track current state. */
- ctxt->hasPErefs = incomment;
return (-1);
}
@@ -5489,7 +5443,7 @@ htmlParseTryOrFinish(htmlParserCtxtPtr ctxt, int terminate) {
(UPP(6) == 'Y') && (UPP(7) == 'P') &&
(UPP(8) == 'E')) {
if ((!terminate) &&
- (htmlParseLookupSequence(ctxt, '>', 0, 0, 0, 1) < 0))
+ (htmlParseLookupSequence(ctxt, '>', 0, 0, 1) < 0))
goto done;
#ifdef DEBUG_PUSH
xmlGenericError(xmlGenericErrorContext,
@@ -5536,7 +5490,7 @@ htmlParseTryOrFinish(htmlParserCtxtPtr ctxt, int terminate) {
if ((cur == '<') && (next == '!') &&
(in->cur[2] == '-') && (in->cur[3] == '-')) {
if ((!terminate) &&
- (htmlParseLookupSequence(ctxt, '-', '-', '>', 1, 1) < 0))
+ (htmlParseLookupSequence(ctxt, '-', '-', '>', 0) < 0))
goto done;
#ifdef DEBUG_PUSH
xmlGenericError(xmlGenericErrorContext,
@@ -5546,7 +5500,7 @@ htmlParseTryOrFinish(htmlParserCtxtPtr ctxt, int terminate) {
ctxt->instate = XML_PARSER_MISC;
} else if ((cur == '<') && (next == '?')) {
if ((!terminate) &&
- (htmlParseLookupSequence(ctxt, '>', 0, 0, 0, 1) < 0))
+ (htmlParseLookupSequence(ctxt, '>', 0, 0, 0) < 0))
goto done;
#ifdef DEBUG_PUSH
xmlGenericError(xmlGenericErrorContext,
@@ -5560,7 +5514,7 @@ htmlParseTryOrFinish(htmlParserCtxtPtr ctxt, int terminate) {
(UPP(6) == 'Y') && (UPP(7) == 'P') &&
(UPP(8) == 'E')) {
if ((!terminate) &&
- (htmlParseLookupSequence(ctxt, '>', 0, 0, 0, 1) < 0))
+ (htmlParseLookupSequence(ctxt, '>', 0, 0, 1) < 0))
goto done;
#ifdef DEBUG_PUSH
xmlGenericError(xmlGenericErrorContext,
@@ -5597,7 +5551,7 @@ htmlParseTryOrFinish(htmlParserCtxtPtr ctxt, int terminate) {
if ((cur == '<') && (next == '!') &&
(in->cur[2] == '-') && (in->cur[3] == '-')) {
if ((!terminate) &&
- (htmlParseLookupSequence(ctxt, '-', '-', '>', 1, 1) < 0))
+ (htmlParseLookupSequence(ctxt, '-', '-', '>', 0) < 0))
goto done;
#ifdef DEBUG_PUSH
xmlGenericError(xmlGenericErrorContext,
@@ -5607,7 +5561,7 @@ htmlParseTryOrFinish(htmlParserCtxtPtr ctxt, int terminate) {
ctxt->instate = XML_PARSER_PROLOG;
} else if ((cur == '<') && (next == '?')) {
if ((!terminate) &&
- (htmlParseLookupSequence(ctxt, '>', 0, 0, 0, 1) < 0))
+ (htmlParseLookupSequence(ctxt, '>', 0, 0, 0) < 0))
goto done;
#ifdef DEBUG_PUSH
xmlGenericError(xmlGenericErrorContext,
@@ -5645,7 +5599,7 @@ htmlParseTryOrFinish(htmlParserCtxtPtr ctxt, int terminate) {
if ((cur == '<') && (next == '!') &&
(in->cur[2] == '-') && (in->cur[3] == '-')) {
if ((!terminate) &&
- (htmlParseLookupSequence(ctxt, '-', '-', '>', 1, 1) < 0))
+ (htmlParseLookupSequence(ctxt, '-', '-', '>', 0) < 0))
goto done;
#ifdef DEBUG_PUSH
xmlGenericError(xmlGenericErrorContext,
@@ -5655,7 +5609,7 @@ htmlParseTryOrFinish(htmlParserCtxtPtr ctxt, int terminate) {
ctxt->instate = XML_PARSER_EPILOG;
} else if ((cur == '<') && (next == '?')) {
if ((!terminate) &&
- (htmlParseLookupSequence(ctxt, '>', 0, 0, 0, 1) < 0))
+ (htmlParseLookupSequence(ctxt, '>', 0, 0, 0) < 0))
goto done;
#ifdef DEBUG_PUSH
xmlGenericError(xmlGenericErrorContext,
@@ -5719,7 +5673,7 @@ htmlParseTryOrFinish(htmlParserCtxtPtr ctxt, int terminate) {
break;
}
if ((!terminate) &&
- (htmlParseLookupSequence(ctxt, '>', 0, 0, 0, 1) < 0))
+ (htmlParseLookupSequence(ctxt, '>', 0, 0, 1) < 0))
goto done;
/* Capture start position */
@@ -5866,7 +5820,7 @@ htmlParseTryOrFinish(htmlParserCtxtPtr ctxt, int terminate) {
int idx;
xmlChar val;
- idx = htmlParseLookupSequence(ctxt, '<', '/', 0, 0, 0);
+ idx = htmlParseLookupSequence(ctxt, '<', '/', 0, 0);
if (idx < 0)
goto done;
val = in->cur[idx + 2];
@@ -5893,7 +5847,7 @@ htmlParseTryOrFinish(htmlParserCtxtPtr ctxt, int terminate) {
(UPP(6) == 'Y') && (UPP(7) == 'P') &&
(UPP(8) == 'E')) {
if ((!terminate) &&
- (htmlParseLookupSequence(ctxt, '>', 0, 0, 0, 1) < 0))
+ (htmlParseLookupSequence(ctxt, '>', 0, 0, 1) < 0))
goto done;
htmlParseErr(ctxt, XML_HTML_STRUCURE_ERROR,
"Misplaced DOCTYPE declaration\n",
@@ -5903,7 +5857,7 @@ htmlParseTryOrFinish(htmlParserCtxtPtr ctxt, int terminate) {
(in->cur[2] == '-') && (in->cur[3] == '-')) {
if ((!terminate) &&
(htmlParseLookupSequence(
- ctxt, '-', '-', '>', 1, 1) < 0))
+ ctxt, '-', '-', '>', 0) < 0))
goto done;
#ifdef DEBUG_PUSH
xmlGenericError(xmlGenericErrorContext,
@@ -5913,7 +5867,7 @@ htmlParseTryOrFinish(htmlParserCtxtPtr ctxt, int terminate) {
ctxt->instate = XML_PARSER_CONTENT;
} else if ((cur == '<') && (next == '?')) {
if ((!terminate) &&
- (htmlParseLookupSequence(ctxt, '>', 0, 0, 0, 1) < 0))
+ (htmlParseLookupSequence(ctxt, '>', 0, 0, 0) < 0))
goto done;
#ifdef DEBUG_PUSH
xmlGenericError(xmlGenericErrorContext,
@@ -5984,7 +5938,7 @@ htmlParseTryOrFinish(htmlParserCtxtPtr ctxt, int terminate) {
if (avail < 2)
goto done;
if ((!terminate) &&
- (htmlParseLookupSequence(ctxt, '>', 0, 0, 0, 1) < 0))
+ (htmlParseLookupSequence(ctxt, '>', 0, 0, 0) < 0))
goto done;
htmlParseEndTag(ctxt);
if (ctxt->nameNr == 0) {
--
2.27.0

View File

@ -1,31 +0,0 @@
From 954696e7cf236c3aa71dc0b7f9e70d3f51e5cb07 Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
Date: Sun, 7 Feb 2021 13:23:09 +0100
Subject: [PATCH] Fix infinite loop in HTML parser introduced with recent
commits
Check for XML_PARSER_EOF to avoid an infinite loop introduced with
recent changes to the HTML push parser.
Found by OSS-Fuzz.
---
HTMLparser.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/HTMLparser.c b/HTMLparser.c
index 2877f4b7..14cc56fa 100644
--- a/HTMLparser.c
+++ b/HTMLparser.c
@@ -5872,7 +5872,8 @@ htmlParseTryOrFinish(htmlParserCtxtPtr ctxt, int terminate) {
xmlGenericError(xmlGenericErrorContext,
"HPP: Parsing char data\n");
#endif
- while ((cur != '<') && (in->cur < in->end)) {
+ while ((ctxt->instate != XML_PARSER_EOF) &&
+ (cur != '<') && (in->cur < in->end)) {
if (cur == '&') {
htmlParseReference(ctxt);
} else {
--
2.27.0

View File

@ -1,99 +0,0 @@
From 8ca3a59b2ee57e2f30272272bb232c84d03b9edc Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
Date: Tue, 15 Dec 2020 20:14:28 +0100
Subject: [PATCH] Fix integer overflow in xmlSchemaGetParticleTotalRangeMin
The function is only used once and its return value is only checked for
zero. Disable the function like its Max counterpart and add an
implementation for the special case.
Found by OSS-Fuzz.
---
xmlschemas.c | 50 +++++++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 45 insertions(+), 5 deletions(-)
diff --git a/xmlschemas.c b/xmlschemas.c
index c455b4a3..1efd0962 100644
--- a/xmlschemas.c
+++ b/xmlschemas.c
@@ -14721,6 +14721,7 @@ xmlSchemaGetUnionSimpleTypeMemberTypes(xmlSchemaTypePtr type)
return (NULL);
}
+#if 0
/**
* xmlSchemaGetParticleTotalRangeMin:
* @particle: the particle
@@ -14776,7 +14777,6 @@ xmlSchemaGetParticleTotalRangeMin(xmlSchemaParticlePtr particle)
}
}
-#if 0
/**
* xmlSchemaGetParticleTotalRangeMax:
* @particle: the particle
@@ -14838,6 +14838,48 @@ xmlSchemaGetParticleTotalRangeMax(xmlSchemaParticlePtr particle)
}
#endif
+/**
+ * xmlSchemaGetParticleEmptiable:
+ * @particle: the particle
+ *
+ * Returns 1 if emptiable, 0 otherwise.
+ */
+static int
+xmlSchemaGetParticleEmptiable(xmlSchemaParticlePtr particle)
+{
+ xmlSchemaParticlePtr part;
+ int emptiable;
+
+ if ((particle->children == NULL) || (particle->minOccurs == 0))
+ return (1);
+
+ part = (xmlSchemaParticlePtr) particle->children->children;
+ if (part == NULL)
+ return (1);
+
+ while (part != NULL) {
+ if ((part->children->type == XML_SCHEMA_TYPE_ELEMENT) ||
+ (part->children->type == XML_SCHEMA_TYPE_ANY))
+ emptiable = (part->minOccurs == 0);
+ else
+ emptiable = xmlSchemaGetParticleEmptiable(part);
+ if (particle->children->type == XML_SCHEMA_TYPE_CHOICE) {
+ if (emptiable)
+ return (1);
+ } else {
+ /* <all> and <sequence> */
+ if (!emptiable)
+ return (0);
+ }
+ part = (xmlSchemaParticlePtr) part->next;
+ }
+
+ if (particle->children->type == XML_SCHEMA_TYPE_CHOICE)
+ return (0);
+ else
+ return (1);
+}
+
/**
* xmlSchemaIsParticleEmptiable:
* @particle: the particle
@@ -14860,10 +14902,8 @@ xmlSchemaIsParticleEmptiable(xmlSchemaParticlePtr particle)
* SPEC (2) "Its {term} is a group and the minimum part of the
* effective total range of that group, [...] is 0."
*/
- if (WXS_IS_MODEL_GROUP(particle->children)) {
- if (xmlSchemaGetParticleTotalRangeMin(particle) == 0)
- return (1);
- }
+ if (WXS_IS_MODEL_GROUP(particle->children))
+ return (xmlSchemaGetParticleEmptiable(particle));
return (0);
}
--
2.27.0

View File

@ -1,31 +0,0 @@
From b7520f8a61b48a9f265f711fa7a0bebf2175bed7 Mon Sep 17 00:00:00 2001
From: Zhipeng Xie <xiezhipeng1@huawei.com>
Date: Tue, 20 Aug 2019 16:33:06 +0800
Subject: [PATCH] Fix memory leak in xmlSchemaValidateStream
When ctxt->schema is NULL, xmlSchemaSAXPlug->xmlSchemaPreRun
alloc a new schema for ctxt->schema and set vctxt->xsiAssemble
to 1. Then xmlSchemaVStart->xmlSchemaPreRun initialize
vctxt->xsiAssemble to 0 again which cause the alloced schema
can not be freed anymore.
Signed-off-by: Zhipeng Xie <xiezhipeng1@huawei.com>
---
xmlschemas.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/xmlschemas.c b/xmlschemas.c
index 019988a..005d8f1 100644
--- a/xmlschemas.c
+++ b/xmlschemas.c
@@ -28111,7 +28111,6 @@ xmlSchemaPreRun(xmlSchemaValidCtxtPtr vctxt) {
vctxt->nberrors = 0;
vctxt->depth = -1;
vctxt->skipDepth = -1;
- vctxt->xsiAssemble = 0;
vctxt->hasKeyrefs = 0;
#ifdef ENABLE_IDC_NODE_TABLES_TEST
vctxt->createIDCNodeTables = 1;
--
2.19.1

File diff suppressed because one or more lines are too long

View File

@ -1,33 +0,0 @@
From 94c2e415a9bc1b9e7b7210a9c73817106bb1f175 Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
Date: Sun, 6 Dec 2020 16:38:00 +0100
Subject: [PATCH] Fix quadratic runtime in HTML push parser with null bytes
Null bytes in the input stream do not necessarily signal an EOF
condition. Check the stream pointers for EOF to avoid quadratic
rescanning of input data.
Note that the CUR_CHAR macro used in functions like htmlParseCharData
calls htmlCurrentChar which translates null bytes.
Found by OSS-Fuzz.
---
HTMLparser.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/HTMLparser.c b/HTMLparser.c
index de624f8d..26a1cdc2 100644
--- a/HTMLparser.c
+++ b/HTMLparser.c
@@ -5832,7 +5832,7 @@ htmlParseTryOrFinish(htmlParserCtxtPtr ctxt, int terminate) {
xmlGenericError(xmlGenericErrorContext,
"HPP: Parsing char data\n");
#endif
- while ((cur != '<') && (cur != 0)) {
+ while ((cur != '<') && (in->cur < in->end)) {
if (cur == '&') {
htmlParseReference(ctxt);
} else {
--
2.27.0

View File

@ -1,128 +0,0 @@
From 6995eed077899c64d34fe8f0d0b34d214cf586af Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
Date: Sun, 19 Jul 2020 13:54:52 +0200
Subject: [PATCH] Fix quadratic runtime when push parsing HTML entity refs
The HTML push parser would look ahead for characters in "; >/" to
terminate an entity reference but actual parsing could stop earlier,
potentially resulting in quadratic runtime.
Parse char data and references alternately in htmlParseTryOrFinish
and only look ahead once for a terminating '<' character.
Found by OSS-Fuzz.
---
HTMLparser.c | 77 ++++++----------------------------------------------
1 file changed, 9 insertions(+), 68 deletions(-)
diff --git a/HTMLparser.c b/HTMLparser.c
index d10cf11f..ad9d7ccc 100644
--- a/HTMLparser.c
+++ b/HTMLparser.c
@@ -5249,61 +5249,6 @@ htmlParseLookupSequence(htmlParserCtxtPtr ctxt, xmlChar first,
return (-1);
}
-/**
- * htmlParseLookupChars:
- * @ctxt: an HTML parser context
- * @stop: Array of chars, which stop the lookup.
- * @stopLen: Length of stop-Array
- *
- * Try to find if any char of the stop-Array is available in the input
- * stream.
- * This function has a side effect of (possibly) incrementing ctxt->checkIndex
- * to avoid rescanning sequences of bytes, it DOES change the state of the
- * parser, do not use liberally.
- *
- * Returns the index to the current parsing point if a stopChar
- * is available, -1 otherwise.
- */
-static int
-htmlParseLookupChars(htmlParserCtxtPtr ctxt, const xmlChar * stop,
- int stopLen)
-{
- int base, len;
- htmlParserInputPtr in;
- const xmlChar *buf;
- int i;
-
- in = ctxt->input;
- if (in == NULL)
- return (-1);
-
- base = in->cur - in->base;
- if (base < 0)
- return (-1);
-
- if (ctxt->checkIndex > base)
- base = ctxt->checkIndex;
-
- if (in->buf == NULL) {
- buf = in->base;
- len = in->length;
- } else {
- buf = xmlBufContent(in->buf->buffer);
- len = xmlBufUse(in->buf->buffer);
- }
-
- for (; base < len; base++) {
- for (i = 0; i < stopLen; ++i) {
- if (buf[base] == stop[i]) {
- ctxt->checkIndex = 0;
- return (base - (in->cur - in->base));
- }
- }
- }
- ctxt->checkIndex = base;
- return (-1);
-}
-
/**
* htmlParseTryOrFinish:
* @ctxt: an HTML parser context
@@ -5893,17 +5838,6 @@ htmlParseTryOrFinish(htmlParserCtxtPtr ctxt, int terminate) {
"HPP: entering START_TAG\n");
#endif
break;
- } else if (cur == '&') {
- if ((!terminate) &&
- (htmlParseLookupChars(ctxt,
- BAD_CAST "; >/", 4) < 0))
- goto done;
-#ifdef DEBUG_PUSH
- xmlGenericError(xmlGenericErrorContext,
- "HPP: Parsing Reference\n");
-#endif
- /* TODO: check generation of subtrees if noent !!! */
- htmlParseReference(ctxt);
} else {
/*
* check that the text sequence is complete
@@ -5912,14 +5846,21 @@ htmlParseTryOrFinish(htmlParserCtxtPtr ctxt, int terminate) {
* data detection.
*/
if ((!terminate) &&
- (htmlParseLookupChars(ctxt, BAD_CAST "<&", 2) < 0))
+ (htmlParseLookupSequence(ctxt, '<', 0, 0, 0) < 0))
goto done;
ctxt->checkIndex = 0;
#ifdef DEBUG_PUSH
xmlGenericError(xmlGenericErrorContext,
"HPP: Parsing char data\n");
#endif
- htmlParseCharData(ctxt);
+ while ((cur != '<') && (cur != 0)) {
+ if (cur == '&') {
+ htmlParseReference(ctxt);
+ } else {
+ htmlParseCharData(ctxt);
+ }
+ cur = in->cur[0];
+ }
}
}
if (cons == ctxt->nbChars) {
--
2.27.0

View File

@ -1,48 +0,0 @@
From 741b0d0a8b9bbee67d68af022cb3137c74e9cd0f Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
Date: Tue, 7 Jul 2020 12:54:34 +0200
Subject: [PATCH] Fix regression introduced with 477c7f6a
The 'inSubset' member is actually used by the SAX2 handlers. Store
extra parser state in 'hasPErefs'.
---
HTMLparser.c | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/HTMLparser.c b/HTMLparser.c
index 468db107..366c19b3 100644
--- a/HTMLparser.c
+++ b/HTMLparser.c
@@ -5160,9 +5160,9 @@ htmlParseLookupSequence(htmlParserCtxtPtr ctxt, xmlChar first,
if (ctxt->checkIndex > base) {
base = ctxt->checkIndex;
- /* Abuse inSubset member to restore current state. */
- incomment = ctxt->inSubset & 1 ? 1 : 0;
- invalue = ctxt->inSubset & 2 ? 1 : 0;
+ /* Abuse hasPErefs member to restore current state. */
+ incomment = ctxt->hasPErefs & 1 ? 1 : 0;
+ invalue = ctxt->hasPErefs & 2 ? 1 : 0;
}
if (in->buf == NULL) {
@@ -5240,12 +5240,12 @@ htmlParseLookupSequence(htmlParserCtxtPtr ctxt, xmlChar first,
}
}
ctxt->checkIndex = base;
- /* Abuse inSubset member to track current state. */
- ctxt->inSubset = 0;
+ /* Abuse hasPErefs member to track current state. */
+ ctxt->hasPErefs = 0;
if (incomment)
- ctxt->inSubset |= 1;
+ ctxt->hasPErefs |= 1;
if (invalue)
- ctxt->inSubset |= 2;
+ ctxt->hasPErefs |= 2;
#ifdef DEBUG_PUSH
if (next == 0)
xmlGenericError(xmlGenericErrorContext,
--
2.27.0

View File

@ -1,306 +0,0 @@
From 79301d3d5e553d46fc3201f48dcec3a93068c5a2 Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
Date: Fri, 18 Dec 2020 12:50:21 +0100
Subject: [PATCH] Fix timeout when handling recursive entities
Abort parsing early to avoid an almost infinite loop in certain error
cases involving recursive entities.
Found with libFuzzer.
---
parser.c | 1 +
result/errors/rec_ext_ent.xml.ent | 178 +++++-------------------------
2 files changed, 30 insertions(+), 149 deletions(-)
diff --git a/parser.c b/parser.c
index 43b88358..a7bdc7f3 100644
--- a/parser.c
+++ b/parser.c
@@ -7158,6 +7158,7 @@ xmlParseReference(xmlParserCtxtPtr ctxt) {
ent->checked |= 1;
if (ret == XML_ERR_ENTITY_LOOP) {
xmlFatalErr(ctxt, XML_ERR_ENTITY_LOOP, NULL);
+ xmlHaltParser(ctxt);
xmlFreeNodeList(list);
return;
}
diff --git a/result/errors/rec_ext_ent.xml.ent b/result/errors/rec_ext_ent.xml.ent
index 30dd2854..d8ccec14 100644
--- a/result/errors/rec_ext_ent.xml.ent
+++ b/result/errors/rec_ext_ent.xml.ent
@@ -1,243 +1,123 @@
test/errors/rec_ext.ent:1: parser error : Detected an entity reference loop
<ent>&e; &e; &e; &e;</ent>
^
-test/errors/rec_ext.ent:2: parser error : chunk is not well balanced
-
-^
-test/errors/rec_ext.ent:1: parser error : Entity 'e' failed to parse
+test/errors/rec_ext.ent:1: parser error : Detected an entity reference loop
<ent>&e; &e; &e; &e;</ent>
^
-test/errors/rec_ext.ent:2: parser error : chunk is not well balanced
-
-^
-test/errors/rec_ext.ent:1: parser error : Entity 'e' failed to parse
+test/errors/rec_ext.ent:1: parser error : Detected an entity reference loop
<ent>&e; &e; &e; &e;</ent>
^
-test/errors/rec_ext.ent:2: parser error : chunk is not well balanced
-
-^
-test/errors/rec_ext.ent:1: parser error : Entity 'e' failed to parse
+test/errors/rec_ext.ent:1: parser error : Detected an entity reference loop
<ent>&e; &e; &e; &e;</ent>
^
-test/errors/rec_ext.ent:2: parser error : chunk is not well balanced
-
-^
-test/errors/rec_ext.ent:1: parser error : Entity 'e' failed to parse
+test/errors/rec_ext.ent:1: parser error : Detected an entity reference loop
<ent>&e; &e; &e; &e;</ent>
^
-test/errors/rec_ext.ent:2: parser error : chunk is not well balanced
-
-^
-test/errors/rec_ext.ent:1: parser error : Entity 'e' failed to parse
+test/errors/rec_ext.ent:1: parser error : Detected an entity reference loop
<ent>&e; &e; &e; &e;</ent>
^
-test/errors/rec_ext.ent:2: parser error : chunk is not well balanced
-
-^
-test/errors/rec_ext.ent:1: parser error : Entity 'e' failed to parse
+test/errors/rec_ext.ent:1: parser error : Detected an entity reference loop
<ent>&e; &e; &e; &e;</ent>
^
-test/errors/rec_ext.ent:2: parser error : chunk is not well balanced
-
-^
-test/errors/rec_ext.ent:1: parser error : Entity 'e' failed to parse
+test/errors/rec_ext.ent:1: parser error : Detected an entity reference loop
<ent>&e; &e; &e; &e;</ent>
^
-test/errors/rec_ext.ent:2: parser error : chunk is not well balanced
-
-^
-test/errors/rec_ext.ent:1: parser error : Entity 'e' failed to parse
+test/errors/rec_ext.ent:1: parser error : Detected an entity reference loop
<ent>&e; &e; &e; &e;</ent>
^
-test/errors/rec_ext.ent:2: parser error : chunk is not well balanced
-
-^
-test/errors/rec_ext.ent:1: parser error : Entity 'e' failed to parse
+test/errors/rec_ext.ent:1: parser error : Detected an entity reference loop
<ent>&e; &e; &e; &e;</ent>
^
-test/errors/rec_ext.ent:2: parser error : chunk is not well balanced
-
-^
-test/errors/rec_ext.ent:1: parser error : Entity 'e' failed to parse
+test/errors/rec_ext.ent:1: parser error : Detected an entity reference loop
<ent>&e; &e; &e; &e;</ent>
^
-test/errors/rec_ext.ent:2: parser error : chunk is not well balanced
-
-^
-test/errors/rec_ext.ent:1: parser error : Entity 'e' failed to parse
+test/errors/rec_ext.ent:1: parser error : Detected an entity reference loop
<ent>&e; &e; &e; &e;</ent>
^
-test/errors/rec_ext.ent:2: parser error : chunk is not well balanced
-
-^
-test/errors/rec_ext.ent:1: parser error : Entity 'e' failed to parse
+test/errors/rec_ext.ent:1: parser error : Detected an entity reference loop
<ent>&e; &e; &e; &e;</ent>
^
-test/errors/rec_ext.ent:2: parser error : chunk is not well balanced
-
-^
-test/errors/rec_ext.ent:1: parser error : Entity 'e' failed to parse
+test/errors/rec_ext.ent:1: parser error : Detected an entity reference loop
<ent>&e; &e; &e; &e;</ent>
^
-test/errors/rec_ext.ent:2: parser error : chunk is not well balanced
-
-^
-test/errors/rec_ext.ent:1: parser error : Entity 'e' failed to parse
+test/errors/rec_ext.ent:1: parser error : Detected an entity reference loop
<ent>&e; &e; &e; &e;</ent>
^
-test/errors/rec_ext.ent:2: parser error : chunk is not well balanced
-
-^
-test/errors/rec_ext.ent:1: parser error : Entity 'e' failed to parse
+test/errors/rec_ext.ent:1: parser error : Detected an entity reference loop
<ent>&e; &e; &e; &e;</ent>
^
-test/errors/rec_ext.ent:2: parser error : chunk is not well balanced
-
-^
-test/errors/rec_ext.ent:1: parser error : Entity 'e' failed to parse
+test/errors/rec_ext.ent:1: parser error : Detected an entity reference loop
<ent>&e; &e; &e; &e;</ent>
^
-test/errors/rec_ext.ent:2: parser error : chunk is not well balanced
-
-^
-test/errors/rec_ext.ent:1: parser error : Entity 'e' failed to parse
+test/errors/rec_ext.ent:1: parser error : Detected an entity reference loop
<ent>&e; &e; &e; &e;</ent>
^
-test/errors/rec_ext.ent:2: parser error : chunk is not well balanced
-
-^
-test/errors/rec_ext.ent:1: parser error : Entity 'e' failed to parse
+test/errors/rec_ext.ent:1: parser error : Detected an entity reference loop
<ent>&e; &e; &e; &e;</ent>
^
-test/errors/rec_ext.ent:2: parser error : chunk is not well balanced
-
-^
-test/errors/rec_ext.ent:1: parser error : Entity 'e' failed to parse
+test/errors/rec_ext.ent:1: parser error : Detected an entity reference loop
<ent>&e; &e; &e; &e;</ent>
^
-test/errors/rec_ext.ent:2: parser error : chunk is not well balanced
-
-^
-test/errors/rec_ext.ent:1: parser error : Entity 'e' failed to parse
+test/errors/rec_ext.ent:1: parser error : Detected an entity reference loop
<ent>&e; &e; &e; &e;</ent>
^
-test/errors/rec_ext.ent:2: parser error : chunk is not well balanced
-
-^
-test/errors/rec_ext.ent:1: parser error : Entity 'e' failed to parse
+test/errors/rec_ext.ent:1: parser error : Detected an entity reference loop
<ent>&e; &e; &e; &e;</ent>
^
-test/errors/rec_ext.ent:2: parser error : chunk is not well balanced
-
-^
-test/errors/rec_ext.ent:1: parser error : Entity 'e' failed to parse
+test/errors/rec_ext.ent:1: parser error : Detected an entity reference loop
<ent>&e; &e; &e; &e;</ent>
^
-test/errors/rec_ext.ent:2: parser error : chunk is not well balanced
-
-^
-test/errors/rec_ext.ent:1: parser error : Entity 'e' failed to parse
+test/errors/rec_ext.ent:1: parser error : Detected an entity reference loop
<ent>&e; &e; &e; &e;</ent>
^
-test/errors/rec_ext.ent:2: parser error : chunk is not well balanced
-
-^
-test/errors/rec_ext.ent:1: parser error : Entity 'e' failed to parse
+test/errors/rec_ext.ent:1: parser error : Detected an entity reference loop
<ent>&e; &e; &e; &e;</ent>
^
-test/errors/rec_ext.ent:2: parser error : chunk is not well balanced
-
-^
-test/errors/rec_ext.ent:1: parser error : Entity 'e' failed to parse
+test/errors/rec_ext.ent:1: parser error : Detected an entity reference loop
<ent>&e; &e; &e; &e;</ent>
^
-test/errors/rec_ext.ent:2: parser error : chunk is not well balanced
-
-^
-test/errors/rec_ext.ent:1: parser error : Entity 'e' failed to parse
+test/errors/rec_ext.ent:1: parser error : Detected an entity reference loop
<ent>&e; &e; &e; &e;</ent>
^
-test/errors/rec_ext.ent:2: parser error : chunk is not well balanced
-
-^
-test/errors/rec_ext.ent:1: parser error : Entity 'e' failed to parse
+test/errors/rec_ext.ent:1: parser error : Detected an entity reference loop
<ent>&e; &e; &e; &e;</ent>
^
-test/errors/rec_ext.ent:2: parser error : chunk is not well balanced
-
-^
-test/errors/rec_ext.ent:1: parser error : Entity 'e' failed to parse
+test/errors/rec_ext.ent:1: parser error : Detected an entity reference loop
<ent>&e; &e; &e; &e;</ent>
^
-test/errors/rec_ext.ent:2: parser error : chunk is not well balanced
-
-^
test/errors/rec_ext.ent:1: parser error : Detected an entity reference loop
<ent>&e; &e; &e; &e;</ent>
^
-test/errors/rec_ext.ent:2: parser error : chunk is not well balanced
-
-^
test/errors/rec_ext.ent:1: parser error : Detected an entity reference loop
<ent>&e; &e; &e; &e;</ent>
^
-test/errors/rec_ext.ent:2: parser error : chunk is not well balanced
-
-^
test/errors/rec_ext.ent:1: parser error : Detected an entity reference loop
<ent>&e; &e; &e; &e;</ent>
^
-test/errors/rec_ext.ent:2: parser error : chunk is not well balanced
-
-^
test/errors/rec_ext.ent:1: parser error : Detected an entity reference loop
<ent>&e; &e; &e; &e;</ent>
^
-test/errors/rec_ext.ent:2: parser error : chunk is not well balanced
-
-^
test/errors/rec_ext.ent:1: parser error : Detected an entity reference loop
<ent>&e; &e; &e; &e;</ent>
^
-test/errors/rec_ext.ent:2: parser error : chunk is not well balanced
-
-^
test/errors/rec_ext.ent:1: parser error : Detected an entity reference loop
<ent>&e; &e; &e; &e;</ent>
^
-test/errors/rec_ext.ent:2: parser error : chunk is not well balanced
-
-^
test/errors/rec_ext.ent:1: parser error : Detected an entity reference loop
<ent>&e; &e; &e; &e;</ent>
^
-test/errors/rec_ext.ent:2: parser error : chunk is not well balanced
-
-^
test/errors/rec_ext.ent:1: parser error : Detected an entity reference loop
<ent>&e; &e; &e; &e;</ent>
^
-test/errors/rec_ext.ent:2: parser error : chunk is not well balanced
-
-^
test/errors/rec_ext.ent:1: parser error : Detected an entity reference loop
<ent>&e; &e; &e; &e;</ent>
^
-test/errors/rec_ext.ent:2: parser error : chunk is not well balanced
-
-^
test/errors/rec_ext.ent:1: parser error : Detected an entity reference loop
<ent>&e; &e; &e; &e;</ent>
^
-test/errors/rec_ext.ent:2: parser error : chunk is not well balanced
-
-^
test/errors/rec_ext.ent:1: parser error : Detected an entity reference loop
<ent>&e; &e; &e; &e;</ent>
^
-test/errors/rec_ext.ent:2: parser error : chunk is not well balanced
-
-^
-./test/errors/rec_ext_ent.xml:4: parser error : Entity 'e' failed to parse
+./test/errors/rec_ext_ent.xml:4: parser error : Detected an entity reference loop
<doc>&e; &e; &e; &e;</doc>
^
--
2.27.0

View File

@ -1,36 +0,0 @@
From 13ba5b619a153f240320eb92b59158d657bdeb3a Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
Date: Sun, 28 Jun 2020 13:16:46 +0200
Subject: [PATCH] Reset HTML parser input before reporting encoding error
If charset conversion fails, reset the input pointers before reporting
the error and bailing out. Otherwise, the input pointers are left in an
invalid state which could lead to use-after-free and other memory
errors.
Similar to f9e7997e. Found by OSS-Fuzz.
---
HTMLparser.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/HTMLparser.c b/HTMLparser.c
index 9ade6635..7fba9429 100644
--- a/HTMLparser.c
+++ b/HTMLparser.c
@@ -6160,12 +6160,12 @@ htmlParseChunk(htmlParserCtxtPtr ctxt, const char *chunk, int size,
size_t current = ctxt->input->cur - ctxt->input->base;
nbchars = xmlCharEncInput(in, terminate);
+ xmlBufSetInputBaseCur(in->buffer, ctxt->input, base, current);
if (nbchars < 0) {
htmlParseErr(ctxt, XML_ERR_INVALID_ENCODING,
"encoder error\n", NULL, NULL);
return(XML_ERR_INVALID_ENCODING);
}
- xmlBufSetInputBaseCur(in->buffer, ctxt->input, base, current);
}
}
}
--
2.27.0

View File

@ -1,50 +0,0 @@
From ef4906c251b39a292c1e411e7b72d270768949c0 Mon Sep 17 00:00:00 2001
From: Pieter van Oostrum <pieter@vanoostrum.org>
Date: Tue, 31 Dec 2019 21:49:58 +0100
Subject: [PATCH 1/1] Updated python/tests/tstLastError.py
libxml2.registerErrorHandler(None,None):
None is not acceptable as first argument
failUnlessEqual replaced by assertEqual
---
python/tests/tstLastError.py | 17 ++++++++++-------
1 file changed, 10 insertions(+), 7 deletions(-)
diff --git a/python/tests/tstLastError.py b/python/tests/tstLastError.py
index 81d0acc4..1758a9fb 100755
--- a/python/tests/tstLastError.py
+++ b/python/tests/tstLastError.py
@@ -25,7 +25,10 @@ class TestCase(unittest.TestCase):
when the exception is raised, check the libxml2.lastError for
expected values."""
# disable the default error handler
- libxml2.registerErrorHandler(None,None)
+ def noerr(ctx, str):
+ pass
+ # None is not acceptable as function.
+ libxml2.registerErrorHandler(noerr,None)
try:
f(*args)
except exc:
@@ -40,12 +43,12 @@ class TestCase(unittest.TestCase):
print("file =",e.file())
print("line =",e.line())
print()
- self.failUnlessEqual(domain,e.domain())
- self.failUnlessEqual(code,e.code())
- self.failUnlessEqual(message,e.message())
- self.failUnlessEqual(level,e.level())
- self.failUnlessEqual(file,e.file())
- self.failUnlessEqual(line,e.line())
+ self.assertEqual(domain,e.domain())
+ self.assertEqual(code,e.code())
+ self.assertEqual(message,e.message())
+ self.assertEqual(level,e.level())
+ self.assertEqual(file,e.file())
+ self.assertEqual(line,e.line())
else:
self.fail("exception %s should have been raised" % exc)
--
2.19.1

View File

@ -1,32 +0,0 @@
From 73060457de03c0dada603bdc6c6e1fc9b08fc94b Mon Sep 17 00:00:00 2001
From: Zhipeng Xie <xiezhipeng1@huawei.com>
Date: Thu, 12 Dec 2019 17:30:55 +0800
Subject: [PATCH] Fix infinite loop in xmlStringLenDecodeEntities
When ctxt->instate == XML_PARSER_EOF,xmlParseStringEntityRef
return NULL which cause a infinite loop in xmlStringLenDecodeEntities
Found with libFuzzer.
Signed-off-by: Zhipeng Xie <xiezhipeng1@huawei.com>
---
parser.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/parser.c b/parser.c
index 4696f916..3e09b3e9 100644
--- a/parser.c
+++ b/parser.c
@@ -2786,7 +2786,8 @@ xmlStringLenDecodeEntities(xmlParserCtxtPtr ctxt, const xmlChar *str, int len,
else
c = 0;
while ((c != 0) && (c != end) && /* non input consuming loop */
- (c != end2) && (c != end3)) {
+ (c != end2) && (c != end3) &&
+ (ctxt->instate != XML_PARSER_EOF)) {
if (c == 0) break;
if ((c == '&') && (str[1] == '#')) {
--
2.19.1

Binary file not shown.

BIN
libxml2-2.9.12.tar.gz Normal file

Binary file not shown.

View File

@ -1,24 +1,18 @@
*** XML/xml2-config.in.orig 2006-06-06 16:35:56.000000000 +0200
--- XML/xml2-config.in 2006-06-06 16:36:24.000000000 +0200
***************
*** 3,9 ****
prefix=@prefix@
exec_prefix=@exec_prefix@
includedir=@includedir@
! libdir=@libdir@
usage()
{
--- 3,14 ----
prefix=@prefix@
exec_prefix=@exec_prefix@
includedir=@includedir@
! if [ "`ldd /bin/sh | grep lib64`" = "" ]
! then
! libdir=${exec_prefix}/lib
! else
! libdir=${exec_prefix}/lib64
! fi
usage()
{
diff --git a/xml2-config.in b/xml2-config.in
index 5863ffa..47f205e 100644
--- a/xml2-config.in
+++ b/xml2-config.in
@@ -3,7 +3,12 @@
prefix=@prefix@
exec_prefix=@exec_prefix@
includedir=@includedir@
-libdir=@libdir@
+if [ "`ldd /bin/sh | grep lib64`" = "" ]
+then
+ libdir=${exec_prefix}/lib
+else
+ libdir=${exec_prefix}/lib64
+fi
cflags=
libs=

View File

@ -1,107 +1,15 @@
Summary: Library providing XML and HTML support
Name: libxml2
Version: 2.9.10
Release: 19
Version: 2.9.12
Release: 1
License: MIT
Group: Development/Libraries
Source: ftp://xmlsoft.org/libxml2/libxml2-%{version}.tar.gz
Patch0: libxml2-multilib.patch
# upstream patches
Patch1: backport-Fix-memory-leak-in-xmlSchemaValidateStream.patch
Patch2: backport-fix-infinite-loop-in-xmlStringLenDecodeEntities.patch
Patch3: backport-Updated-python-tests-tstLastError.py.patch
Patch4: Null-pointer-handling-in-catalog-c.patch
Patch5: Fix-overflow-handling-in-xmlBufBackToBuffer.patch
Patch6: Fix-memory-leak-in-error-path-of-XPath-expr-parser.patch
Patch7: Fix-memory-leaks-of-encoding-handlers-in-xmlsave-c.patch
Patch8: Use-random-seed-in-xmlDictComputeFastKey.patch
Patch9: Fix-more-memory-leaks-in-error-paths-of-XPath-parser.patch
Patch10: Fix-freeing-of-nested-documents.patch
Patch11: Fix-overflow-check-in-xmlNodeDump.patch
Patch12: Check-for-overflow-when-allocating-two-dimensional-arrays.patch
Patch13: Fix-integer-overflow-in-xmlBufferResize.patch
Patch14: Fix-copying-of-entities-in-xmlParseReference.patch
Patch15: Copy-some-XMLReader-option-flags-to-parser-context.patch
Patch16: Merge-code-paths-loading-external-entities.patch
Patch17: Don-t-load-external-entity-from-xmlSAX2GetEntity.patch
Patch18: Fix-use-after-free-with-validating-reader.patch
Patch19: Never-expand-parameter-entities-in-text-declaration.patch
Patch20: Fix-integer-overflow-in-xmlFAParseQuantExact.patch
Patch21: Report-error-for-invalid-regexp-quantifiers.patch
Patch22: Add-regexp-regression-tests.patch
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: Fix-integer-overflow-when-comparing-schema-dates.patch
Patch37: Fix-memory-leak-in-xmlXIncludeIncludeNode-error-path.patch
Patch38: Don-t-recurse-into-xi-include-children-in-xmlXInclud.patch
Patch39: Don-t-process-siblings-of-root-in-xmlXIncludeProcess.patch
Patch40: Fix-exponential-runtime-and-memory-in-xi-fallback-pr.patch
Patch41: Fuzz-XInclude-engine.patch
Patch42: Fix-memory-leak-in-runtest.c.patch
Patch43: Fix-XInclude-regression-introduced-with-recent-commi.patch
Patch44: Fix-memory-leak-in-xmlXIncludeAddNode-error-paths.patch
Patch45: Fix-double-free-in-XML-reader-with-XIncludes.patch
Patch46: Limit-size-of-free-lists-in-XML-reader-when-fuzzing.patch
Patch47: Fix-cleanup-of-attributes-in-XML-reader.patch
Patch48: Fix-null-deref-in-XPointer-expression-error-path.patch
Patch49: Fix-use-after-free-when-XIncluding-text-from-Reader.patch
Patch50: backport-Add-test-case-for-recursive-external-parsed-entities.patch
Patch51: backport-Fix-timeout-when-handling-recursive-entities.patch
Patch52: backport-Avoid-call-stack-overflow-with-XML-reader-and-recurs.patch
Patch53: backport-Reset-HTML-parser-input-before-reporting-encoding-er.patch
Patch54: backport-Fix-quadratic-runtime-in-HTML-parser.patch
Patch55: backport-Fix-regression-introduced-with-477c7f6a.patch
Patch56: backport-Fix-HTML-push-parser-lookahead.patch
Patch57: backport-Fix-quadratic-runtime-when-push-parsing-HTML-entity-.patch
Patch58: backport-Fix-quadratic-runtime-in-HTML-push-parser-with-null-.patch
Patch59: backport-Fix-infinite-loop-in-HTML-parser-introduced-with-rec.patch
Patch60: backport-Fix-integer-overflow-in-xmlSchemaGetParticleTotalRan.patch
Patch61: backport-CVE-2021-3537.patch
Patch62: CVE-2021-3517.patch
Patch63: CVE-2021-3518.patch
Patch64: Fix-handling-of-unexpected-EOF-in-xmlParseContent.patch
Patch65: Fix-line-numbers-in-error-messages-for-mismatched-ta.patch
Patch66: Fix-null-deref-in-legacy-SAX1-parser.patch
Patch67: update-for-xsd-language-type-check.patch
Patch68: Fix-dangling-pointer-with-xmllint-dropdtd.patch
Patch69: Fix-duplicate-xmlStrEqual-calls-in-htmlParseEndTag.patch
Patch70: Fix-exponential-behavior-with-recursive-entities.patch
Patch71: Fix-quadratic-behavior-when-looking-up-xml-attribute.patch
Patch72: Fix-use-after-free-with-xmllint-html-push.patch
Patch73: Fix-xmlGetNodePath-with-invalid-node-types.patch
Patch74: Stop-checking-attributes-for-UTF-8-validity.patch
Patch75: CVE-2021-3541.patch
Patch76: Fix-corner-case-with-empty-xi-fallback.patch
Patch77: Fix-quadratic-runtime-in-xi-fallback-processing.patch
Patch78: Fix-error-reporting-with-xi-fallback.patch
Patch79: Revert-Fix-quadratic-runtime-in-xi-fallback-processi.patch
Patch80: Remove-dead-code-in-xinclude.c.patch
Patch81: Fix-regression-introduced-with-commit-74dcc10b.patch
Patch82: Fix-regression-introduced-with-commit-d88df4b.patch
Patch83: Make-xmlNodeDumpOutputInternal-non-recursive.patch
Patch84: Don-t-add-formatting-newlines-to-XInclude-nodes.patch
Patch85: Make-htmlNodeDumpFormatOutput-non-recursive.patch
Patch86: Fix-memory-leaks-in-XPointer-string-range-function.patch
Patch87: Fix-null-pointer-deref-in-xmlXPtrRangeInsideFunction.patch
Patch88: Stop-using-maxParserDepth-in-xpath.c.patch
Patch89: Hardcode-maximum-XPath-recursion-depth.patch
Patch90: Fix-XPath-recursion-limit.patch
Patch91: Fix-Null-deref-in-xmlSchemaGetComponentTargetNs.patch
Patch92: Fix-memleaks-in-xmlXIncludeProcessFlags.patch
Patch0: libxml2-multilib.patch
Patch1: Fix-XPath-recursion-limit.patch
Patch2: Fix-Null-deref-in-xmlSchemaGetComponentTargetNs.patch
Patch3: Fix-memleaks-in-xmlXIncludeProcessFlags.patch
BuildRoot: %{_tmppath}/%{name}-%{version}-root
BuildRequires: python3-devel
@ -262,6 +170,12 @@ rm -fr %{buildroot}
%changelog
* Wed Nov 10 2021 Zhipeng Xie <xiezhipeng1@huawei.com> - 2.9.12-1
- Type:enhancement
- ID:NA
- SUG:NA
- DESC:upgrade to upstream v2.9.12
* Tue Nov 9 2021 panxiaohe <panxiaohe@huawei.com> - 2.9.10-19
- Type:bugfix
- ID:NA

View File

@ -1,72 +0,0 @@
From 33468d7e7080e384ad703a2369003cf18b2ad91d Mon Sep 17 00:00:00 2001
From: PaulHiggs <paul_higgs@hotmail.com>
Date: Mon, 3 May 2021 16:09:44 +0100
Subject: [PATCH] update for xsd:language type check
Fixes #242.
---
xmlschemastypes.c | 41 ++++++++++++++++++++++++++++++++++++++++-
1 file changed, 40 insertions(+), 1 deletion(-)
diff --git a/xmlschemastypes.c b/xmlschemastypes.c
index 07b5fd7..9c2dff0 100644
--- a/xmlschemastypes.c
+++ b/xmlschemastypes.c
@@ -2187,6 +2187,44 @@ xmlSchemaParseUInt(const xmlChar **str, unsigned long *llo,
return(ret);
}
+/*
+ * xmlSchemaCheckLanguageType
+ * @value: the value to check
+ *
+ * Check that a value conforms to the lexical space of the language datatype.
+ * Must conform to [a-zA-Z]{1,8}(-[a-zA-Z0-9]{1,8})*
+ *
+ * Returns 1 if this validates, 0 otherwise.
+ */
+static int
+xmlSchemaCheckLanguageType(const xmlChar* value) {
+ int first = 1, len = 0;
+ const xmlChar* cur = value;
+
+ if (value == NULL)
+ return (0);
+
+ while (cur[0] != 0) {
+ if (!( ((cur[0] >= 'a') && (cur[0] <= 'z')) || ((cur[0] >= 'A') && (cur[0] <= 'Z'))
+ || (cur[0] == '-')
+ || ((first == 0) && (xmlIsDigit_ch(cur[0]))) ))
+ return (0);
+ if (cur[0] == '-') {
+ if ((len < 1) || (len > 8))
+ return (0);
+ len = 0;
+ first = 0;
+ }
+ else
+ len++;
+ cur++;
+ }
+ if ((len < 1) || (len > 8))
+ return (0);
+
+ return (1);
+}
+
/**
* xmlSchemaValAtomicType:
* @type: the predefined type
@@ -2704,7 +2742,8 @@ xmlSchemaValAtomicType(xmlSchemaTypePtr type, const xmlChar * value,
if (norm != NULL)
value = norm;
}
- if (xmlCheckLanguageID(value) == 1) {
+
+ if (xmlSchemaCheckLanguageType(value) == 1) {
if (val != NULL) {
v = xmlSchemaNewValue(XML_SCHEMAS_LANGUAGE);
if (v != NULL) {
--
1.8.3.1