mirror of
https://gitlab.gnome.org/GNOME/libxml2.git
synced 2026-01-26 21:41:34 +03:00
Add RelaxNG include limit
This patch adds a default xmlRelaxNGIncludeLimit of 1.000, and that limit can be modified at runtime with the env variable RNG_INCLUDE_LIMIT. Fix https://gitlab.gnome.org/GNOME/libxml2/-/issues/998
This commit is contained in:
committed by
Daniel Garcia Moreno
parent
354f620a45
commit
19549c6159
@@ -136,6 +136,10 @@ XMLPUBFUN int
|
||||
xmlRelaxParserSetFlag (xmlRelaxNGParserCtxt *ctxt,
|
||||
int flag);
|
||||
|
||||
XMLPUBFUN int
|
||||
xmlRelaxParserSetIncLImit (xmlRelaxNGParserCtxt *ctxt,
|
||||
int limit);
|
||||
|
||||
XMLPUBFUN void
|
||||
xmlRelaxNGFreeParserCtxt (xmlRelaxNGParserCtxt *ctxt);
|
||||
XMLPUBFUN void
|
||||
|
||||
63
relaxng.c
63
relaxng.c
@@ -18,6 +18,8 @@
|
||||
|
||||
#ifdef LIBXML_RELAXNG_ENABLED
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stddef.h>
|
||||
@@ -44,6 +46,12 @@
|
||||
static const xmlChar *xmlRelaxNGNs = (const xmlChar *)
|
||||
"http://relaxng.org/ns/structure/1.0";
|
||||
|
||||
/*
|
||||
* Default include limit, this can be override with RNG_INCLUDE_LIMIT
|
||||
* env variable
|
||||
*/
|
||||
static const int _xmlRelaxNGIncludeLimit = 1000;
|
||||
|
||||
#define IS_RELAXNG(node, typ) \
|
||||
((node != NULL) && (node->ns != NULL) && \
|
||||
(node->type == XML_ELEMENT_NODE) && \
|
||||
@@ -218,6 +226,7 @@ struct _xmlRelaxNGParserCtxt {
|
||||
int incNr; /* Depth of the include parsing stack */
|
||||
int incMax; /* Max depth of the parsing stack */
|
||||
xmlRelaxNGIncludePtr *incTab; /* array of incs */
|
||||
int incLimit; /* Include limit, to avoid stack-overflow on parse */
|
||||
|
||||
int idref; /* requires idref checking */
|
||||
|
||||
@@ -1342,6 +1351,23 @@ xmlRelaxParserSetFlag(xmlRelaxNGParserCtxt *ctxt, int flags)
|
||||
return(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Semi private function used to set the include recursion limit to a
|
||||
* parser context. Set to 0 to use the default value.
|
||||
*
|
||||
* @param ctxt a RelaxNG parser context
|
||||
* @param limit the new include depth limit
|
||||
* @returns 0 if success and -1 in case of error
|
||||
*/
|
||||
int
|
||||
xmlRelaxParserSetIncLImit(xmlRelaxNGParserCtxt *ctxt, int limit)
|
||||
{
|
||||
if (ctxt == NULL) return(-1);
|
||||
if (limit < 0) return(-1);
|
||||
ctxt->incLimit = limit;
|
||||
return(0);
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* *
|
||||
* Document functions *
|
||||
@@ -1397,7 +1423,7 @@ xmlRelaxReadMemory(xmlRelaxNGParserCtxtPtr ctxt, const char *buf, int size) {
|
||||
*
|
||||
* @param ctxt the parser context
|
||||
* @param value the element doc
|
||||
* @returns 0 in case of error, the index in the stack otherwise
|
||||
* @returns -1 in case of error, the index in the stack otherwise
|
||||
*/
|
||||
static int
|
||||
xmlRelaxNGIncludePush(xmlRelaxNGParserCtxtPtr ctxt,
|
||||
@@ -1411,9 +1437,15 @@ xmlRelaxNGIncludePush(xmlRelaxNGParserCtxtPtr ctxt,
|
||||
sizeof(ctxt->incTab[0]));
|
||||
if (ctxt->incTab == NULL) {
|
||||
xmlRngPErrMemory(ctxt);
|
||||
return (0);
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
if (ctxt->incNr >= ctxt->incLimit) {
|
||||
xmlRngPErr(ctxt, (xmlNodePtr)value->doc, XML_RNGP_PARSE_ERROR,
|
||||
"xmlRelaxNG: inclusion recursion limit reached\n", NULL, NULL);
|
||||
return(-1);
|
||||
}
|
||||
|
||||
if (ctxt->incNr >= ctxt->incMax) {
|
||||
ctxt->incMax *= 2;
|
||||
ctxt->incTab =
|
||||
@@ -1422,7 +1454,7 @@ xmlRelaxNGIncludePush(xmlRelaxNGParserCtxtPtr ctxt,
|
||||
sizeof(ctxt->incTab[0]));
|
||||
if (ctxt->incTab == NULL) {
|
||||
xmlRngPErrMemory(ctxt);
|
||||
return (0);
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
ctxt->incTab[ctxt->incNr] = value;
|
||||
@@ -1586,7 +1618,9 @@ xmlRelaxNGLoadInclude(xmlRelaxNGParserCtxtPtr ctxt, const xmlChar * URL,
|
||||
/*
|
||||
* push it on the stack
|
||||
*/
|
||||
xmlRelaxNGIncludePush(ctxt, ret);
|
||||
if (xmlRelaxNGIncludePush(ctxt, ret) < 0) {
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Some preprocessing of the document content, this include recursing
|
||||
@@ -7261,11 +7295,32 @@ xmlRelaxNGParse(xmlRelaxNGParserCtxt *ctxt)
|
||||
xmlDocPtr doc;
|
||||
xmlNodePtr root;
|
||||
|
||||
const char *include_limit_env = getenv("RNG_INCLUDE_LIMIT");
|
||||
|
||||
xmlRelaxNGInitTypes();
|
||||
|
||||
if (ctxt == NULL)
|
||||
return (NULL);
|
||||
|
||||
if (ctxt->incLimit == 0) {
|
||||
ctxt->incLimit = _xmlRelaxNGIncludeLimit;
|
||||
if (include_limit_env != NULL) {
|
||||
char *strEnd;
|
||||
unsigned long val = 0;
|
||||
errno = 0;
|
||||
val = strtoul(include_limit_env, &strEnd, 10);
|
||||
if (errno != 0 || *strEnd != 0 || val > INT_MAX) {
|
||||
xmlRngPErr(ctxt, NULL, XML_RNGP_PARSE_ERROR,
|
||||
"xmlRelaxNGParse: invalid RNG_INCLUDE_LIMIT %s\n",
|
||||
(const xmlChar*)include_limit_env,
|
||||
NULL);
|
||||
return(NULL);
|
||||
}
|
||||
if (val)
|
||||
ctxt->incLimit = val;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* First step is to parse the input document into an DOM/Infoset
|
||||
*/
|
||||
|
||||
67
runtest.c
67
runtest.c
@@ -3741,6 +3741,70 @@ rngTest(const char *filename,
|
||||
return(ret);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse an RNG schemas with a custom RNG_INCLUDE_LIMIT
|
||||
*
|
||||
* @param filename the schemas file
|
||||
* @param result the file with expected result
|
||||
* @param err the file with error messages
|
||||
* @returns 0 in case of success, an error code otherwise
|
||||
*/
|
||||
static int
|
||||
rngIncludeTest(const char *filename,
|
||||
const char *resul ATTRIBUTE_UNUSED,
|
||||
const char *errr ATTRIBUTE_UNUSED,
|
||||
int options ATTRIBUTE_UNUSED) {
|
||||
xmlRelaxNGParserCtxtPtr ctxt;
|
||||
xmlRelaxNGPtr schemas;
|
||||
int ret = 0;
|
||||
|
||||
/* first compile the schemas if possible */
|
||||
ctxt = xmlRelaxNGNewParserCtxt(filename);
|
||||
xmlRelaxNGSetParserStructuredErrors(ctxt, testStructuredErrorHandler,
|
||||
NULL);
|
||||
|
||||
/* Should work */
|
||||
schemas = xmlRelaxNGParse(ctxt);
|
||||
if (schemas == NULL) {
|
||||
testErrorHandler(NULL, "Relax-NG schema %s failed to compile\n",
|
||||
filename);
|
||||
ret = -1;
|
||||
goto done;
|
||||
}
|
||||
xmlRelaxNGFree(schemas);
|
||||
xmlRelaxNGFreeParserCtxt(ctxt);
|
||||
|
||||
ctxt = xmlRelaxNGNewParserCtxt(filename);
|
||||
/* Should fail */
|
||||
xmlRelaxParserSetIncLImit(ctxt, 2);
|
||||
xmlRelaxNGSetParserStructuredErrors(ctxt, testStructuredErrorHandler,
|
||||
NULL);
|
||||
schemas = xmlRelaxNGParse(ctxt);
|
||||
if (schemas != NULL) {
|
||||
ret = -1;
|
||||
xmlRelaxNGFree(schemas);
|
||||
}
|
||||
xmlRelaxNGFreeParserCtxt(ctxt);
|
||||
|
||||
ctxt = xmlRelaxNGNewParserCtxt(filename);
|
||||
/* Should work */
|
||||
xmlRelaxParserSetIncLImit(ctxt, 3);
|
||||
xmlRelaxNGSetParserStructuredErrors(ctxt, testStructuredErrorHandler,
|
||||
NULL);
|
||||
schemas = xmlRelaxNGParse(ctxt);
|
||||
if (schemas == NULL) {
|
||||
testErrorHandler(NULL, "Relax-NG schema %s failed to compile\n",
|
||||
filename);
|
||||
ret = -1;
|
||||
goto done;
|
||||
}
|
||||
xmlRelaxNGFree(schemas);
|
||||
|
||||
done:
|
||||
xmlRelaxNGFreeParserCtxt(ctxt);
|
||||
return(ret);
|
||||
}
|
||||
|
||||
#ifdef LIBXML_READER_ENABLED
|
||||
/**
|
||||
* Parse a set of files with streaming, applying an RNG schemas
|
||||
@@ -5202,6 +5266,9 @@ testDesc testDescriptions[] = {
|
||||
{ "Relax-NG regression tests" ,
|
||||
rngTest, "./test/relaxng/*.rng", NULL, NULL, NULL,
|
||||
XML_PARSE_DTDATTR | XML_PARSE_NOENT },
|
||||
{ "Relax-NG include limit tests" ,
|
||||
rngIncludeTest, "./test/relaxng/include/include-limit.rng", NULL, NULL, NULL,
|
||||
0 },
|
||||
#ifdef LIBXML_READER_ENABLED
|
||||
{ "Relax-NG streaming regression tests" ,
|
||||
rngStreamTest, "./test/relaxng/*.rng", NULL, NULL, NULL,
|
||||
|
||||
4
test/relaxng/include/include-limit.rng
Normal file
4
test/relaxng/include/include-limit.rng
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<grammar xmlns="http://relaxng.org/ns/structure/1.0">
|
||||
<include href="include-limit_1.rng"/>
|
||||
</grammar>
|
||||
4
test/relaxng/include/include-limit_1.rng
Normal file
4
test/relaxng/include/include-limit_1.rng
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<grammar xmlns="http://relaxng.org/ns/structure/1.0">
|
||||
<include href="include-limit_2.rng"/>
|
||||
</grammar>
|
||||
4
test/relaxng/include/include-limit_2.rng
Normal file
4
test/relaxng/include/include-limit_2.rng
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<grammar xmlns="http://relaxng.org/ns/structure/1.0">
|
||||
<include href="include-limit_3.rng"/>
|
||||
</grammar>
|
||||
8
test/relaxng/include/include-limit_3.rng
Normal file
8
test/relaxng/include/include-limit_3.rng
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<grammar xmlns="http://relaxng.org/ns/structure/1.0">
|
||||
<start>
|
||||
<element name="root">
|
||||
<empty/>
|
||||
</element>
|
||||
</start>
|
||||
</grammar>
|
||||
Reference in New Issue
Block a user