diff --git a/ChangeLog b/ChangeLog index e730927e..03047a78 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +Mon Feb 3 09:50:26 CET 2003 Daniel Veillard + + * python/libxml.c: removed an unprotedted debug message Aleksi Suhonen + * parser.c: put a guard against infinite document depth, basically + trying to avoid another kind of DoS attack. + * relaxng.c: some code w.r.t. nameClasses + Sun Feb 2 17:01:43 CET 2003 Daniel Veillard * test/relaxng/* result/relaxng/*: check all the namespace support diff --git a/parser.c b/parser.c index f05c64f8..3392c85e 100644 --- a/parser.c +++ b/parser.c @@ -76,6 +76,14 @@ #include #endif +/** + * MAX_DEPTH: + * + * arbitrary depth limit for the XML documents that we allow to + * process. This is not a limitation of the parser but a safety + * boundary feature. + */ +#define MAX_DEPTH 1024 #define XML_PARSER_BIG_BUFFER_SIZE 300 #define XML_PARSER_BUFFER_SIZE 100 @@ -191,6 +199,18 @@ nodePush(xmlParserCtxtPtr ctxt, xmlNodePtr value) return (0); } } +#ifdef MAX_DEPTH + if (ctxt->nodeNr > MAX_DEPTH) { + if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL)) + ctxt->sax->error(ctxt->userData, + "Excessive depth in document: change MAX_DEPTH = %d\n", + MAX_DEPTH); + ctxt->wellFormed = 0; + ctxt->instate = XML_PARSER_EOF; + if (ctxt->recovery == 0) ctxt->disableSAX = 1; + return(0); + } +#endif ctxt->nodeTab[ctxt->nodeNr] = value; ctxt->node = value; return (ctxt->nodeNr++); diff --git a/python/libxml.c b/python/libxml.c index 06039501..f7b752fa 100644 --- a/python/libxml.c +++ b/python/libxml.c @@ -2527,7 +2527,9 @@ libxml_xmlNewNode(ATTRIBUTE_UNUSED PyObject * self, PyObject * args) if (!PyArg_ParseTuple(args, (char *) "s:xmlNewNode", &name)) return (NULL); node = (xmlNodePtr) xmlNewNode(NULL, name); +#ifdef DEBUG printf("NewNode: %s : %p\n", name, (void *) node); +#endif if (node == NULL) { Py_INCREF(Py_None); diff --git a/relaxng.c b/relaxng.c index 220edba1..c3fe55cc 100644 --- a/relaxng.c +++ b/relaxng.c @@ -123,6 +123,7 @@ struct _xmlRelaxNGDefine { xmlRelaxNGDefinePtr parent; /* the parent definition, if any */ xmlRelaxNGDefinePtr next; /* list within grouping sequences */ xmlRelaxNGDefinePtr attrs; /* list of attributes for elements */ + xmlRelaxNGDefinePtr nameClass;/* the nameClass definition if any */ xmlRelaxNGDefinePtr nextHash;/* next define in defs/refs hash tables */ }; @@ -1562,6 +1563,9 @@ static xmlRelaxNGPtr xmlRelaxNGParseDocument( xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node); static int xmlRelaxNGParseGrammarContent( xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes); +static xmlRelaxNGDefinePtr xmlRelaxNGParseNameClass( + xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node, + xmlRelaxNGDefinePtr def); #define IS_BLANK_NODE(n) \ @@ -2420,7 +2424,6 @@ static xmlRelaxNGDefinePtr xmlRelaxNGParseAttribute(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) { xmlRelaxNGDefinePtr ret, cur, last; xmlNodePtr child; - xmlChar *val; int old_flags; ret = xmlRelaxNGNewDefine(ctxt, node); @@ -2438,27 +2441,10 @@ xmlRelaxNGParseAttribute(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) { } old_flags = ctxt->flags; ctxt->flags |= XML_RELAXNG_IN_ATTRIBUTE; - if (IS_RELAXNG(child, "name")) { - val = xmlNodeGetContent(child); - ret->name = val; - val = xmlGetProp(child, BAD_CAST "ns"); - ret->ns = val; - } else if (IS_RELAXNG(child, "anyName")) { - TODO - } else if (IS_RELAXNG(child, "nsName")) { - TODO - } else if (IS_RELAXNG(child, "choice")) { - TODO - } else { - if (ctxt->error != NULL) - ctxt->error(ctxt->userData, - "element: expecting name, anyName, nsName or choice : got %s\n", - child->name); - ctxt->nbErrors++; - ctxt->flags = old_flags; - return(ret); - } - child = child->next; + cur = xmlRelaxNGParseNameClass(ctxt, child, ret); + if (cur != NULL) + child = child->next; + last = NULL; while (child != NULL) { cur = xmlRelaxNGParsePattern(ctxt, child); @@ -2514,6 +2500,75 @@ xmlRelaxNGParseAttribute(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) { return(ret); } +/** + * xmlRelaxNGParseExceptNameClass: + * @ctxt: a Relax-NG parser context + * @node: the except node + * + * parse the content of a RelaxNG nameClass node. + * + * Returns the definition pointer or NULL in case of error. + */ +static xmlRelaxNGDefinePtr +xmlRelaxNGParseExceptNameClass(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) { + TODO + return(NULL); +} + +/** + * xmlRelaxNGParseNameClass: + * @ctxt: a Relax-NG parser context + * @node: the nameClass node + * @def: the current definition + * + * parse the content of a RelaxNG nameClass node. + * + * Returns the definition pointer or NULL in case of error. + */ +static xmlRelaxNGDefinePtr +xmlRelaxNGParseNameClass(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node, + xmlRelaxNGDefinePtr def) { + xmlRelaxNGDefinePtr ret = def; + xmlChar *val; + + if (IS_RELAXNG(node, "name")) { + val = xmlNodeGetContent(node); + ret->name = val; + val = xmlGetProp(node, BAD_CAST "ns"); + ret->ns = val; + } else if (IS_RELAXNG(node, "anyName")) { + ret->name = NULL; + ret->ns = NULL; + if (node->children != NULL) { + ret->nameClass = + xmlRelaxNGParseExceptNameClass(ctxt, node->children); + } + } else if (IS_RELAXNG(node, "nsName")) { + ret->name = NULL; + ret->ns = xmlGetProp(node, BAD_CAST "ns"); + if (ret->ns == NULL) { + if (ctxt->error != NULL) + ctxt->error(ctxt->userData, + "nsName has no ns attribute\n"); + ctxt->nbErrors++; + } + if (node->children != NULL) { + ret->nameClass = + xmlRelaxNGParseExceptNameClass(ctxt, node->children); + } + } else if (IS_RELAXNG(node, "choice")) { + TODO + } else { + if (ctxt->error != NULL) + ctxt->error(ctxt->userData, + "expecting name, anyName, nsName or choice : got %s\n", + node->name); + ctxt->nbErrors++; + return(NULL); + } + return(ret); +} + /** * xmlRelaxNGParseElement: * @ctxt: a Relax-NG parser context @@ -2527,7 +2582,6 @@ static xmlRelaxNGDefinePtr xmlRelaxNGParseElement(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) { xmlRelaxNGDefinePtr ret, cur, last; xmlNodePtr child; - xmlChar *val; const xmlChar *olddefine; ret = xmlRelaxNGNewDefine(ctxt, node); @@ -2543,26 +2597,10 @@ xmlRelaxNGParseElement(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) { ctxt->nbErrors++; return(ret); } - if (IS_RELAXNG(child, "name")) { - val = xmlNodeGetContent(child); - ret->name = val; - val = xmlGetProp(child, BAD_CAST "ns"); - ret->ns = val; - } else if (IS_RELAXNG(child, "anyName")) { - TODO - } else if (IS_RELAXNG(child, "nsName")) { - TODO - } else if (IS_RELAXNG(child, "choice")) { - TODO - } else { - if (ctxt->error != NULL) - ctxt->error(ctxt->userData, - "element: expecting name, anyName, nsName or choice : got %s\n", - child->name); - ctxt->nbErrors++; - return(ret); - } - child = child->next; + cur = xmlRelaxNGParseNameClass(ctxt, child, ret); + if (cur != NULL) + child = child->next; + if (child == NULL) { if (ctxt->error != NULL) ctxt->error(ctxt->userData, @@ -3405,12 +3443,7 @@ xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt, xmlDocPtr doc) { text = text->next; } } - if (text == NULL) { - if (ctxt->error != NULL) - ctxt->error(ctxt->userData, - "xmlRelaxNGParse: attribute without name\n"); - ctxt->nbErrors++; - } else { + if (text != NULL) { xmlSetProp(text, BAD_CAST "ns", BAD_CAST ""); } } @@ -4293,9 +4326,71 @@ xmlRelaxNGValidateAttribute(xmlRelaxNGValidCtxtPtr ctxt, #ifdef DEBUG xmlGenericError(xmlGenericErrorContext, "xmlRelaxNGValidateAttribute(%s): %d\n", define->name, ret); +#endif + } else if (define->ns != NULL) { + for (i = 0;i < ctxt->state->nbAttrs;i++) { + tmp = ctxt->state->attrs[i]; + if ((tmp != NULL) && (tmp->ns != NULL) && + (xmlStrEqual(define->ns, tmp->ns->href))) { + prop = tmp; + break; + } + } + if (prop != NULL) { + value = xmlNodeListGetString(prop->doc, prop->children, 1); + oldvalue = ctxt->state->value; + ctxt->state->value = value; + ret = xmlRelaxNGValidateValueContent(ctxt, define->content); + value = ctxt->state->value; + ctxt->state->value = oldvalue; + if (value != NULL) + xmlFree(value); + if (ret == 0) { + /* + * flag the attribute as processed + */ + ctxt->state->attrs[i] = NULL; + } + } else { + ret = -1; + } +#ifdef DEBUG + xmlGenericError(xmlGenericErrorContext, + "xmlRelaxNGValidateAttribute(nsName ns = %s): %d\n", + define->ns, ret); #endif } else { - TODO + for (i = 0;i < ctxt->state->nbAttrs;i++) { + tmp = ctxt->state->attrs[i]; + if (tmp != NULL) { + prop = tmp; + break; + } + } + if (prop != NULL) { + value = xmlNodeListGetString(prop->doc, prop->children, 1); + oldvalue = ctxt->state->value; + ctxt->state->value = value; + ret = xmlRelaxNGValidateValueContent(ctxt, define->content); + value = ctxt->state->value; + ctxt->state->value = oldvalue; + if (value != NULL) + xmlFree(value); + if (ret == 0) { + /* + * flag the attribute as processed + */ + ctxt->state->attrs[i] = NULL; + } + } else { + ret = -1; + } +#ifdef DEBUG + xmlGenericError(xmlGenericErrorContext, + "xmlRelaxNGValidateAttribute(anyName): %d\n", + ret); +#endif + } return(ret); @@ -4748,11 +4843,11 @@ xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt, node->name, define->ns); return(-1); } - } else { + } else if (define->name != NULL) { if (node->ns != NULL) { VALID_CTXT(); VALID_ERROR("Expecting no namespace for element %s\n", - node->name); + define->name); return(-1); } }