mirror of
https://gitlab.gnome.org/GNOME/libxml2.git
synced 2025-01-12 09:17:37 +03:00
parser: Allow to set maximum amplification factor
This commit is contained in:
parent
9d80a2b134
commit
ed3bd05284
@ -93,6 +93,7 @@
|
||||
<arg choice="plain"><option>--xmlout</option></arg>
|
||||
<arg choice="plain"><option>--push</option></arg>
|
||||
<arg choice="plain"><option>--memory</option></arg>
|
||||
<arg choice="plain"><option>--max-ampl <replaceable class="option">INTEGER</replaceable></option></arg>
|
||||
<arg choice="plain"><option>--maxmem <replaceable class="option">NBBYTES</replaceable></option></arg>
|
||||
<arg choice="plain"><option>--nowarning</option></arg>
|
||||
<arg choice="plain"><option>--noblanks</option></arg>
|
||||
@ -338,6 +339,18 @@
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--max-ampl <replaceable class="option">INTEGER</replaceable></option></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Set the maximum amplification factor which protects against
|
||||
exponential entity expansion ("billion laughs"). The default value
|
||||
is 5. Documents making heavy use of entity expansion may require a
|
||||
higher value.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--maxmem <replaceable class="option">NNBYTES</replaceable></option></term>
|
||||
<listitem>
|
||||
|
@ -312,6 +312,7 @@ struct _xmlParserCtxt {
|
||||
int endCheckState; /* quote state for push parser */
|
||||
unsigned short nbErrors; /* number of errors */
|
||||
unsigned short nbWarnings; /* number of warnings */
|
||||
unsigned maxAmpl; /* maximum amplification factor */
|
||||
};
|
||||
|
||||
/**
|
||||
@ -1149,6 +1150,9 @@ XMLPUBFUN int
|
||||
XMLPUBFUN int
|
||||
xmlCtxtUseOptions (xmlParserCtxtPtr ctxt,
|
||||
int options);
|
||||
XMLPUBFUN void
|
||||
xmlCtxtSetMaxAmplification(xmlParserCtxtPtr ctxt,
|
||||
unsigned maxAmpl);
|
||||
XMLPUBFUN xmlDocPtr
|
||||
xmlReadDoc (const xmlChar *cur,
|
||||
const char *URL,
|
||||
|
@ -121,6 +121,9 @@ XMLPUBFUN int
|
||||
xmlTextReaderSetup(xmlTextReaderPtr reader,
|
||||
xmlParserInputBufferPtr input, const char *URL,
|
||||
const char *encoding, int options);
|
||||
XMLPUBFUN void
|
||||
xmlTextReaderSetMaxAmplification(xmlTextReaderPtr reader,
|
||||
unsigned maxAmpl);
|
||||
|
||||
/*
|
||||
* Iterators
|
||||
|
32
parser.c
32
parser.c
@ -121,13 +121,7 @@ xmlParseElementEnd(xmlParserCtxtPtr ctxt);
|
||||
*/
|
||||
|
||||
/*
|
||||
* XML_PARSER_NON_LINEAR is roughly the maximum allowed amplification factor
|
||||
* of serialized output after entity expansion.
|
||||
*/
|
||||
#define XML_PARSER_NON_LINEAR 5
|
||||
|
||||
/*
|
||||
* A certain amount is always allowed.
|
||||
* A certain amount of entity expansion which is always allowed.
|
||||
*/
|
||||
#define XML_PARSER_ALLOWED_EXPANSION 1000000
|
||||
|
||||
@ -590,9 +584,10 @@ xmlParserEntityCheck(xmlParserCtxtPtr ctxt, unsigned long extra)
|
||||
*/
|
||||
if ((ctxt->sizeentcopy > XML_PARSER_ALLOWED_EXPANSION) &&
|
||||
((ctxt->sizeentcopy >= ULONG_MAX) ||
|
||||
(ctxt->sizeentcopy / XML_PARSER_NON_LINEAR > consumed))) {
|
||||
(ctxt->sizeentcopy / ctxt->maxAmpl > consumed))) {
|
||||
xmlFatalErrMsg(ctxt, XML_ERR_ENTITY_LOOP,
|
||||
"Maximum entity amplification factor exceeded");
|
||||
"Maximum entity amplification factor exceeded, see "
|
||||
"xmlCtxtSetMaxAmplification.\n");
|
||||
xmlHaltParser(ctxt);
|
||||
return(1);
|
||||
}
|
||||
@ -14301,6 +14296,25 @@ xmlCtxtUseOptions(xmlParserCtxtPtr ctxt, int options)
|
||||
return(xmlCtxtUseOptionsInternal(ctxt, options, NULL));
|
||||
}
|
||||
|
||||
/**
|
||||
* xmlCtxtSetMaxAmplification:
|
||||
* @ctxt: an XML parser context
|
||||
* @maxAmpl: maximum amplification factor
|
||||
*
|
||||
* To protect against exponential entity expansion ("billion laughs"), the
|
||||
* size of serialized output is (roughly) limited to the input size
|
||||
* multiplied by this factor. The default value is 5.
|
||||
*
|
||||
* When working with documents making heavy use of entity expansion, it can
|
||||
* be necessary to increase the value. For security reasons, this should only
|
||||
* be considered when processing trusted input.
|
||||
*/
|
||||
void
|
||||
xmlCtxtSetMaxAmplification(xmlParserCtxtPtr ctxt, unsigned maxAmpl)
|
||||
{
|
||||
ctxt->maxAmpl = maxAmpl;
|
||||
}
|
||||
|
||||
/**
|
||||
* xmlDoRead:
|
||||
* @ctxt: an XML parser context
|
||||
|
@ -49,6 +49,12 @@
|
||||
#include "private/io.h"
|
||||
#include "private/parser.h"
|
||||
|
||||
/*
|
||||
* XML_MAX_AMPLIFICATION_DEFAULT is the default maximum allowed amplification
|
||||
* factor of serialized output after entity expansion.
|
||||
*/
|
||||
#define XML_MAX_AMPLIFICATION_DEFAULT 5
|
||||
|
||||
/*
|
||||
* Various global defaults for parsing
|
||||
*/
|
||||
@ -2110,6 +2116,7 @@ xmlInitSAXParserCtxt(xmlParserCtxtPtr ctxt, const xmlSAXHandler *sax,
|
||||
ctxt->sizeentities = 0;
|
||||
ctxt->sizeentcopy = 0;
|
||||
ctxt->input_id = 1;
|
||||
ctxt->maxAmpl = XML_MAX_AMPLIFICATION_DEFAULT;
|
||||
xmlInitNodeInfoSeq(&ctxt->node_seq);
|
||||
return(0);
|
||||
}
|
||||
|
113
xmllint.c
113
xmllint.c
@ -194,6 +194,7 @@ static const char *xpathquery = NULL;
|
||||
static int options = XML_PARSE_COMPACT | XML_PARSE_BIG_LINES;
|
||||
static int sax = 0;
|
||||
static int oldxml10 = 0;
|
||||
static unsigned maxAmpl = 0;
|
||||
|
||||
/************************************************************************
|
||||
* *
|
||||
@ -1648,6 +1649,8 @@ testSAX(const char *filename) {
|
||||
progresult = XMLLINT_ERR_MEM;
|
||||
return;
|
||||
}
|
||||
if (maxAmpl > 0)
|
||||
xmlCtxtSetMaxAmplification(ctxt, maxAmpl);
|
||||
xmlCtxtReadFile(ctxt, filename, NULL, options);
|
||||
|
||||
if (ctxt->myDoc != NULL) {
|
||||
@ -1799,6 +1802,8 @@ static void streamFile(char *filename) {
|
||||
|
||||
|
||||
if (reader != NULL) {
|
||||
if (maxAmpl > 0)
|
||||
xmlTextReaderSetMaxAmplification(reader, maxAmpl);
|
||||
#ifdef LIBXML_VALID_ENABLED
|
||||
if (valid)
|
||||
xmlTextReaderSetParserProp(reader, XML_PARSER_VALIDATE, 1);
|
||||
@ -2220,6 +2225,8 @@ static void parseAndPrintFile(char *filename, xmlParserCtxtPtr rectxt) {
|
||||
return;
|
||||
}
|
||||
xmlCtxtUseOptions(ctxt, options);
|
||||
if (maxAmpl > 0)
|
||||
xmlCtxtSetMaxAmplification(ctxt, maxAmpl);
|
||||
while ((res = fread(chars, 1, size, f)) > 0) {
|
||||
xmlParseChunk(ctxt, chars, res, 0);
|
||||
}
|
||||
@ -2263,6 +2270,8 @@ static void parseAndPrintFile(char *filename, xmlParserCtxtPtr rectxt) {
|
||||
progresult = XMLLINT_ERR_MEM;
|
||||
return;
|
||||
}
|
||||
if (maxAmpl > 0)
|
||||
xmlCtxtSetMaxAmplification(ctxt, maxAmpl);
|
||||
} else {
|
||||
ctxt = rectxt;
|
||||
}
|
||||
@ -2293,12 +2302,24 @@ static void parseAndPrintFile(char *filename, xmlParserCtxtPtr rectxt) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (rectxt == NULL)
|
||||
doc = xmlReadMemory((char *) base, info.st_size,
|
||||
filename, NULL, options);
|
||||
else
|
||||
if (rectxt == NULL) {
|
||||
xmlParserCtxtPtr ctxt;
|
||||
|
||||
ctxt = xmlNewParserCtxt();
|
||||
if (ctxt == NULL) {
|
||||
fprintf(stderr, "out of memory\n");
|
||||
progresult = XMLLINT_ERR_MEM;
|
||||
return;
|
||||
}
|
||||
if (maxAmpl > 0)
|
||||
xmlCtxtSetMaxAmplification(ctxt, maxAmpl);
|
||||
doc = xmlCtxtReadMemory(ctxt, base, info.st_size,
|
||||
filename, NULL, options);
|
||||
xmlFreeParserCtxt(ctxt);
|
||||
} else {
|
||||
doc = xmlCtxtReadMemory(rectxt, (char *) base, info.st_size,
|
||||
filename, NULL, options);
|
||||
}
|
||||
|
||||
munmap((char *) base, info.st_size);
|
||||
close(fd);
|
||||
@ -2317,6 +2338,8 @@ static void parseAndPrintFile(char *filename, xmlParserCtxtPtr rectxt) {
|
||||
ctxt = rectxt;
|
||||
}
|
||||
|
||||
if (maxAmpl > 0)
|
||||
xmlCtxtSetMaxAmplification(ctxt, maxAmpl);
|
||||
doc = xmlCtxtReadFile(ctxt, filename, NULL, options);
|
||||
|
||||
if (ctxt->valid == 0)
|
||||
@ -2325,10 +2348,22 @@ static void parseAndPrintFile(char *filename, xmlParserCtxtPtr rectxt) {
|
||||
xmlFreeParserCtxt(ctxt);
|
||||
#endif /* LIBXML_VALID_ENABLED */
|
||||
} else {
|
||||
if (rectxt != NULL)
|
||||
if (rectxt != NULL) {
|
||||
doc = xmlCtxtReadFile(rectxt, filename, NULL, options);
|
||||
else
|
||||
doc = xmlReadFile(filename, NULL, options);
|
||||
} else {
|
||||
xmlParserCtxtPtr ctxt;
|
||||
|
||||
ctxt = xmlNewParserCtxt();
|
||||
if (ctxt == NULL) {
|
||||
fprintf(stderr, "out of memory\n");
|
||||
progresult = XMLLINT_ERR_MEM;
|
||||
return;
|
||||
}
|
||||
if (maxAmpl > 0)
|
||||
xmlCtxtSetMaxAmplification(ctxt, maxAmpl);
|
||||
doc = xmlCtxtReadFile(ctxt, filename, NULL, options);
|
||||
xmlFreeParserCtxt(ctxt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -3050,6 +3085,7 @@ static void usage(FILE *f, const char *name) {
|
||||
#ifdef LIBXML_XPATH_ENABLED
|
||||
fprintf(f, "\t--xpath expr: evaluate the XPath expression, imply --noout\n");
|
||||
#endif
|
||||
fprintf(f, "\t--max-ampl value: set maximum amplification factor\n");
|
||||
|
||||
fprintf(f, "\nLibxml project home page: https://gitlab.gnome.org/GNOME/libxml2\n");
|
||||
}
|
||||
@ -3073,6 +3109,26 @@ static void deregisterNode(xmlNodePtr node)
|
||||
nbregister--;
|
||||
}
|
||||
|
||||
static unsigned long
|
||||
parseInteger(const char *ctxt, const char *str,
|
||||
unsigned long min, unsigned long max) {
|
||||
char *strEnd;
|
||||
unsigned long val;
|
||||
|
||||
errno = 0;
|
||||
val = strtoul(str, &strEnd, 10);
|
||||
if (errno == EINVAL || *strEnd != 0) {
|
||||
fprintf(stderr, "%s: invalid integer: %s\n", ctxt, str);
|
||||
exit(XMLLINT_ERR_UNCLASS);
|
||||
}
|
||||
if (errno != 0 || val < min || val > max) {
|
||||
fprintf(stderr, "%s: integer out of range: %s\n", ctxt, str);
|
||||
exit(XMLLINT_ERR_UNCLASS);
|
||||
}
|
||||
|
||||
return(val);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv) {
|
||||
int i, acount;
|
||||
@ -3092,25 +3148,13 @@ main(int argc, char **argv) {
|
||||
|
||||
if ((!strcmp(argv[i], "-maxmem")) ||
|
||||
(!strcmp(argv[i], "--maxmem"))) {
|
||||
char *val_end;
|
||||
long val;
|
||||
|
||||
i++;
|
||||
if (i >= argc) {
|
||||
fprintf(stderr, "maxmem: missing integer value\n");
|
||||
return(XMLLINT_ERR_UNCLASS);
|
||||
}
|
||||
errno = 0;
|
||||
val = strtol(argv[i], &val_end, 10);
|
||||
if (errno == EINVAL || *val_end != 0) {
|
||||
fprintf(stderr, "maxmem: invalid integer: %s\n", argv[i]);
|
||||
return(XMLLINT_ERR_UNCLASS);
|
||||
}
|
||||
if (errno != 0 || val < 0 || val > INT_MAX) {
|
||||
fprintf(stderr, "maxmem: integer out of range: %s\n", argv[i]);
|
||||
return(XMLLINT_ERR_UNCLASS);
|
||||
}
|
||||
maxmem = val;
|
||||
maxmem = parseInteger("maxmem", argv[i], 0, INT_MAX);
|
||||
}
|
||||
}
|
||||
if (maxmem != 0)
|
||||
@ -3446,6 +3490,14 @@ main(int argc, char **argv) {
|
||||
(!strcmp(argv[i], "--oldxml10"))) {
|
||||
oldxml10++;
|
||||
options |= XML_PARSE_OLD10;
|
||||
} else if ((!strcmp(argv[i], "-max-ampl")) ||
|
||||
(!strcmp(argv[i], "--max-ampl"))) {
|
||||
i++;
|
||||
if (i >= argc) {
|
||||
fprintf(stderr, "max-ampl: missing integer value\n");
|
||||
return(XMLLINT_ERR_UNCLASS);
|
||||
}
|
||||
maxAmpl = parseInteger("max-ampl", argv[i], 1, UINT_MAX);
|
||||
} else {
|
||||
fprintf(stderr, "Unknown option %s\n", argv[i]);
|
||||
usage(stderr, argv[0]);
|
||||
@ -3678,12 +3730,25 @@ main(int argc, char **argv) {
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
if ((!strcmp(argv[i], "-max-ampl")) ||
|
||||
(!strcmp(argv[i], "--max-ampl"))) {
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
if ((timing) && (repeat))
|
||||
startTimer();
|
||||
/* Remember file names. "-" means stdin. <sven@zen.org> */
|
||||
if ((argv[i][0] != '-') || (strcmp(argv[i], "-") == 0)) {
|
||||
if (repeat) {
|
||||
xmlParserCtxtPtr ctxt = NULL;
|
||||
xmlParserCtxtPtr ctxt;
|
||||
|
||||
ctxt = xmlNewParserCtxt();
|
||||
if (ctxt == NULL) {
|
||||
progresult = XMLLINT_ERR_MEM;
|
||||
goto error;
|
||||
}
|
||||
if (maxAmpl > 0)
|
||||
xmlCtxtSetMaxAmplification(ctxt, maxAmpl);
|
||||
|
||||
for (acount = 0;acount < repeat;acount++) {
|
||||
#ifdef LIBXML_READER_ENABLED
|
||||
@ -3694,16 +3759,14 @@ main(int argc, char **argv) {
|
||||
if (sax) {
|
||||
testSAX(argv[i]);
|
||||
} else {
|
||||
if (ctxt == NULL)
|
||||
ctxt = xmlNewParserCtxt();
|
||||
parseAndPrintFile(argv[i], ctxt);
|
||||
}
|
||||
#ifdef LIBXML_READER_ENABLED
|
||||
}
|
||||
#endif /* LIBXML_READER_ENABLED */
|
||||
}
|
||||
if (ctxt != NULL)
|
||||
xmlFreeParserCtxt(ctxt);
|
||||
|
||||
xmlFreeParserCtxt(ctxt);
|
||||
} else {
|
||||
nbregister = 0;
|
||||
|
||||
|
13
xmlreader.c
13
xmlreader.c
@ -5235,6 +5235,19 @@ xmlTextReaderSetup(xmlTextReaderPtr reader,
|
||||
return (0);
|
||||
}
|
||||
|
||||
/**
|
||||
* xmlTextReaderSetMaxAmplification:
|
||||
* @reader: an XML reader
|
||||
* @maxAmpl: maximum amplification factor
|
||||
*
|
||||
* Set the maximum amplification factor. See xmlCtxtSetMaxAmplification.
|
||||
*/
|
||||
void
|
||||
xmlTextReaderSetMaxAmplification(xmlTextReaderPtr reader, unsigned maxAmpl)
|
||||
{
|
||||
xmlCtxtSetMaxAmplification(reader->ctxt, maxAmpl);
|
||||
}
|
||||
|
||||
/**
|
||||
* xmlTextReaderByteConsumed:
|
||||
* @reader: an XML reader
|
||||
|
Loading…
Reference in New Issue
Block a user