1
0
mirror of https://gitlab.gnome.org/GNOME/libxml2.git synced 2025-08-01 10:06:59 +03:00

parser: Check reallocations for overflow

This commit is contained in:
Nick Wellnhofer
2024-12-15 23:36:04 +01:00
parent 5320a4aa38
commit 8231c03663
2 changed files with 289 additions and 211 deletions

447
parser.c
View File

@ -73,6 +73,7 @@
#include "private/error.h" #include "private/error.h"
#include "private/html.h" #include "private/html.h"
#include "private/io.h" #include "private/io.h"
#include "private/memory.h"
#include "private/parser.h" #include "private/parser.h"
#define NS_INDEX_EMPTY INT_MAX #define NS_INDEX_EMPTY INT_MAX
@ -88,6 +89,8 @@
#define SIZE_MAX ((size_t) -1) #define SIZE_MAX ((size_t) -1)
#endif #endif
#define XML_MAX_ATTRS 100000000 /* 100 million */
struct _xmlStartTag { struct _xmlStartTag {
const xmlChar *prefix; const xmlChar *prefix;
const xmlChar *URI; const xmlChar *URI;
@ -1104,7 +1107,19 @@ xmlAddDefAttrs(xmlParserCtxtPtr ctxt,
xmlDefAttrsPtr temp; xmlDefAttrsPtr temp;
int newSize; int newSize;
newSize = (defaults != NULL) ? 2 * defaults->maxAttrs : 4; if (defaults == NULL) {
newSize = 4;
} else {
if ((defaults->maxAttrs >= XML_MAX_ATTRS) ||
((size_t) defaults->maxAttrs >
SIZE_MAX / 2 / sizeof(temp[0]) - sizeof(*defaults)))
goto mem_error;
if (defaults->maxAttrs > XML_MAX_ATTRS / 2)
newSize = XML_MAX_ATTRS;
else
newSize = defaults->maxAttrs * 2;
}
temp = xmlRealloc(defaults, temp = xmlRealloc(defaults,
sizeof(*defaults) + newSize * sizeof(xmlDefAttr)); sizeof(*defaults) + newSize * sizeof(xmlDefAttr));
if (temp == NULL) if (temp == NULL)
@ -1670,9 +1685,11 @@ xmlParserNsGrow(xmlParserCtxtPtr ctxt) {
xmlParserNsExtra *extra; xmlParserNsExtra *extra;
int newSize; int newSize;
if (ctxt->nsMax > INT_MAX / 2) newSize = xmlGrowCapacity(ctxt->nsMax,
sizeof(table[0]) + sizeof(extra[0]),
16, XML_MAX_ITEMS);
if (newSize < 0)
goto error; goto error;
newSize = ctxt->nsMax ? ctxt->nsMax * 2 : 16;
table = xmlRealloc(ctxt->nsTab, 2 * newSize * sizeof(table[0])); table = xmlRealloc(ctxt->nsTab, 2 * newSize * sizeof(table[0]));
if (table == NULL) if (table == NULL)
@ -1895,35 +1912,31 @@ static int
xmlCtxtGrowAttrs(xmlParserCtxtPtr ctxt) { xmlCtxtGrowAttrs(xmlParserCtxtPtr ctxt) {
const xmlChar **atts; const xmlChar **atts;
unsigned *attallocs; unsigned *attallocs;
int maxatts = ctxt->maxatts; int newSize;
if (maxatts == 0) { newSize = xmlGrowCapacity(ctxt->maxatts / 5,
maxatts = 50; sizeof(atts[0]) * 5 + sizeof(attallocs[0]),
} else { 10, XML_MAX_ATTRS);
if ((maxatts > INT_MAX / 2 - 5) || if (newSize < 0) {
((size_t) maxatts > SIZE_MAX / 2 / sizeof(const xmlChar *))) xmlFatalErr(ctxt, XML_ERR_RESOURCE_LIMIT,
goto mem_error; "Maximum number of attributes exceeded");
maxatts *= 2; return(-1);
} }
atts = xmlMalloc(maxatts * sizeof(const xmlChar *)); atts = xmlRealloc(ctxt->atts, newSize * sizeof(atts[0]) * 5);
if (atts == NULL) if (atts == NULL)
goto mem_error; goto mem_error;
attallocs = xmlRealloc(ctxt->attallocs,
(maxatts / 5) * sizeof(attallocs[0]));
if (attallocs == NULL) {
xmlFree(atts);
goto mem_error;
}
if (ctxt->maxatts > 0)
memcpy(atts, ctxt->atts, ctxt->maxatts * sizeof(const xmlChar *));
xmlFree(ctxt->atts);
ctxt->atts = atts; ctxt->atts = atts;
ctxt->attallocs = attallocs;
ctxt->maxatts = maxatts;
return(maxatts); attallocs = xmlRealloc(ctxt->attallocs,
newSize * sizeof(attallocs[0]));
if (attallocs == NULL)
goto mem_error;
ctxt->attallocs = attallocs;
ctxt->maxatts = newSize * 5;
return(0);
mem_error: mem_error:
xmlErrMemory(ctxt); xmlErrMemory(ctxt);
@ -1949,19 +1962,20 @@ xmlCtxtPushInput(xmlParserCtxtPtr ctxt, xmlParserInputPtr value)
return(-1); return(-1);
maxDepth = (ctxt->options & XML_PARSE_HUGE) ? 40 : 20; maxDepth = (ctxt->options & XML_PARSE_HUGE) ? 40 : 20;
if (ctxt->inputNr > maxDepth) {
if (ctxt->inputNr >= ctxt->inputMax) {
xmlParserInputPtr *tmp;
int newSize;
newSize = xmlGrowCapacity(ctxt->inputMax, sizeof(tmp[0]),
5, maxDepth);
if (newSize < 0) {
xmlFatalErrMsg(ctxt, XML_ERR_RESOURCE_LIMIT, xmlFatalErrMsg(ctxt, XML_ERR_RESOURCE_LIMIT,
"Maximum entity nesting depth exceeded"); "Maximum entity nesting depth exceeded");
xmlHaltParser(ctxt); xmlHaltParser(ctxt);
return(-1); return(-1);
} }
tmp = xmlRealloc(ctxt->inputTab, newSize * sizeof(tmp[0]));
if (ctxt->inputNr >= ctxt->inputMax) {
size_t newSize = ctxt->inputMax * 2;
xmlParserInputPtr *tmp;
tmp = (xmlParserInputPtr *) xmlRealloc(ctxt->inputTab,
newSize * sizeof(*tmp));
if (tmp == NULL) { if (tmp == NULL) {
xmlErrMemory(ctxt); xmlErrMemory(ctxt);
return(-1); return(-1);
@ -2069,32 +2083,34 @@ inputPop(xmlParserCtxtPtr ctxt)
int int
nodePush(xmlParserCtxtPtr ctxt, xmlNodePtr value) nodePush(xmlParserCtxtPtr ctxt, xmlNodePtr value)
{ {
int maxDepth;
if (ctxt == NULL) if (ctxt == NULL)
return(0); return(0);
maxDepth = (ctxt->options & XML_PARSE_HUGE) ? 2048 : 256; if (ctxt->nodeNr >= ctxt->nodeMax) {
if (ctxt->nodeNr > maxDepth) { int maxDepth = (ctxt->options & XML_PARSE_HUGE) ? 2048 : 256;
xmlNodePtr *tmp;
int newSize;
newSize = xmlGrowCapacity(ctxt->nodeMax, sizeof(tmp[0]),
10, maxDepth);
if (newSize < 0) {
xmlFatalErrMsgInt(ctxt, XML_ERR_RESOURCE_LIMIT, xmlFatalErrMsgInt(ctxt, XML_ERR_RESOURCE_LIMIT,
"Excessive depth in document: %d use XML_PARSE_HUGE option\n", "Excessive depth in document: %d,"
" use XML_PARSE_HUGE option\n",
ctxt->nodeNr); ctxt->nodeNr);
xmlHaltParser(ctxt); xmlHaltParser(ctxt);
return(-1); return(-1);
} }
if (ctxt->nodeNr >= ctxt->nodeMax) {
xmlNodePtr *tmp;
tmp = (xmlNodePtr *) xmlRealloc(ctxt->nodeTab, tmp = xmlRealloc(ctxt->nodeTab, newSize * sizeof(tmp[0]));
ctxt->nodeMax * 2 *
sizeof(ctxt->nodeTab[0]));
if (tmp == NULL) { if (tmp == NULL) {
xmlErrMemory(ctxt); xmlErrMemory(ctxt);
return (-1); return (-1);
} }
ctxt->nodeTab = tmp; ctxt->nodeTab = tmp;
ctxt->nodeMax *= 2; ctxt->nodeMax = newSize;
} }
ctxt->nodeTab[ctxt->nodeNr] = value; ctxt->nodeTab[ctxt->nodeNr] = value;
ctxt->node = value; ctxt->node = value;
return (ctxt->nodeNr++); return (ctxt->nodeNr++);
@ -2150,26 +2166,27 @@ nameNsPush(xmlParserCtxtPtr ctxt, const xmlChar * value,
if (ctxt->nameNr >= ctxt->nameMax) { if (ctxt->nameNr >= ctxt->nameMax) {
const xmlChar **tmp; const xmlChar **tmp;
xmlStartTag *tmp2; xmlStartTag *tmp2;
ctxt->nameMax *= 2; int newSize;
tmp = (const xmlChar * *) xmlRealloc((xmlChar * *)ctxt->nameTab,
ctxt->nameMax * newSize = xmlGrowCapacity(ctxt->nameMax,
sizeof(ctxt->nameTab[0])); sizeof(tmp[0]) + sizeof(tmp2[0]),
if (tmp == NULL) { 10, XML_MAX_ITEMS);
ctxt->nameMax /= 2; if (newSize < 0)
goto mem_error;
tmp = xmlRealloc(ctxt->nameTab, newSize * sizeof(tmp[0]));
if (tmp == NULL)
goto mem_error; goto mem_error;
}
ctxt->nameTab = tmp; ctxt->nameTab = tmp;
tmp2 = (xmlStartTag *) xmlRealloc((void * *)ctxt->pushTab,
ctxt->nameMax * tmp2 = xmlRealloc(ctxt->pushTab, newSize * sizeof(tmp2[0]));
sizeof(ctxt->pushTab[0])); if (tmp2 == NULL)
if (tmp2 == NULL) {
ctxt->nameMax /= 2;
goto mem_error; goto mem_error;
}
ctxt->pushTab = tmp2; ctxt->pushTab = tmp2;
ctxt->nameMax = newSize;
} else if (ctxt->pushTab == NULL) { } else if (ctxt->pushTab == NULL) {
ctxt->pushTab = (xmlStartTag *) xmlMalloc(ctxt->nameMax * ctxt->pushTab = xmlMalloc(ctxt->nameMax * sizeof(ctxt->pushTab[0]));
sizeof(ctxt->pushTab[0]));
if (ctxt->pushTab == NULL) if (ctxt->pushTab == NULL)
goto mem_error; goto mem_error;
} }
@ -2230,14 +2247,19 @@ namePush(xmlParserCtxtPtr ctxt, const xmlChar * value)
if (ctxt->nameNr >= ctxt->nameMax) { if (ctxt->nameNr >= ctxt->nameMax) {
const xmlChar **tmp; const xmlChar **tmp;
tmp = (const xmlChar * *) xmlRealloc((xmlChar * *)ctxt->nameTab, int newSize;
ctxt->nameMax * 2 *
sizeof(ctxt->nameTab[0])); newSize = xmlGrowCapacity(ctxt->nameMax, sizeof(tmp[0]),
if (tmp == NULL) { 10, XML_MAX_ITEMS);
if (newSize < 0)
goto mem_error;
tmp = xmlRealloc(ctxt->nameTab, newSize * sizeof(tmp[0]));
if (tmp == NULL)
goto mem_error; goto mem_error;
}
ctxt->nameTab = tmp; ctxt->nameTab = tmp;
ctxt->nameMax *= 2;
ctxt->nameMax = newSize;
} }
ctxt->nameTab[ctxt->nameNr] = value; ctxt->nameTab[ctxt->nameNr] = value;
ctxt->name = value; ctxt->name = value;
@ -2277,16 +2299,23 @@ namePop(xmlParserCtxtPtr ctxt)
static int spacePush(xmlParserCtxtPtr ctxt, int val) { static int spacePush(xmlParserCtxtPtr ctxt, int val) {
if (ctxt->spaceNr >= ctxt->spaceMax) { if (ctxt->spaceNr >= ctxt->spaceMax) {
int *tmp; int *tmp;
int newSize;
ctxt->spaceMax *= 2; newSize = xmlGrowCapacity(ctxt->spaceMax, sizeof(tmp[0]),
tmp = (int *) xmlRealloc(ctxt->spaceTab, 10, XML_MAX_ITEMS);
ctxt->spaceMax * sizeof(ctxt->spaceTab[0])); if (newSize < 0) {
xmlErrMemory(ctxt);
return(-1);
}
tmp = xmlRealloc(ctxt->spaceTab, newSize * sizeof(tmp[0]));
if (tmp == NULL) { if (tmp == NULL) {
xmlErrMemory(ctxt); xmlErrMemory(ctxt);
ctxt->spaceMax /=2;
return(-1); return(-1);
} }
ctxt->spaceTab = tmp; ctxt->spaceTab = tmp;
ctxt->spaceMax = newSize;
} }
ctxt->spaceTab[ctxt->spaceNr] = val; ctxt->spaceTab[ctxt->spaceNr] = val;
ctxt->space = &ctxt->spaceTab[ctxt->spaceNr]; ctxt->space = &ctxt->spaceTab[ctxt->spaceNr];
@ -3083,15 +3112,22 @@ xmlSplitQName(xmlParserCtxtPtr ctxt, const xmlChar *name, xmlChar **prefixOut) {
while ((c != 0) && (c != ':')) { /* tested bigname.xml */ while ((c != 0) && (c != ':')) { /* tested bigname.xml */
if (len + 10 > max) { if (len + 10 > max) {
xmlChar *tmp; xmlChar *tmp;
int newSize;
max *= 2; newSize = xmlGrowCapacity(max, 1, 1, XML_MAX_ITEMS);
tmp = (xmlChar *) xmlRealloc(buffer, max); if (newSize < 0) {
if (tmp == NULL) {
xmlFree(buffer);
xmlErrMemory(ctxt); xmlErrMemory(ctxt);
xmlFree(buffer);
return(NULL);
}
tmp = xmlRealloc(buffer, newSize);
if (tmp == NULL) {
xmlErrMemory(ctxt);
xmlFree(buffer);
return(NULL); return(NULL);
} }
buffer = tmp; buffer = tmp;
max = newSize;
} }
buffer[len++] = c; buffer[len++] = c;
c = *cur++; c = *cur++;
@ -3171,9 +3207,15 @@ xmlSplitQName(xmlParserCtxtPtr ctxt, const xmlChar *name, xmlChar **prefixOut) {
while (c != 0) { /* tested bigname2.xml */ while (c != 0) { /* tested bigname2.xml */
if (len + 10 > max) { if (len + 10 > max) {
xmlChar *tmp; xmlChar *tmp;
int newSize;
max *= 2; newSize = xmlGrowCapacity(max, 1, 1, XML_MAX_ITEMS);
tmp = (xmlChar *) xmlRealloc(buffer, max); if (newSize < 0) {
xmlErrMemory(ctxt);
xmlFree(buffer);
return(NULL);
}
tmp = xmlRealloc(buffer, newSize);
if (tmp == NULL) { if (tmp == NULL) {
xmlErrMemory(ctxt); xmlErrMemory(ctxt);
xmlFree(prefix); xmlFree(prefix);
@ -3181,6 +3223,7 @@ xmlSplitQName(xmlParserCtxtPtr ctxt, const xmlChar *name, xmlChar **prefixOut) {
return(NULL); return(NULL);
} }
buffer = tmp; buffer = tmp;
max = newSize;
} }
buffer[len++] = c; buffer[len++] = c;
c = *cur++; c = *cur++;
@ -3667,24 +3710,26 @@ xmlParseStringName(xmlParserCtxtPtr ctxt, const xmlChar** str) {
while (xmlIsNameChar(ctxt, c)) { while (xmlIsNameChar(ctxt, c)) {
if (len + 10 > max) { if (len + 10 > max) {
xmlChar *tmp; xmlChar *tmp;
int newSize;
max *= 2; newSize = xmlGrowCapacity(max, 1, 1, maxLength);
tmp = (xmlChar *) xmlRealloc(buffer, max); if (newSize < 0) {
xmlFatalErr(ctxt, XML_ERR_NAME_TOO_LONG, "NCName");
xmlFree(buffer);
return(NULL);
}
tmp = xmlRealloc(buffer, newSize);
if (tmp == NULL) { if (tmp == NULL) {
xmlErrMemory(ctxt); xmlErrMemory(ctxt);
xmlFree(buffer); xmlFree(buffer);
return(NULL); return(NULL);
} }
buffer = tmp; buffer = tmp;
max = newSize;
} }
COPY_BUF(buffer, len, c); COPY_BUF(buffer, len, c);
cur += l; cur += l;
c = CUR_SCHAR(cur, l); c = CUR_SCHAR(cur, l);
if (len > maxLength) {
xmlFatalErr(ctxt, XML_ERR_NAME_TOO_LONG, "NCName");
xmlFree(buffer);
return(NULL);
}
} }
buffer[len] = 0; buffer[len] = 0;
*str = cur; *str = cur;
@ -3750,22 +3795,24 @@ xmlParseNmtoken(xmlParserCtxtPtr ctxt) {
while (xmlIsNameChar(ctxt, c)) { while (xmlIsNameChar(ctxt, c)) {
if (len + 10 > max) { if (len + 10 > max) {
xmlChar *tmp; xmlChar *tmp;
int newSize;
max *= 2; newSize = xmlGrowCapacity(max, 1, 1, maxLength);
tmp = (xmlChar *) xmlRealloc(buffer, max); if (newSize < 0) {
xmlFatalErr(ctxt, XML_ERR_NAME_TOO_LONG, "NmToken");
xmlFree(buffer);
return(NULL);
}
tmp = xmlRealloc(buffer, newSize);
if (tmp == NULL) { if (tmp == NULL) {
xmlErrMemory(ctxt); xmlErrMemory(ctxt);
xmlFree(buffer); xmlFree(buffer);
return(NULL); return(NULL);
} }
buffer = tmp; buffer = tmp;
max = newSize;
} }
COPY_BUF(buffer, len, c); COPY_BUF(buffer, len, c);
if (len > maxLength) {
xmlFatalErr(ctxt, XML_ERR_NAME_TOO_LONG, "NmToken");
xmlFree(buffer);
return(NULL);
}
NEXTL(l); NEXTL(l);
c = xmlCurrentChar(ctxt, &l); c = xmlCurrentChar(ctxt, &l);
} }
@ -4669,22 +4716,24 @@ xmlParseSystemLiteral(xmlParserCtxtPtr ctxt) {
while ((IS_CHAR(cur)) && (cur != stop)) { /* checked */ while ((IS_CHAR(cur)) && (cur != stop)) { /* checked */
if (len + 5 >= size) { if (len + 5 >= size) {
xmlChar *tmp; xmlChar *tmp;
int newSize;
size *= 2; newSize = xmlGrowCapacity(size, 1, 1, maxLength);
tmp = (xmlChar *) xmlRealloc(buf, size); if (newSize < 0) {
xmlFatalErr(ctxt, XML_ERR_NAME_TOO_LONG, "SystemLiteral");
xmlFree(buf);
return(NULL);
}
tmp = xmlRealloc(buf, newSize);
if (tmp == NULL) { if (tmp == NULL) {
xmlFree(buf); xmlFree(buf);
xmlErrMemory(ctxt); xmlErrMemory(ctxt);
return(NULL); return(NULL);
} }
buf = tmp; buf = tmp;
size = newSize;
} }
COPY_BUF(buf, len, cur); COPY_BUF(buf, len, cur);
if (len > maxLength) {
xmlFatalErr(ctxt, XML_ERR_NAME_TOO_LONG, "SystemLiteral");
xmlFree(buf);
return(NULL);
}
NEXTL(l); NEXTL(l);
cur = xmlCurrentCharRecover(ctxt, &l); cur = xmlCurrentCharRecover(ctxt, &l);
} }
@ -4741,22 +4790,24 @@ xmlParsePubidLiteral(xmlParserCtxtPtr ctxt) {
(PARSER_STOPPED(ctxt) == 0)) { /* checked */ (PARSER_STOPPED(ctxt) == 0)) { /* checked */
if (len + 1 >= size) { if (len + 1 >= size) {
xmlChar *tmp; xmlChar *tmp;
int newSize;
size *= 2; newSize = xmlGrowCapacity(size, 1, 1, maxLength);
tmp = (xmlChar *) xmlRealloc(buf, size); if (newSize) {
xmlFatalErr(ctxt, XML_ERR_NAME_TOO_LONG, "Public ID");
xmlFree(buf);
return(NULL);
}
tmp = xmlRealloc(buf, size);
if (tmp == NULL) { if (tmp == NULL) {
xmlErrMemory(ctxt); xmlErrMemory(ctxt);
xmlFree(buf); xmlFree(buf);
return(NULL); return(NULL);
} }
buf = tmp; buf = tmp;
size = newSize;
} }
buf[len++] = cur; buf[len++] = cur;
if (len > maxLength) {
xmlFatalErr(ctxt, XML_ERR_NAME_TOO_LONG, "Public ID");
xmlFree(buf);
return(NULL);
}
NEXT; NEXT;
cur = CUR; cur = CUR;
} }
@ -5162,7 +5213,7 @@ xmlParseCommentComplex(xmlParserCtxtPtr ctxt, xmlChar *buf,
int q, ql; int q, ql;
int r, rl; int r, rl;
int cur, l; int cur, l;
size_t maxLength = (ctxt->options & XML_PARSE_HUGE) ? int maxLength = (ctxt->options & XML_PARSE_HUGE) ?
XML_MAX_HUGE_LENGTH : XML_MAX_HUGE_LENGTH :
XML_MAX_TEXT_LENGTH; XML_MAX_TEXT_LENGTH;
@ -5207,26 +5258,26 @@ xmlParseCommentComplex(xmlParserCtxtPtr ctxt, xmlChar *buf,
xmlFatalErr(ctxt, XML_ERR_HYPHEN_IN_COMMENT, NULL); xmlFatalErr(ctxt, XML_ERR_HYPHEN_IN_COMMENT, NULL);
} }
if (len + 5 >= size) { if (len + 5 >= size) {
xmlChar *new_buf; xmlChar *tmp;
size_t new_size; int newSize;
new_size = size * 2; newSize = xmlGrowCapacity(size, 1, 1, maxLength);
new_buf = (xmlChar *) xmlRealloc(buf, new_size); if (newSize < 0) {
if (new_buf == NULL) {
xmlFree (buf);
xmlErrMemory(ctxt);
return;
}
buf = new_buf;
size = new_size;
}
COPY_BUF(buf, len, q);
if (len > maxLength) {
xmlFatalErrMsgStr(ctxt, XML_ERR_COMMENT_NOT_FINISHED, xmlFatalErrMsgStr(ctxt, XML_ERR_COMMENT_NOT_FINISHED,
"Comment too big found", NULL); "Comment too big found", NULL);
xmlFree (buf); xmlFree (buf);
return; return;
} }
tmp = xmlRealloc(buf, newSize);
if (tmp == NULL) {
xmlErrMemory(ctxt);
xmlFree(buf);
return;
}
buf = tmp;
size = newSize;
}
COPY_BUF(buf, len, q);
q = r; q = r;
ql = rl; ql = rl;
@ -5328,6 +5379,12 @@ get_more:
* save current set of data * save current set of data
*/ */
if (nbchar > 0) { if (nbchar > 0) {
if (nbchar > maxLength - len) {
xmlFatalErrMsgStr(ctxt, XML_ERR_COMMENT_NOT_FINISHED,
"Comment too big found", NULL);
xmlFree(buf);
return;
}
if (buf == NULL) { if (buf == NULL) {
if ((*in == '-') && (in[1] == '-')) if ((*in == '-') && (in[1] == '-'))
size = nbchar + 1; size = nbchar + 1;
@ -5342,10 +5399,10 @@ get_more:
} else if (len + nbchar + 1 >= size) { } else if (len + nbchar + 1 >= size) {
xmlChar *new_buf; xmlChar *new_buf;
size += len + nbchar + XML_PARSER_BUFFER_SIZE; size += len + nbchar + XML_PARSER_BUFFER_SIZE;
new_buf = (xmlChar *) xmlRealloc(buf, size); new_buf = xmlRealloc(buf, size);
if (new_buf == NULL) { if (new_buf == NULL) {
xmlFree (buf);
xmlErrMemory(ctxt); xmlErrMemory(ctxt);
xmlFree(buf);
return; return;
} }
buf = new_buf; buf = new_buf;
@ -5354,12 +5411,6 @@ get_more:
len += nbchar; len += nbchar;
buf[len] = 0; buf[len] = 0;
} }
if (len > maxLength) {
xmlFatalErrMsgStr(ctxt, XML_ERR_COMMENT_NOT_FINISHED,
"Comment too big found", NULL);
xmlFree (buf);
return;
}
ctxt->input->cur = in; ctxt->input->cur = in;
if (*in == 0xA) { if (*in == 0xA) {
in++; in++;
@ -5591,23 +5642,25 @@ xmlParsePI(xmlParserCtxtPtr ctxt) {
((cur != '?') || (NXT(1) != '>'))) { ((cur != '?') || (NXT(1) != '>'))) {
if (len + 5 >= size) { if (len + 5 >= size) {
xmlChar *tmp; xmlChar *tmp;
size_t new_size = size * 2; int newSize;
tmp = (xmlChar *) xmlRealloc(buf, new_size);
newSize = xmlGrowCapacity(size, 1, 1, maxLength);
if (newSize < 0) {
xmlFatalErrMsgStr(ctxt, XML_ERR_PI_NOT_FINISHED,
"PI %s too big found", target);
xmlFree(buf);
return;
}
tmp = xmlRealloc(buf, newSize);
if (tmp == NULL) { if (tmp == NULL) {
xmlErrMemory(ctxt); xmlErrMemory(ctxt);
xmlFree(buf); xmlFree(buf);
return; return;
} }
buf = tmp; buf = tmp;
size = new_size; size = newSize;
} }
COPY_BUF(buf, len, cur); COPY_BUF(buf, len, cur);
if (len > maxLength) {
xmlFatalErrMsgStr(ctxt, XML_ERR_PI_NOT_FINISHED,
"PI %s too big found", target);
xmlFree(buf);
return;
}
NEXTL(l); NEXTL(l);
cur = xmlCurrentCharRecover(ctxt, &l); cur = xmlCurrentCharRecover(ctxt, &l);
} }
@ -7065,15 +7118,23 @@ xmlParseConditionalSections(xmlParserCtxtPtr ctxt) {
if (inputIdsSize <= depth) { if (inputIdsSize <= depth) {
int *tmp; int *tmp;
int newSize;
inputIdsSize = (inputIdsSize == 0 ? 4 : inputIdsSize * 2); newSize = xmlGrowCapacity(inputIdsSize, sizeof(tmp[0]),
tmp = (int *) xmlRealloc(inputIds, 4, 1000);
inputIdsSize * sizeof(int)); if (newSize < 0) {
xmlFatalErrMsg(ctxt, XML_ERR_RESOURCE_LIMIT,
"Maximum conditional section nesting"
" depth exceeded\n");
goto error;
}
tmp = xmlRealloc(inputIds, newSize * sizeof(tmp[0]));
if (tmp == NULL) { if (tmp == NULL) {
xmlErrMemory(ctxt); xmlErrMemory(ctxt);
goto error; goto error;
} }
inputIds = tmp; inputIds = tmp;
inputIdsSize = newSize;
} }
inputIds[depth] = id; inputIds[depth] = id;
depth++; depth++;
@ -8499,52 +8560,50 @@ xmlParseStartTag(xmlParserCtxtPtr ctxt) {
for (i = 0; i < nbatts;i += 2) { for (i = 0; i < nbatts;i += 2) {
if (xmlStrEqual(atts[i], attname)) { if (xmlStrEqual(atts[i], attname)) {
xmlErrAttributeDup(ctxt, NULL, attname); xmlErrAttributeDup(ctxt, NULL, attname);
xmlFree(attvalue);
goto failed; goto failed;
} }
} }
/* /*
* Add the pair to atts * Add the pair to atts
*/ */
if (atts == NULL) { if (nbatts + 4 > maxatts) {
maxatts = 22; /* allow for 10 attrs by default */ const xmlChar **n;
atts = (const xmlChar **) int newSize;
xmlMalloc(maxatts * sizeof(xmlChar *));
if (atts == NULL) { newSize = xmlGrowCapacity(maxatts, sizeof(n[0]) * 2,
11, XML_MAX_ATTRS);
if (newSize < 0) {
xmlErrMemory(ctxt); xmlErrMemory(ctxt);
if (attvalue != NULL)
xmlFree(attvalue);
goto failed; goto failed;
} }
ctxt->atts = atts; #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
ctxt->maxatts = maxatts; if (newSize < 2)
} else if (nbatts + 4 > maxatts) { newSize = 2;
const xmlChar **n; #endif
n = xmlRealloc(atts, newSize * sizeof(n[0]) * 2);
maxatts *= 2;
n = (const xmlChar **) xmlRealloc((void *) atts,
maxatts * sizeof(const xmlChar *));
if (n == NULL) { if (n == NULL) {
xmlErrMemory(ctxt); xmlErrMemory(ctxt);
if (attvalue != NULL)
xmlFree(attvalue);
goto failed; goto failed;
} }
atts = n; atts = n;
maxatts = newSize * 2;
ctxt->atts = atts; ctxt->atts = atts;
ctxt->maxatts = maxatts; ctxt->maxatts = maxatts;
} }
atts[nbatts++] = attname; atts[nbatts++] = attname;
atts[nbatts++] = attvalue; atts[nbatts++] = attvalue;
atts[nbatts] = NULL; atts[nbatts] = NULL;
atts[nbatts + 1] = NULL; atts[nbatts + 1] = NULL;
} else {
if (attvalue != NULL) attvalue = NULL;
xmlFree(attvalue);
} }
failed: failed:
if (attvalue != NULL)
xmlFree(attvalue);
GROW GROW
if ((RAW == '>') || (((RAW == '/') && (NXT(1) == '>')))) if ((RAW == '>') || (((RAW == '/') && (NXT(1) == '>'))))
break; break;
@ -9250,11 +9309,13 @@ xmlParseStartTag2(xmlParserCtxtPtr ctxt, const xmlChar **pref,
* of xmlChar pointers. * of xmlChar pointers.
*/ */
if ((atts == NULL) || (nbatts + 5 > maxatts)) { if ((atts == NULL) || (nbatts + 5 > maxatts)) {
if (xmlCtxtGrowAttrs(ctxt) < 0) { int res = xmlCtxtGrowAttrs(ctxt);
goto next_attr;
}
maxatts = ctxt->maxatts; maxatts = ctxt->maxatts;
atts = ctxt->atts; atts = ctxt->atts;
if (res < 0)
goto next_attr;
} }
ctxt->attallocs[nratts++] = (hattname.hashValue & 0x7FFFFFFF) | ctxt->attallocs[nratts++] = (hattname.hashValue & 0x7FFFFFFF) |
((unsigned) alloc << 31); ((unsigned) alloc << 31);
@ -9325,6 +9386,11 @@ next_attr:
NULL, 1) > 0) NULL, 1) > 0)
nbNs++; nbNs++;
} else { } else {
if (nratts + nbTotalDef >= XML_MAX_ATTRS) {
xmlFatalErr(ctxt, XML_ERR_RESOURCE_LIMIT,
"Maximum number of attributes exceeded");
break;
}
nbTotalDef += 1; nbTotalDef += 1;
} }
} }
@ -9512,12 +9578,15 @@ next_attr:
xmlParserEntityCheck(ctxt, attr->expandedSize); xmlParserEntityCheck(ctxt, attr->expandedSize);
if ((atts == NULL) || (nbatts + 5 > maxatts)) { if ((atts == NULL) || (nbatts + 5 > maxatts)) {
if (xmlCtxtGrowAttrs(ctxt) < 0) { res = xmlCtxtGrowAttrs(ctxt);
maxatts = ctxt->maxatts;
atts = ctxt->atts;
if (res < 0) {
localname = NULL; localname = NULL;
goto done; goto done;
} }
maxatts = ctxt->maxatts;
atts = ctxt->atts;
} }
atts[nbatts++] = attname; atts[nbatts++] = attname;
@ -9754,21 +9823,23 @@ xmlParseCDSect(xmlParserCtxtPtr ctxt) {
((r != ']') || (s != ']') || (cur != '>'))) { ((r != ']') || (s != ']') || (cur != '>'))) {
if (len + 5 >= size) { if (len + 5 >= size) {
xmlChar *tmp; xmlChar *tmp;
int newSize;
tmp = (xmlChar *) xmlRealloc(buf, size * 2); newSize = xmlGrowCapacity(size, 1, 1, maxLength);
if (newSize < 0) {
xmlFatalErrMsg(ctxt, XML_ERR_CDATA_NOT_FINISHED,
"CData section too big found\n");
goto out;
}
tmp = xmlRealloc(buf, newSize);
if (tmp == NULL) { if (tmp == NULL) {
xmlErrMemory(ctxt); xmlErrMemory(ctxt);
goto out; goto out;
} }
buf = tmp; buf = tmp;
size *= 2; size = newSize;
} }
COPY_BUF(buf, len, r); COPY_BUF(buf, len, r);
if (len > maxLength) {
xmlFatalErrMsg(ctxt, XML_ERR_CDATA_NOT_FINISHED,
"CData section too big found\n");
goto out;
}
r = s; r = s;
rl = sl; rl = sl;
s = cur; s = cur;
@ -10148,6 +10219,9 @@ xmlParseVersionNum(xmlParserCtxtPtr ctxt) {
xmlChar *buf = NULL; xmlChar *buf = NULL;
int len = 0; int len = 0;
int size = 10; int size = 10;
int maxLength = (ctxt->options & XML_PARSE_HUGE) ?
XML_MAX_TEXT_LENGTH :
XML_MAX_NAME_LENGTH;
xmlChar cur; xmlChar cur;
buf = xmlMalloc(size); buf = xmlMalloc(size);
@ -10173,15 +10247,22 @@ xmlParseVersionNum(xmlParserCtxtPtr ctxt) {
while ((cur >= '0') && (cur <= '9')) { while ((cur >= '0') && (cur <= '9')) {
if (len + 1 >= size) { if (len + 1 >= size) {
xmlChar *tmp; xmlChar *tmp;
int newSize;
size *= 2; newSize = xmlGrowCapacity(size, 1, 1, maxLength);
tmp = (xmlChar *) xmlRealloc(buf, size); if (newSize) {
if (tmp == NULL) { xmlFatalErr(ctxt, XML_ERR_NAME_TOO_LONG, "VersionNum");
xmlFree(buf); xmlFree(buf);
return(NULL);
}
tmp = xmlRealloc(buf, newSize);
if (tmp == NULL) {
xmlErrMemory(ctxt); xmlErrMemory(ctxt);
xmlFree(buf);
return(NULL); return(NULL);
} }
buf = tmp; buf = tmp;
size = newSize;
} }
buf[len++] = cur; buf[len++] = cur;
NEXT; NEXT;
@ -10281,22 +10362,24 @@ xmlParseEncName(xmlParserCtxtPtr ctxt) {
(cur == '-')) { (cur == '-')) {
if (len + 1 >= size) { if (len + 1 >= size) {
xmlChar *tmp; xmlChar *tmp;
int newSize;
size *= 2; newSize = xmlGrowCapacity(size, 1, 1, maxLength);
tmp = (xmlChar *) xmlRealloc(buf, size); if (newSize < 0) {
xmlFatalErr(ctxt, XML_ERR_NAME_TOO_LONG, "EncName");
xmlFree(buf);
return(NULL);
}
tmp = xmlRealloc(buf, newSize);
if (tmp == NULL) { if (tmp == NULL) {
xmlErrMemory(ctxt); xmlErrMemory(ctxt);
xmlFree(buf); xmlFree(buf);
return(NULL); return(NULL);
} }
buf = tmp; buf = tmp;
size = newSize;
} }
buf[len++] = cur; buf[len++] = cur;
if (len > maxLength) {
xmlFatalErr(ctxt, XML_ERR_NAME_TOO_LONG, "EncName");
xmlFree(buf);
return(NULL);
}
NEXT; NEXT;
cur = CUR; cur = CUR;
} }

View File

@ -44,6 +44,7 @@
#include "private/enc.h" #include "private/enc.h"
#include "private/error.h" #include "private/error.h"
#include "private/io.h" #include "private/io.h"
#include "private/memory.h"
#include "private/parser.h" #include "private/parser.h"
#define XML_MAX_ERRORS 100 #define XML_MAX_ERRORS 100
@ -3274,29 +3275,23 @@ xmlParserAddNodeInfo(xmlParserCtxtPtr ctxt,
/* Otherwise, we need to add new node to buffer */ /* Otherwise, we need to add new node to buffer */
else { else {
if ((ctxt->node_seq.length + 1 > ctxt->node_seq.maximum) || if (ctxt->node_seq.length + 1 > ctxt->node_seq.maximum) {
(ctxt->node_seq.buffer == NULL)) { xmlParserNodeInfo *tmp;
xmlParserNodeInfo *tmp_buffer; int newSize;
unsigned int byte_size;
if (ctxt->node_seq.maximum == 0) newSize = xmlGrowCapacity(ctxt->node_seq.maximum, sizeof(tmp[0]),
ctxt->node_seq.maximum = 2; 4, XML_MAX_ITEMS);
byte_size = (sizeof(*ctxt->node_seq.buffer) * if (newSize < 0) {
(2 * ctxt->node_seq.maximum));
if (ctxt->node_seq.buffer == NULL)
tmp_buffer = (xmlParserNodeInfo *) xmlMalloc(byte_size);
else
tmp_buffer =
(xmlParserNodeInfo *) xmlRealloc(ctxt->node_seq.buffer,
byte_size);
if (tmp_buffer == NULL) {
xmlCtxtErrMemory(ctxt); xmlCtxtErrMemory(ctxt);
return; return;
} }
ctxt->node_seq.buffer = tmp_buffer; tmp = xmlRealloc(ctxt->node_seq.buffer, newSize * sizeof(tmp[0]));
ctxt->node_seq.maximum *= 2; if (tmp == NULL) {
xmlCtxtErrMemory(ctxt);
return;
}
ctxt->node_seq.buffer = tmp;
ctxt->node_seq.maximum = newSize;
} }
/* If position is not at end, move elements out of the way */ /* If position is not at end, move elements out of the way */