Commit 23f05e0c authored by Daniel Veillard's avatar Daniel Veillard

Detect excessive entities expansion upon replacement

If entities expansion in the XML parser is asked for,
it is possble to craft relatively small input document leading
to excessive on-the-fly content generation.
This patch accounts for those replacement and stop parsing
after a given threshold. it can be bypassed as usual with the
HUGE parser option.
parent bf058dce
......@@ -310,6 +310,7 @@ struct _xmlParserCtxt {
xmlParserNodeInfo *nodeInfoTab; /* array of nodeInfos */
int input_id; /* we need to label inputs */
unsigned long sizeentcopy; /* volume of entity copy */
};
/**
......
......@@ -122,7 +122,7 @@ xmlCreateEntityParserCtxtInternal(const xmlChar *URL, const xmlChar *ID,
*/
static int
xmlParserEntityCheck(xmlParserCtxtPtr ctxt, size_t size,
xmlEntityPtr ent)
xmlEntityPtr ent, size_t replacement)
{
size_t consumed = 0;
......@@ -130,7 +130,24 @@ xmlParserEntityCheck(xmlParserCtxtPtr ctxt, size_t size,
return (0);
if (ctxt->lastError.code == XML_ERR_ENTITY_LOOP)
return (1);
if (size != 0) {
if (replacement != 0) {
if (replacement < XML_MAX_TEXT_LENGTH)
return(0);
/*
* If the volume of entity copy reaches 10 times the
* amount of parsed data and over the large text threshold
* then that's very likely to be an abuse.
*/
if (ctxt->input != NULL) {
consumed = ctxt->input->consumed +
(ctxt->input->cur - ctxt->input->base);
}
consumed += ctxt->sizeentities;
if (replacement < XML_PARSER_NON_LINEAR * consumed)
return(0);
} else if (size != 0) {
/*
* Do the check based on the replacement size of the entity
*/
......@@ -176,7 +193,6 @@ xmlParserEntityCheck(xmlParserCtxtPtr ctxt, size_t size,
*/
return (0);
}
xmlFatalErr(ctxt, XML_ERR_ENTITY_LOOP, NULL);
return (1);
}
......@@ -2743,7 +2759,7 @@ xmlStringLenDecodeEntities(xmlParserCtxtPtr ctxt, const xmlChar *str, int len,
while (*current != 0) { /* non input consuming loop */
buffer[nbchars++] = *current++;
if (nbchars + XML_PARSER_BUFFER_SIZE > buffer_size) {
if (xmlParserEntityCheck(ctxt, nbchars, ent))
if (xmlParserEntityCheck(ctxt, nbchars, ent, 0))
goto int_error;
growBuffer(buffer, XML_PARSER_BUFFER_SIZE);
}
......@@ -2785,7 +2801,7 @@ xmlStringLenDecodeEntities(xmlParserCtxtPtr ctxt, const xmlChar *str, int len,
while (*current != 0) { /* non input consuming loop */
buffer[nbchars++] = *current++;
if (nbchars + XML_PARSER_BUFFER_SIZE > buffer_size) {
if (xmlParserEntityCheck(ctxt, nbchars, ent))
if (xmlParserEntityCheck(ctxt, nbchars, ent, 0))
goto int_error;
growBuffer(buffer, XML_PARSER_BUFFER_SIZE);
}
......@@ -7203,7 +7219,7 @@ xmlParseReference(xmlParserCtxtPtr ctxt) {
xmlFreeNodeList(list);
return;
}
if (xmlParserEntityCheck(ctxt, 0, ent)) {
if (xmlParserEntityCheck(ctxt, 0, ent, 0)) {
xmlFreeNodeList(list);
return;
}
......@@ -7360,6 +7376,13 @@ xmlParseReference(xmlParserCtxtPtr ctxt) {
(ctxt->parseMode == XML_PARSE_READER)) {
xmlNodePtr nw = NULL, cur, firstChild = NULL;
/*
* We are copying here, make sure there is no abuse
*/
ctxt->sizeentcopy += ent->length;
if (xmlParserEntityCheck(ctxt, 0, ent, ctxt->sizeentcopy))
return;
/*
* when operating on a reader, the entities definitions
* are always owning the entities subtree.
......@@ -7400,6 +7423,14 @@ xmlParseReference(xmlParserCtxtPtr ctxt) {
} else if ((list == NULL) || (ctxt->inputNr > 0)) {
xmlNodePtr nw = NULL, cur, next, last,
firstChild = NULL;
/*
* We are copying here, make sure there is no abuse
*/
ctxt->sizeentcopy += ent->length;
if (xmlParserEntityCheck(ctxt, 0, ent, ctxt->sizeentcopy))
return;
/*
* Copy the entity child list and make it the new
* entity child list. The goal is to make sure any
......@@ -14767,6 +14798,7 @@ xmlCtxtReset(xmlParserCtxtPtr ctxt)
ctxt->catalogs = NULL;
ctxt->nbentities = 0;
ctxt->sizeentities = 0;
ctxt->sizeentcopy = 0;
xmlInitNodeInfoSeq(&ctxt->node_seq);
if (ctxt->attsDefault != NULL) {
......
......@@ -1719,6 +1719,8 @@ xmlInitParserCtxt(xmlParserCtxtPtr ctxt)
ctxt->charset = XML_CHAR_ENCODING_UTF8;
ctxt->catalogs = NULL;
ctxt->nbentities = 0;
ctxt->sizeentities = 0;
ctxt->sizeentcopy = 0;
ctxt->input_id = 1;
xmlInitNodeInfoSeq(&ctxt->node_seq);
return(0);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment