--- include/libxml/entities.h.orig 2005-01-04 15:49:49.000000000 +0100 +++ include/libxml/entities.h 2008-08-11 17:56:53.000000000 +0200 @@ -56,6 +56,7 @@ struct _xmlEntity { struct _xmlEntity *nexte; /* unused */ const xmlChar *URI; /* the full URI as computed */ int owner; /* does the entity own the childrens */ + unsigned long nbentities; /* the number of entities references */ }; /* --- include/libxml/parser.h.orig 2003-04-24 14:04:00.000000000 +0200 +++ include/libxml/parser.h 2008-08-11 19:03:50.000000000 +0200 @@ -234,6 +234,7 @@ struct _xmlParserCtxt { void *catalogs; /* document's own catalog */ int recovery; /* run in recovery mode */ int progressive; /* is this a progressive parsing */ + unsigned long nbentities; /* number of entities references */ }; /** --- parser.c.orig 2003-08-15 01:42:29.000000000 +0200 +++ parser.c 2008-08-11 19:28:59.000000000 +0200 @@ -1061,7 +1061,7 @@ xmlStringDecodeEntities(xmlParserCtxtPtr if (str == NULL) return(NULL); - if (ctxt->depth > 40) { + if ((ctxt->depth > 40) || (ctxt->nbentities >= 500000)) { ctxt->errNo = XML_ERR_ENTITY_LOOP; if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL)) ctxt->sax->error(ctxt->userData, @@ -1102,6 +1102,11 @@ xmlStringDecodeEntities(xmlParserCtxtPtr "String decoding Entity Reference: %.30s\n", str); ent = xmlParseStringEntityRef(ctxt, &str); + if (ctxt->errNo == XML_ERR_ENTITY_LOOP) + goto int_error; + ctxt->nbentities++; + if (ent != NULL) + ctxt->nbentities += ent->nbentities; if ((ent != NULL) && (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) { if (ent->content != NULL) { @@ -1146,6 +1151,11 @@ xmlStringDecodeEntities(xmlParserCtxtPtr xmlGenericError(xmlGenericErrorContext, "String decoding PE Reference: %.30s\n", str); ent = xmlParseStringPEReference(ctxt, &str); + if (ctxt->errNo == XML_ERR_ENTITY_LOOP) + goto int_error; + ctxt->nbentities++; + if (ent != NULL) + ctxt->nbentities += ent->nbentities; if (ent != NULL) { xmlChar *rep; @@ -1176,6 +1186,10 @@ xmlStringDecodeEntities(xmlParserCtxtPtr } buffer[nbchars++] = 0; return(buffer); +int_error: + if (buffer != NULL) + xmlFree(buffer); + return(NULL); } @@ -2527,6 +2541,9 @@ xmlParseAttValueComplex(xmlParserCtxtPtr } } else { ent = xmlParseEntityRef(ctxt); + ctxt->nbentities++; + if (ent != NULL) + ctxt->nbentities += ent->nbentities; if ((ent != NULL) && (ctxt->replaceEntities != 0)) { xmlChar *rep; @@ -3595,6 +3612,7 @@ xmlParseEntityDecl(xmlParserCtxtPtr ctxt int isParameter = 0; xmlChar *orig = NULL; int skipped; + unsigned long oldnbent = ctxt->nbentities; GROW; if ((RAW == '<') && (NXT(1) == '!') && @@ -3870,6 +3888,7 @@ xmlParseEntityDecl(xmlParserCtxtPtr ctxt } } if (cur != NULL) { + cur->nbentities = ctxt->nbentities - oldnbent; if (cur->orig != NULL) xmlFree(orig); else @@ -5480,6 +5499,16 @@ xmlParseReference(xmlParserCtxtPtr ctxt) if (ent == NULL) return; if (!ctxt->wellFormed) return; + ctxt->nbentities++; + if (ctxt->nbentities >= 500000) { + ctxt->errNo = XML_ERR_ENTITY_LOOP; + if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL)) + ctxt->sax->error(ctxt->userData, + "Detected entity reference loop\n"); + ctxt->wellFormed = 0; + if (ctxt->recovery == 0) ctxt->disableSAX = 1; + return; + } if ((ent->name != NULL) && (ent->etype != XML_INTERNAL_PREDEFINED_ENTITY)) { xmlNodePtr list = NULL; @@ -5538,6 +5567,7 @@ xmlParseReference(xmlParserCtxtPtr ctxt) xmlFreeNodeList(list); } } else { + unsigned long oldnbent = ctxt->nbentities; /* * 4.3.2: An internal general parsed entity is well-formed * if its replacement text matches the production labeled @@ -5560,6 +5590,7 @@ xmlParseReference(xmlParserCtxtPtr ctxt) ret = xmlParseBalancedChunkMemoryInternal(ctxt, value, user_data, &list); ctxt->depth--; + } else if (ent->etype == XML_EXTERNAL_GENERAL_PARSED_ENTITY) { ctxt->depth++; @@ -5573,6 +5604,7 @@ xmlParseReference(xmlParserCtxtPtr ctxt) ctxt->sax->error(ctxt->userData, "Internal: invalid entity type\n"); } + ent->nbentities = ctxt->nbentities - oldnbent; if (ret == XML_ERR_ENTITY_LOOP) { ctxt->errNo = XML_ERR_ENTITY_LOOP; if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL)) @@ -5635,6 +5667,7 @@ xmlParseReference(xmlParserCtxtPtr ctxt) } } } + ctxt->nbentities += ent->nbentities; if ((ctxt->sax != NULL) && (ctxt->sax->reference != NULL) && (ctxt->replaceEntities == 0) && (!ctxt->disableSAX)) { /* @@ -9713,7 +9746,7 @@ xmlParseCtxtExternalEntity(xmlParserCtxt xmlChar start[4]; xmlCharEncoding enc; - if (ctx->depth > 40) { + if ((ctx->depth > 40) || (ctx->nbentities >= 500000)) { return(XML_ERR_ENTITY_LOOP); } @@ -9894,7 +9927,8 @@ xmlParseExternalEntityPrivate(xmlDocPtr xmlChar start[4]; xmlCharEncoding enc; - if (depth > 40) { + if ((depth > 40) || + ((oldctxt != NULL) && (oldctxt->nbentities >= 500000))) { return(XML_ERR_ENTITY_LOOP); } @@ -10053,6 +10087,7 @@ xmlParseExternalEntityPrivate(xmlDocPtr oldctxt->node_seq.maximum = ctxt->node_seq.maximum; oldctxt->node_seq.length = ctxt->node_seq.length; oldctxt->node_seq.buffer = ctxt->node_seq.buffer; + oldctxt->nbentities += ctxt->nbentities; ctxt->node_seq.maximum = 0; ctxt->node_seq.length = 0; ctxt->node_seq.buffer = NULL; @@ -10149,7 +10184,7 @@ xmlParseBalancedChunkMemoryInternal(xmlP int size; int ret = 0; - if (oldctxt->depth > 40) { + if ((oldctxt->depth > 40) || (oldctxt->nbentities >= 500000)) { return(XML_ERR_ENTITY_LOOP); } @@ -10264,6 +10299,7 @@ xmlParseBalancedChunkMemoryInternal(xmlP ctxt->myDoc->children = content; } + oldctxt->nbentities += ctxt->nbentities; ctxt->sax = oldsax; xmlFreeParserCtxt(ctxt); if (newDoc != NULL)