summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Veillard <veillard@redhat.com>2021-05-13 14:55:12 +0200
committerDaniel Veillard <veillard@redhat.com>2021-05-13 14:55:12 +0200
commit8598060bacada41a0eb09d95c97744ff4e428f8e (patch)
tree9ef67577afaf25f2dae30e2fae749537b6b4b9cd
parentbfd2f4300fb348a0fb8265a17546a0eb8bdec719 (diff)
downloadlibxml2-8598060bacada41a0eb09d95c97744ff4e428f8e.tar.gz
Patch for security issue CVE-2021-3541CVE-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.
-rw-r--r--parser.c26
1 files changed, 26 insertions, 0 deletions
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) &&