--- include/libxml/entities.h.orig 2002-03-13 04:35:14.000000000 +0100 +++ include/libxml/entities.h 2008-08-11 19:40:53.000000000 +0200 @@ -52,6 +52,7 @@ struct _xmlEntity { struct _xmlEntity *nexte; /* unused */ const xmlChar *URI; /* the full URI as computed */ + unsigned long nbentities; /* the number of entities references */ }; /* --- include/libxml/parser.h.orig 2002-03-13 04:35:14.000000000 +0100 +++ include/libxml/parser.h 2008-08-11 19:41:53.000000000 +0200 @@ -219,6 +219,7 @@ struct _xmlParserCtxt { int loadsubset; /* should the external subset be loaded */ int linenumbers; /* set line number in element content */ void *catalogs; /* document's own catalog */ + unsigned long nbentities; /* number of entities references */ }; /** --- parser.c.orig 2002-03-21 04:35:11.000000000 +0100 +++ parser.c 2008-08-11 19:53:04.000000000 +0200 @@ -919,7 +919,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, @@ -959,6 +959,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) { @@ -1003,6 +1008,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; @@ -1033,6 +1043,10 @@ xmlStringDecodeEntities(xmlParserCtxtPtr } buffer[nbchars++] = 0; return(buffer); +int_error: + if (buffer != NULL) + xmlFree(buffer); + return(NULL); } @@ -2279,6 +2293,9 @@ xmlParseAttValue(xmlParserCtxtPtr ctxt) } } else { ent = xmlParseEntityRef(ctxt); + ctxt->nbentities++; + if (ent != NULL) + ctxt->nbentities += ent->nbentities; if ((ent != NULL) && (ctxt->replaceEntities != 0)) { xmlChar *rep; @@ -3337,6 +3354,7 @@ xmlParseEntityDecl(xmlParserCtxtPtr ctxt xmlChar *ndata = NULL; int isParameter = 0; xmlChar *orig = NULL; + unsigned long oldnbent = ctxt->nbentities; GROW; if ((RAW == '<') && (NXT(1) == '!') && @@ -3612,6 +3630,7 @@ xmlParseEntityDecl(xmlParserCtxtPtr ctxt } } if (cur != NULL) { + cur->nbentities = ctxt->nbentities - oldnbent; if (cur->orig != NULL) xmlFree(orig); else @@ -5228,6 +5247,15 @@ 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; + return; + } if ((ent->name != NULL) && (ent->etype != XML_INTERNAL_PREDEFINED_ENTITY)) { xmlNodePtr list = NULL; @@ -5285,6 +5313,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 @@ -5308,6 +5337,7 @@ xmlParseReference(xmlParserCtxtPtr ctxt) ctxt->sax, user_data, ctxt->depth, value, &list); ctxt->depth--; + } else if (ent->etype == XML_EXTERNAL_GENERAL_PARSED_ENTITY) { ctxt->depth++; @@ -5321,6 +5351,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)) @@ -5379,6 +5410,7 @@ xmlParseReference(xmlParserCtxtPtr ctxt) } } } + ctxt->nbentities += ent->nbentities; if ((ctxt->sax != NULL) && (ctxt->sax->reference != NULL) && (ctxt->replaceEntities == 0) && (!ctxt->disableSAX)) { /* @@ -9251,7 +9283,7 @@ xmlParseCtxtExternalEntity(xmlParserCtxt xmlChar start[4]; xmlCharEncoding enc; - if (ctx->depth > 40) { + if ((ctx->depth > 40) || (ctx->nbentities >= 500000)) { return(XML_ERR_ENTITY_LOOP); } @@ -9428,7 +9460,8 @@ xmlParseExternalEntityPrivate(xmlDocPtr xmlChar start[4]; xmlCharEncoding enc; - if (depth > 40) { + if ((depth > 40) || + ((oldctxt != NULL) && (oldctxt->nbentities >= 500000))) { return(XML_ERR_ENTITY_LOOP); } @@ -9572,6 +9605,7 @@ xmlParseExternalEntityPrivate(xmlDocPtr } ret = 0; } + oldctxt->nbentities += ctxt->nbentities; if (sax != NULL) ctxt->sax = oldsax; xmlFreeParserCtxt(ctxt);