You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
140 lines
4.6 KiB
140 lines
4.6 KiB
commit 8ed73eb939d6c9b79f3fa41b76916cc443196bbc |
|
Author: Daniel Veillard <veillard@redhat.com> |
|
Date: Thu Oct 2 16:17:09 2014 +0800 |
|
|
|
Fix for CVE-2014-3660 |
|
|
|
Issues related to the billion laugh entity expansion which happened to |
|
escape the initial set of fixes |
|
|
|
diff --git a/parser.c b/parser.c |
|
index f30588c..3c72cbb 100644 |
|
--- a/parser.c |
|
+++ b/parser.c |
|
@@ -130,6 +130,29 @@ xmlParserEntityCheck(xmlParserCtxtPtr ctxt, size_t size, |
|
return (0); |
|
if (ctxt->lastError.code == XML_ERR_ENTITY_LOOP) |
|
return (1); |
|
+ |
|
+ /* |
|
+ * This may look absurd but is needed to detect |
|
+ * entities problems |
|
+ */ |
|
+ if ((ent != NULL) && (ent->etype != XML_INTERNAL_PREDEFINED_ENTITY) && |
|
+ (ent->content != NULL) && (ent->checked == 0)) { |
|
+ unsigned long oldnbent = ctxt->nbentities; |
|
+ xmlChar *rep; |
|
+ |
|
+ ent->checked = 1; |
|
+ |
|
+ rep = xmlStringDecodeEntities(ctxt, ent->content, |
|
+ XML_SUBSTITUTE_REF, 0, 0, 0); |
|
+ |
|
+ ent->checked = (ctxt->nbentities - oldnbent + 1) * 2; |
|
+ if (rep != NULL) { |
|
+ if (xmlStrchr(rep, '<')) |
|
+ ent->checked |= 1; |
|
+ xmlFree(rep); |
|
+ rep = NULL; |
|
+ } |
|
+ } |
|
if (replacement != 0) { |
|
if (replacement < XML_MAX_TEXT_LENGTH) |
|
return(0); |
|
@@ -189,9 +212,12 @@ xmlParserEntityCheck(xmlParserCtxtPtr ctxt, size_t size, |
|
return (0); |
|
} else { |
|
/* |
|
- * strange we got no data for checking just return |
|
+ * strange we got no data for checking |
|
*/ |
|
- return (0); |
|
+ if (((ctxt->lastError.code != XML_ERR_UNDECLARED_ENTITY) && |
|
+ (ctxt->lastError.code != XML_WAR_UNDECLARED_ENTITY)) || |
|
+ (ctxt->nbentities <= 10000)) |
|
+ return (0); |
|
} |
|
xmlFatalErr(ctxt, XML_ERR_ENTITY_LOOP, NULL); |
|
return (1); |
|
@@ -2584,6 +2610,7 @@ xmlParserHandlePEReference(xmlParserCtxtPtr ctxt) { |
|
name, NULL); |
|
ctxt->valid = 0; |
|
} |
|
+ xmlParserEntityCheck(ctxt, 0, NULL, 0); |
|
} else if (ctxt->input->free != deallocblankswrapper) { |
|
input = xmlNewBlanksWrapperInputStream(ctxt, entity); |
|
if (xmlPushInput(ctxt, input) < 0) |
|
@@ -2737,6 +2764,7 @@ xmlStringLenDecodeEntities(xmlParserCtxtPtr ctxt, const xmlChar *str, int len, |
|
if ((ctxt->lastError.code == XML_ERR_ENTITY_LOOP) || |
|
(ctxt->lastError.code == XML_ERR_INTERNAL_ERROR)) |
|
goto int_error; |
|
+ xmlParserEntityCheck(ctxt, 0, ent, 0); |
|
if (ent != NULL) |
|
ctxt->nbentities += ent->checked / 2; |
|
if ((ent != NULL) && |
|
@@ -2788,6 +2816,7 @@ xmlStringLenDecodeEntities(xmlParserCtxtPtr ctxt, const xmlChar *str, int len, |
|
ent = xmlParseStringPEReference(ctxt, &str); |
|
if (ctxt->lastError.code == XML_ERR_ENTITY_LOOP) |
|
goto int_error; |
|
+ xmlParserEntityCheck(ctxt, 0, ent, 0); |
|
if (ent != NULL) |
|
ctxt->nbentities += ent->checked / 2; |
|
if (ent != NULL) { |
|
@@ -7286,6 +7315,7 @@ xmlParseReference(xmlParserCtxtPtr ctxt) { |
|
(ret != XML_WAR_UNDECLARED_ENTITY)) { |
|
xmlFatalErrMsgStr(ctxt, XML_ERR_UNDECLARED_ENTITY, |
|
"Entity '%s' failed to parse\n", ent->name); |
|
+ xmlParserEntityCheck(ctxt, 0, ent, 0); |
|
} else if (list != NULL) { |
|
xmlFreeNodeList(list); |
|
list = NULL; |
|
@@ -7392,7 +7422,7 @@ xmlParseReference(xmlParserCtxtPtr ctxt) { |
|
/* |
|
* We are copying here, make sure there is no abuse |
|
*/ |
|
- ctxt->sizeentcopy += ent->length; |
|
+ ctxt->sizeentcopy += ent->length + 5; |
|
if (xmlParserEntityCheck(ctxt, 0, ent, ctxt->sizeentcopy)) |
|
return; |
|
|
|
@@ -7440,7 +7470,7 @@ xmlParseReference(xmlParserCtxtPtr ctxt) { |
|
/* |
|
* We are copying here, make sure there is no abuse |
|
*/ |
|
- ctxt->sizeentcopy += ent->length; |
|
+ ctxt->sizeentcopy += ent->length + 5; |
|
if (xmlParserEntityCheck(ctxt, 0, ent, ctxt->sizeentcopy)) |
|
return; |
|
|
|
@@ -7626,6 +7656,7 @@ xmlParseEntityRef(xmlParserCtxtPtr ctxt) { |
|
ctxt->sax->reference(ctxt->userData, name); |
|
} |
|
} |
|
+ xmlParserEntityCheck(ctxt, 0, ent, 0); |
|
ctxt->valid = 0; |
|
} |
|
|
|
@@ -7819,6 +7850,7 @@ xmlParseStringEntityRef(xmlParserCtxtPtr ctxt, const xmlChar ** str) { |
|
"Entity '%s' not defined\n", |
|
name); |
|
} |
|
+ xmlParserEntityCheck(ctxt, 0, ent, 0); |
|
/* TODO ? check regressions ctxt->valid = 0; */ |
|
} |
|
|
|
@@ -7978,6 +8010,7 @@ xmlParsePEReference(xmlParserCtxtPtr ctxt) |
|
name, NULL); |
|
ctxt->valid = 0; |
|
} |
|
+ xmlParserEntityCheck(ctxt, 0, NULL, 0); |
|
} else { |
|
/* |
|
* Internal checking in case the entity quest barfed |
|
@@ -8217,6 +8250,7 @@ xmlParseStringPEReference(xmlParserCtxtPtr ctxt, const xmlChar **str) { |
|
name, NULL); |
|
ctxt->valid = 0; |
|
} |
|
+ xmlParserEntityCheck(ctxt, 0, NULL, 0); |
|
} else { |
|
/* |
|
* Internal checking in case the entity quest barfed
|
|
|