1
0
mirror of https://gitlab.gnome.org/GNOME/libxml2.git synced 2025-10-23 01:52:48 +03:00

parser: Rework handling of undeclared entities

Throw an error if entity substitution was requested.

Now we only downgrade to a warning if

- XML_PARSE_DTDLOAD wasn't specified, and
- entity aren't substituted or XML_PARSE_NO_XXE was specified.

Should fix #724.
This commit is contained in:
Nick Wellnhofer
2024-05-15 17:52:20 +02:00
parent 51b5d1e378
commit 4fefba4cf6
3 changed files with 92 additions and 74 deletions

160
parser.c
View File

@@ -349,6 +349,23 @@ xmlFatalErrMsgStr(xmlParserCtxtPtr ctxt, xmlParserErrors error,
val, NULL, NULL, 0, msg, val); val, NULL, NULL, 0, msg, val);
} }
/**
* xmlErrMsgStr:
* @ctxt: an XML parser context
* @error: the error number
* @msg: the error message
* @val: a string value
*
* Handle a non fatal parser error
*/
static void LIBXML_ATTR_FORMAT(3,0)
xmlErrMsgStr(xmlParserCtxtPtr ctxt, xmlParserErrors error,
const char *msg, const xmlChar * val)
{
xmlCtxtErr(ctxt, NULL, XML_FROM_PARSER, error, XML_ERR_ERROR,
val, NULL, NULL, 0, msg, val);
}
/** /**
* xmlNsErr: * xmlNsErr:
* @ctxt: an XML parser context * @ctxt: an XML parser context
@@ -7501,6 +7518,65 @@ xmlParseReference(xmlParserCtxtPtr ctxt) {
} }
} }
static void
xmlHandleUndeclaredEntity(xmlParserCtxtPtr ctxt, const xmlChar *name) {
/*
* [ WFC: Entity Declared ]
* In a document without any DTD, a document with only an
* internal DTD subset which contains no parameter entity
* references, or a document with "standalone='yes'", the
* Name given in the entity reference must match that in an
* entity declaration, except that well-formed documents
* need not declare any of the following entities: amp, lt,
* gt, apos, quot.
* The declaration of a parameter entity must precede any
* reference to it.
* Similarly, the declaration of a general entity must
* precede any reference to it which appears in a default
* value in an attribute-list declaration. Note that if
* entities are declared in the external subset or in
* external parameter entities, a non-validating processor
* is not obligated to read and process their declarations;
* for such documents, the rule that an entity must be
* declared is a well-formedness constraint only if
* standalone='yes'.
*/
if ((ctxt->standalone == 1) ||
((ctxt->hasExternalSubset == 0) &&
(ctxt->hasPErefs == 0))) {
xmlFatalErrMsgStr(ctxt, XML_ERR_UNDECLARED_ENTITY,
"Entity '%s' not defined\n", name);
} else if (ctxt->validate) {
/*
* [ VC: Entity Declared ]
* In a document with an external subset or external
* parameter entities with "standalone='no'", ...
* ... The declaration of a parameter entity must
* precede any reference to it...
*/
xmlValidityError(ctxt, XML_ERR_UNDECLARED_ENTITY,
"Entity '%s' not defined\n", name, NULL);
} else if ((ctxt->loadsubset) ||
((ctxt->replaceEntities) &&
((ctxt->options & XML_PARSE_NO_XXE) == 0))) {
/*
* Also raise a non-fatal error
*
* - if the external subset is loaded and all entity declarations
* should be available, or
* - entity substition was requested without restricting
* external entity access.
*/
xmlErrMsgStr(ctxt, XML_WAR_UNDECLARED_ENTITY,
"Entity '%s' not defined\n", name);
} else {
xmlWarningMsg(ctxt, XML_WAR_UNDECLARED_ENTITY,
"Entity '%s' not defined\n", name, NULL);
}
ctxt->valid = 0;
}
static xmlEntityPtr static xmlEntityPtr
xmlLookupGeneralEntity(xmlParserCtxtPtr ctxt, const xmlChar *name, int inAttr) { xmlLookupGeneralEntity(xmlParserCtxtPtr ctxt, const xmlChar *name, int inAttr) {
xmlEntityPtr ent; xmlEntityPtr ent;
@@ -7529,49 +7605,9 @@ xmlLookupGeneralEntity(xmlParserCtxtPtr ctxt, const xmlChar *name, int inAttr) {
ent = xmlSAX2GetEntity(ctxt, name); ent = xmlSAX2GetEntity(ctxt, name);
} }
} }
/*
* [ WFC: Entity Declared ]
* In a document without any DTD, a document with only an
* internal DTD subset which contains no parameter entity
* references, or a document with "standalone='yes'", the
* Name given in the entity reference must match that in an
* entity declaration, except that well-formed documents
* need not declare any of the following entities: amp, lt,
* gt, apos, quot.
* The declaration of a parameter entity must precede any
* reference to it.
* Similarly, the declaration of a general entity must
* precede any reference to it which appears in a default
* value in an attribute-list declaration. Note that if
* entities are declared in the external subset or in
* external parameter entities, a non-validating processor
* is not obligated to read and process their declarations;
* for such documents, the rule that an entity must be
* declared is a well-formedness constraint only if
* standalone='yes'.
*/
if (ent == NULL) { if (ent == NULL) {
if (((!ctxt->validate) && (ctxt->loadsubset)) || xmlHandleUndeclaredEntity(ctxt, name);
(ctxt->standalone == 1) ||
((ctxt->hasExternalSubset == 0) &&
(ctxt->hasPErefs == 0))) {
xmlFatalErrMsgStr(ctxt, XML_ERR_UNDECLARED_ENTITY,
"Entity '%s' not defined\n", name);
} else if (ctxt->validate) {
/*
* [ VC: Entity Declared ]
* In a document with an external subset or external
* parameter entities with "standalone='no'", ...
* ... The declaration of a parameter entity must
* precede any reference to it...
*/
xmlValidityError(ctxt, XML_ERR_UNDECLARED_ENTITY,
"Entity '%s' not defined\n", name, NULL);
} else {
xmlWarningMsg(ctxt, XML_WAR_UNDECLARED_ENTITY,
"Entity '%s' not defined\n", name, NULL);
}
ctxt->valid = 0;
} }
/* /*
@@ -7776,27 +7812,18 @@ xmlParsePEReference(xmlParserCtxtPtr ctxt)
NEXT; NEXT;
/* Must be set before xmlHandleUndeclaredEntity */
ctxt->hasPErefs = 1;
/* /*
* Request the entity from SAX * Request the entity from SAX
*/ */
if ((ctxt->sax != NULL) && if ((ctxt->sax != NULL) &&
(ctxt->sax->getParameterEntity != NULL)) (ctxt->sax->getParameterEntity != NULL))
entity = ctxt->sax->getParameterEntity(ctxt->userData, name); entity = ctxt->sax->getParameterEntity(ctxt->userData, name);
if (entity == NULL) { if (entity == NULL) {
if (((!ctxt->validate) && (ctxt->loadsubset)) || xmlHandleUndeclaredEntity(ctxt, name);
(ctxt->standalone == 1)) {
xmlFatalErrMsgStr(ctxt, XML_ERR_UNDECLARED_ENTITY,
"PEReference: %%%s; not found\n",
name);
} else if (ctxt->validate) {
xmlValidityError(ctxt, XML_ERR_UNDECLARED_ENTITY,
"PEReference: %%%s; not found\n",
name, NULL);
} else {
xmlWarningMsg(ctxt, XML_WAR_UNDECLARED_ENTITY,
"PEReference: %%%s; not found\n",
name, NULL);
}
} else { } else {
/* /*
* Internal checking in case the entity quest barfed * Internal checking in case the entity quest barfed
@@ -7838,7 +7865,6 @@ xmlParsePEReference(xmlParserCtxtPtr ctxt)
} }
} }
} }
ctxt->hasPErefs = 1;
} }
/** /**
@@ -8033,26 +8059,18 @@ xmlParseStringPEReference(xmlParserCtxtPtr ctxt, const xmlChar **str) {
} }
ptr++; ptr++;
/* Must be set before xmlHandleUndeclaredEntity */
ctxt->hasPErefs = 1;
/* /*
* Request the entity from SAX * Request the entity from SAX
*/ */
if ((ctxt->sax != NULL) && if ((ctxt->sax != NULL) &&
(ctxt->sax->getParameterEntity != NULL)) (ctxt->sax->getParameterEntity != NULL))
entity = ctxt->sax->getParameterEntity(ctxt->userData, name); entity = ctxt->sax->getParameterEntity(ctxt->userData, name);
if (entity == NULL) { if (entity == NULL) {
if (((!ctxt->validate) && (ctxt->loadsubset)) || xmlHandleUndeclaredEntity(ctxt, name);
(ctxt->standalone == 1)) {
xmlFatalErrMsgStr(ctxt, XML_ERR_UNDECLARED_ENTITY,
"PEReference: %%%s; not found\n", name);
} else if (ctxt->validate) {
xmlValidityError(ctxt, XML_ERR_UNDECLARED_ENTITY,
"PEReference: %%%s; not found\n",
name, NULL);
} else {
xmlWarningMsg(ctxt, XML_WAR_UNDECLARED_ENTITY,
"PEReference: %%%s; not found\n",
name, NULL);
}
} else { } else {
/* /*
* Internal checking in case the entity quest barfed * Internal checking in case the entity quest barfed
@@ -8064,7 +8082,7 @@ xmlParseStringPEReference(xmlParserCtxtPtr ctxt, const xmlChar **str) {
name, NULL); name, NULL);
} }
} }
ctxt->hasPErefs = 1;
xmlFree(name); xmlFree(name);
*str = ptr; *str = ptr;
return(entity); return(entity);

View File

@@ -1,4 +1,4 @@
./test/errors/rec_att_default.xml:3: parser warning : Entity 'b' not defined ./test/errors/rec_att_default.xml:3: parser error : Entity 'b' not defined
<!ATTLIST x y CDATA "&a;"> <!ATTLIST x y CDATA "&a;">
^ ^
./test/errors/rec_att_default.xml:6: parser error : Detected an entity reference loop ./test/errors/rec_att_default.xml:6: parser error : Detected an entity reference loop

View File

@@ -7,7 +7,7 @@ SAX.startElementNs(doc, NULL, NULL, 0, 0, 0)
SAX.characters( SAX.characters(
, 5) , 5)
SAX.getEntity(undeclared) SAX.getEntity(undeclared)
SAX.warning: Entity 'undeclared' not defined SAX.error: Entity 'undeclared' not defined
SAX.startElementNs(elem, NULL, NULL, 0, 1, 0, attr='"/> SAX.startElementNs(elem, NULL, NULL, 0, 1, 0, attr='"/>
...', 0) ...', 0)
SAX.endElementNs(elem, NULL, NULL) SAX.endElementNs(elem, NULL, NULL)
@@ -15,7 +15,7 @@ SAX.characters(
, 5) , 5)
SAX.startElementNs(elem, NULL, NULL, 0, 0, 0) SAX.startElementNs(elem, NULL, NULL, 0, 0, 0)
SAX.getEntity(undeclared) SAX.getEntity(undeclared)
SAX.warning: Entity 'undeclared' not defined SAX.error: Entity 'undeclared' not defined
SAX.endElementNs(elem, NULL, NULL) SAX.endElementNs(elem, NULL, NULL)
SAX.characters( SAX.characters(
, 1) , 1)