|
|
|
@@ -1,4 +1,4 @@
|
|
|
|
|
/* 2e2c8ce5f11a473d65ec313ab20ceee6afefb355f5405afc06e7204e2e41c8c0 (2.4.4+)
|
|
|
|
|
/* 042615face2b8727e23bb27cf4f56baa292a1f91df47c1bca8f09dff49067888 (2.4.5+)
|
|
|
|
|
__ __ _
|
|
|
|
|
___\ \/ /_ __ __ _| |_
|
|
|
|
|
/ _ \\ /| '_ \ / _` | __|
|
|
|
|
@@ -11,9 +11,9 @@
|
|
|
|
|
Copyright (c) 2000-2006 Fred L. Drake, Jr. <fdrake@users.sourceforge.net>
|
|
|
|
|
Copyright (c) 2001-2002 Greg Stein <gstein@users.sourceforge.net>
|
|
|
|
|
Copyright (c) 2002-2016 Karl Waclawek <karl@waclawek.net>
|
|
|
|
|
Copyright (c) 2005-2009 Steven Solie <ssolie@users.sourceforge.net>
|
|
|
|
|
Copyright (c) 2005-2009 Steven Solie <steven@solie.ca>
|
|
|
|
|
Copyright (c) 2016 Eric Rahm <erahm@mozilla.com>
|
|
|
|
|
Copyright (c) 2016-2021 Sebastian Pipping <sebastian@pipping.org>
|
|
|
|
|
Copyright (c) 2016-2022 Sebastian Pipping <sebastian@pipping.org>
|
|
|
|
|
Copyright (c) 2016 Gaurav <g.gupta@samsung.com>
|
|
|
|
|
Copyright (c) 2016 Thomas Beutlich <tc@tbeu.de>
|
|
|
|
|
Copyright (c) 2016 Gustavo Grieco <gustavo.grieco@imag.fr>
|
|
|
|
@@ -727,8 +727,7 @@ XML_ParserCreate(const XML_Char *encodingName) {
|
|
|
|
|
|
|
|
|
|
XML_Parser XMLCALL
|
|
|
|
|
XML_ParserCreateNS(const XML_Char *encodingName, XML_Char nsSep) {
|
|
|
|
|
XML_Char tmp[2];
|
|
|
|
|
*tmp = nsSep;
|
|
|
|
|
XML_Char tmp[2] = {nsSep, 0};
|
|
|
|
|
return XML_ParserCreate_MM(encodingName, NULL, tmp);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -1364,8 +1363,7 @@ XML_ExternalEntityParserCreate(XML_Parser oldParser, const XML_Char *context,
|
|
|
|
|
would be otherwise.
|
|
|
|
|
*/
|
|
|
|
|
if (parser->m_ns) {
|
|
|
|
|
XML_Char tmp[2];
|
|
|
|
|
*tmp = parser->m_namespaceSeparator;
|
|
|
|
|
XML_Char tmp[2] = {parser->m_namespaceSeparator, 0};
|
|
|
|
|
parser = parserCreate(encodingName, &parser->m_mem, tmp, newDtd);
|
|
|
|
|
} else {
|
|
|
|
|
parser = parserCreate(encodingName, &parser->m_mem, NULL, newDtd);
|
|
|
|
@@ -2509,29 +2507,29 @@ XML_GetFeatureList(void) {
|
|
|
|
|
{XML_FEATURE_SIZEOF_XML_LCHAR, XML_L("sizeof(XML_LChar)"),
|
|
|
|
|
sizeof(XML_LChar)},
|
|
|
|
|
#ifdef XML_UNICODE
|
|
|
|
|
{XML_FEATURE_UNICODE, XML_L("XML_UNICODE"), 0},
|
|
|
|
|
{XML_FEATURE_UNICODE, XML_L("XML_UNICODE"), 0},
|
|
|
|
|
#endif
|
|
|
|
|
#ifdef XML_UNICODE_WCHAR_T
|
|
|
|
|
{XML_FEATURE_UNICODE_WCHAR_T, XML_L("XML_UNICODE_WCHAR_T"), 0},
|
|
|
|
|
{XML_FEATURE_UNICODE_WCHAR_T, XML_L("XML_UNICODE_WCHAR_T"), 0},
|
|
|
|
|
#endif
|
|
|
|
|
#ifdef XML_DTD
|
|
|
|
|
{XML_FEATURE_DTD, XML_L("XML_DTD"), 0},
|
|
|
|
|
{XML_FEATURE_DTD, XML_L("XML_DTD"), 0},
|
|
|
|
|
#endif
|
|
|
|
|
#ifdef XML_CONTEXT_BYTES
|
|
|
|
|
{XML_FEATURE_CONTEXT_BYTES, XML_L("XML_CONTEXT_BYTES"),
|
|
|
|
|
XML_CONTEXT_BYTES},
|
|
|
|
|
{XML_FEATURE_CONTEXT_BYTES, XML_L("XML_CONTEXT_BYTES"),
|
|
|
|
|
XML_CONTEXT_BYTES},
|
|
|
|
|
#endif
|
|
|
|
|
#ifdef XML_MIN_SIZE
|
|
|
|
|
{XML_FEATURE_MIN_SIZE, XML_L("XML_MIN_SIZE"), 0},
|
|
|
|
|
{XML_FEATURE_MIN_SIZE, XML_L("XML_MIN_SIZE"), 0},
|
|
|
|
|
#endif
|
|
|
|
|
#ifdef XML_NS
|
|
|
|
|
{XML_FEATURE_NS, XML_L("XML_NS"), 0},
|
|
|
|
|
{XML_FEATURE_NS, XML_L("XML_NS"), 0},
|
|
|
|
|
#endif
|
|
|
|
|
#ifdef XML_LARGE_SIZE
|
|
|
|
|
{XML_FEATURE_LARGE_SIZE, XML_L("XML_LARGE_SIZE"), 0},
|
|
|
|
|
{XML_FEATURE_LARGE_SIZE, XML_L("XML_LARGE_SIZE"), 0},
|
|
|
|
|
#endif
|
|
|
|
|
#ifdef XML_ATTR_INFO
|
|
|
|
|
{XML_FEATURE_ATTR_INFO, XML_L("XML_ATTR_INFO"), 0},
|
|
|
|
|
{XML_FEATURE_ATTR_INFO, XML_L("XML_ATTR_INFO"), 0},
|
|
|
|
|
#endif
|
|
|
|
|
#ifdef XML_DTD
|
|
|
|
|
/* Added in Expat 2.4.0. */
|
|
|
|
@@ -2543,7 +2541,7 @@ XML_GetFeatureList(void) {
|
|
|
|
|
XML_L("XML_BLAP_ACT_THRES"),
|
|
|
|
|
EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEFAULT},
|
|
|
|
|
#endif
|
|
|
|
|
{XML_FEATURE_END, NULL, 0}};
|
|
|
|
|
{XML_FEATURE_END, NULL, 0}};
|
|
|
|
|
|
|
|
|
|
return features;
|
|
|
|
|
}
|
|
|
|
@@ -2583,6 +2581,7 @@ storeRawNames(XML_Parser parser) {
|
|
|
|
|
while (tag) {
|
|
|
|
|
int bufSize;
|
|
|
|
|
int nameLen = sizeof(XML_Char) * (tag->name.strLen + 1);
|
|
|
|
|
size_t rawNameLen;
|
|
|
|
|
char *rawNameBuf = tag->buf + nameLen;
|
|
|
|
|
/* Stop if already stored. Since m_tagStack is a stack, we can stop
|
|
|
|
|
at the first entry that has already been copied; everything
|
|
|
|
@@ -2594,7 +2593,11 @@ storeRawNames(XML_Parser parser) {
|
|
|
|
|
/* For re-use purposes we need to ensure that the
|
|
|
|
|
size of tag->buf is a multiple of sizeof(XML_Char).
|
|
|
|
|
*/
|
|
|
|
|
bufSize = nameLen + ROUND_UP(tag->rawNameLength, sizeof(XML_Char));
|
|
|
|
|
rawNameLen = ROUND_UP(tag->rawNameLength, sizeof(XML_Char));
|
|
|
|
|
/* Detect and prevent integer overflow. */
|
|
|
|
|
if (rawNameLen > (size_t)INT_MAX - nameLen)
|
|
|
|
|
return XML_FALSE;
|
|
|
|
|
bufSize = nameLen + (int)rawNameLen;
|
|
|
|
|
if (bufSize > tag->bufEnd - tag->buf) {
|
|
|
|
|
char *temp = (char *)REALLOC(parser, tag->buf, bufSize);
|
|
|
|
|
if (temp == NULL)
|
|
|
|
@@ -3287,13 +3290,38 @@ storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr,
|
|
|
|
|
|
|
|
|
|
/* get the attributes from the tokenizer */
|
|
|
|
|
n = XmlGetAttributes(enc, attStr, parser->m_attsSize, parser->m_atts);
|
|
|
|
|
|
|
|
|
|
/* Detect and prevent integer overflow */
|
|
|
|
|
if (n > INT_MAX - nDefaultAtts) {
|
|
|
|
|
return XML_ERROR_NO_MEMORY;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (n + nDefaultAtts > parser->m_attsSize) {
|
|
|
|
|
int oldAttsSize = parser->m_attsSize;
|
|
|
|
|
ATTRIBUTE *temp;
|
|
|
|
|
#ifdef XML_ATTR_INFO
|
|
|
|
|
XML_AttrInfo *temp2;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/* Detect and prevent integer overflow */
|
|
|
|
|
if ((nDefaultAtts > INT_MAX - INIT_ATTS_SIZE)
|
|
|
|
|
|| (n > INT_MAX - (nDefaultAtts + INIT_ATTS_SIZE))) {
|
|
|
|
|
return XML_ERROR_NO_MEMORY;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
parser->m_attsSize = n + nDefaultAtts + INIT_ATTS_SIZE;
|
|
|
|
|
|
|
|
|
|
/* Detect and prevent integer overflow.
|
|
|
|
|
* The preprocessor guard addresses the "always false" warning
|
|
|
|
|
* from -Wtype-limits on platforms where
|
|
|
|
|
* sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */
|
|
|
|
|
#if UINT_MAX >= SIZE_MAX
|
|
|
|
|
if ((unsigned)parser->m_attsSize > (size_t)(-1) / sizeof(ATTRIBUTE)) {
|
|
|
|
|
parser->m_attsSize = oldAttsSize;
|
|
|
|
|
return XML_ERROR_NO_MEMORY;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
temp = (ATTRIBUTE *)REALLOC(parser, (void *)parser->m_atts,
|
|
|
|
|
parser->m_attsSize * sizeof(ATTRIBUTE));
|
|
|
|
|
if (temp == NULL) {
|
|
|
|
@@ -3302,6 +3330,17 @@ storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr,
|
|
|
|
|
}
|
|
|
|
|
parser->m_atts = temp;
|
|
|
|
|
#ifdef XML_ATTR_INFO
|
|
|
|
|
/* Detect and prevent integer overflow.
|
|
|
|
|
* The preprocessor guard addresses the "always false" warning
|
|
|
|
|
* from -Wtype-limits on platforms where
|
|
|
|
|
* sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */
|
|
|
|
|
# if UINT_MAX >= SIZE_MAX
|
|
|
|
|
if ((unsigned)parser->m_attsSize > (size_t)(-1) / sizeof(XML_AttrInfo)) {
|
|
|
|
|
parser->m_attsSize = oldAttsSize;
|
|
|
|
|
return XML_ERROR_NO_MEMORY;
|
|
|
|
|
}
|
|
|
|
|
# endif
|
|
|
|
|
|
|
|
|
|
temp2 = (XML_AttrInfo *)REALLOC(parser, (void *)parser->m_attInfo,
|
|
|
|
|
parser->m_attsSize * sizeof(XML_AttrInfo));
|
|
|
|
|
if (temp2 == NULL) {
|
|
|
|
@@ -3440,7 +3479,13 @@ storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr,
|
|
|
|
|
if (nPrefixes) {
|
|
|
|
|
int j; /* hash table index */
|
|
|
|
|
unsigned long version = parser->m_nsAttsVersion;
|
|
|
|
|
int nsAttsSize = (int)1 << parser->m_nsAttsPower;
|
|
|
|
|
|
|
|
|
|
/* Detect and prevent invalid shift */
|
|
|
|
|
if (parser->m_nsAttsPower >= sizeof(unsigned int) * 8 /* bits per byte */) {
|
|
|
|
|
return XML_ERROR_NO_MEMORY;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
unsigned int nsAttsSize = 1u << parser->m_nsAttsPower;
|
|
|
|
|
unsigned char oldNsAttsPower = parser->m_nsAttsPower;
|
|
|
|
|
/* size of hash table must be at least 2 * (# of prefixed attributes) */
|
|
|
|
|
if ((nPrefixes << 1)
|
|
|
|
@@ -3451,7 +3496,28 @@ storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr,
|
|
|
|
|
;
|
|
|
|
|
if (parser->m_nsAttsPower < 3)
|
|
|
|
|
parser->m_nsAttsPower = 3;
|
|
|
|
|
nsAttsSize = (int)1 << parser->m_nsAttsPower;
|
|
|
|
|
|
|
|
|
|
/* Detect and prevent invalid shift */
|
|
|
|
|
if (parser->m_nsAttsPower >= sizeof(nsAttsSize) * 8 /* bits per byte */) {
|
|
|
|
|
/* Restore actual size of memory in m_nsAtts */
|
|
|
|
|
parser->m_nsAttsPower = oldNsAttsPower;
|
|
|
|
|
return XML_ERROR_NO_MEMORY;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nsAttsSize = 1u << parser->m_nsAttsPower;
|
|
|
|
|
|
|
|
|
|
/* Detect and prevent integer overflow.
|
|
|
|
|
* The preprocessor guard addresses the "always false" warning
|
|
|
|
|
* from -Wtype-limits on platforms where
|
|
|
|
|
* sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */
|
|
|
|
|
#if UINT_MAX >= SIZE_MAX
|
|
|
|
|
if (nsAttsSize > (size_t)(-1) / sizeof(NS_ATT)) {
|
|
|
|
|
/* Restore actual size of memory in m_nsAtts */
|
|
|
|
|
parser->m_nsAttsPower = oldNsAttsPower;
|
|
|
|
|
return XML_ERROR_NO_MEMORY;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
temp = (NS_ATT *)REALLOC(parser, parser->m_nsAtts,
|
|
|
|
|
nsAttsSize * sizeof(NS_ATT));
|
|
|
|
|
if (! temp) {
|
|
|
|
@@ -3609,9 +3675,31 @@ storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr,
|
|
|
|
|
tagNamePtr->prefixLen = prefixLen;
|
|
|
|
|
for (i = 0; localPart[i++];)
|
|
|
|
|
; /* i includes null terminator */
|
|
|
|
|
|
|
|
|
|
/* Detect and prevent integer overflow */
|
|
|
|
|
if (binding->uriLen > INT_MAX - prefixLen
|
|
|
|
|
|| i > INT_MAX - (binding->uriLen + prefixLen)) {
|
|
|
|
|
return XML_ERROR_NO_MEMORY;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
n = i + binding->uriLen + prefixLen;
|
|
|
|
|
if (n > binding->uriAlloc) {
|
|
|
|
|
TAG *p;
|
|
|
|
|
|
|
|
|
|
/* Detect and prevent integer overflow */
|
|
|
|
|
if (n > INT_MAX - EXPAND_SPARE) {
|
|
|
|
|
return XML_ERROR_NO_MEMORY;
|
|
|
|
|
}
|
|
|
|
|
/* Detect and prevent integer overflow.
|
|
|
|
|
* The preprocessor guard addresses the "always false" warning
|
|
|
|
|
* from -Wtype-limits on platforms where
|
|
|
|
|
* sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */
|
|
|
|
|
#if UINT_MAX >= SIZE_MAX
|
|
|
|
|
if ((unsigned)(n + EXPAND_SPARE) > (size_t)(-1) / sizeof(XML_Char)) {
|
|
|
|
|
return XML_ERROR_NO_MEMORY;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
uri = (XML_Char *)MALLOC(parser, (n + EXPAND_SPARE) * sizeof(XML_Char));
|
|
|
|
|
if (! uri)
|
|
|
|
|
return XML_ERROR_NO_MEMORY;
|
|
|
|
@@ -3691,6 +3779,17 @@ addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId,
|
|
|
|
|
if (! mustBeXML && isXMLNS
|
|
|
|
|
&& (len > xmlnsLen || uri[len] != xmlnsNamespace[len]))
|
|
|
|
|
isXMLNS = XML_FALSE;
|
|
|
|
|
|
|
|
|
|
// NOTE: While Expat does not validate namespace URIs against RFC 3986,
|
|
|
|
|
// we have to at least make sure that the XML processor on top of
|
|
|
|
|
// Expat (that is splitting tag names by namespace separator into
|
|
|
|
|
// 2- or 3-tuples (uri-local or uri-local-prefix)) cannot be confused
|
|
|
|
|
// by an attacker putting additional namespace separator characters
|
|
|
|
|
// into namespace declarations. That would be ambiguous and not to
|
|
|
|
|
// be expected.
|
|
|
|
|
if (parser->m_ns && (uri[len] == parser->m_namespaceSeparator)) {
|
|
|
|
|
return XML_ERROR_SYNTAX;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
isXML = isXML && len == xmlLen;
|
|
|
|
|
isXMLNS = isXMLNS && len == xmlnsLen;
|
|
|
|
@@ -3707,6 +3806,21 @@ addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId,
|
|
|
|
|
if (parser->m_freeBindingList) {
|
|
|
|
|
b = parser->m_freeBindingList;
|
|
|
|
|
if (len > b->uriAlloc) {
|
|
|
|
|
/* Detect and prevent integer overflow */
|
|
|
|
|
if (len > INT_MAX - EXPAND_SPARE) {
|
|
|
|
|
return XML_ERROR_NO_MEMORY;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Detect and prevent integer overflow.
|
|
|
|
|
* The preprocessor guard addresses the "always false" warning
|
|
|
|
|
* from -Wtype-limits on platforms where
|
|
|
|
|
* sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */
|
|
|
|
|
#if UINT_MAX >= SIZE_MAX
|
|
|
|
|
if ((unsigned)(len + EXPAND_SPARE) > (size_t)(-1) / sizeof(XML_Char)) {
|
|
|
|
|
return XML_ERROR_NO_MEMORY;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
XML_Char *temp = (XML_Char *)REALLOC(
|
|
|
|
|
parser, b->uri, sizeof(XML_Char) * (len + EXPAND_SPARE));
|
|
|
|
|
if (temp == NULL)
|
|
|
|
@@ -3719,6 +3833,21 @@ addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId,
|
|
|
|
|
b = (BINDING *)MALLOC(parser, sizeof(BINDING));
|
|
|
|
|
if (! b)
|
|
|
|
|
return XML_ERROR_NO_MEMORY;
|
|
|
|
|
|
|
|
|
|
/* Detect and prevent integer overflow */
|
|
|
|
|
if (len > INT_MAX - EXPAND_SPARE) {
|
|
|
|
|
return XML_ERROR_NO_MEMORY;
|
|
|
|
|
}
|
|
|
|
|
/* Detect and prevent integer overflow.
|
|
|
|
|
* The preprocessor guard addresses the "always false" warning
|
|
|
|
|
* from -Wtype-limits on platforms where
|
|
|
|
|
* sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */
|
|
|
|
|
#if UINT_MAX >= SIZE_MAX
|
|
|
|
|
if ((unsigned)(len + EXPAND_SPARE) > (size_t)(-1) / sizeof(XML_Char)) {
|
|
|
|
|
return XML_ERROR_NO_MEMORY;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
b->uri
|
|
|
|
|
= (XML_Char *)MALLOC(parser, sizeof(XML_Char) * (len + EXPAND_SPARE));
|
|
|
|
|
if (! b->uri) {
|
|
|
|
@@ -5045,6 +5174,11 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end,
|
|
|
|
|
if (parser->m_prologState.level >= parser->m_groupSize) {
|
|
|
|
|
if (parser->m_groupSize) {
|
|
|
|
|
{
|
|
|
|
|
/* Detect and prevent integer overflow */
|
|
|
|
|
if (parser->m_groupSize > (unsigned int)(-1) / 2u) {
|
|
|
|
|
return XML_ERROR_NO_MEMORY;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
char *const new_connector = (char *)REALLOC(
|
|
|
|
|
parser, parser->m_groupConnector, parser->m_groupSize *= 2);
|
|
|
|
|
if (new_connector == NULL) {
|
|
|
|
@@ -5055,6 +5189,16 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (dtd->scaffIndex) {
|
|
|
|
|
/* Detect and prevent integer overflow.
|
|
|
|
|
* The preprocessor guard addresses the "always false" warning
|
|
|
|
|
* from -Wtype-limits on platforms where
|
|
|
|
|
* sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */
|
|
|
|
|
#if UINT_MAX >= SIZE_MAX
|
|
|
|
|
if (parser->m_groupSize > (size_t)(-1) / sizeof(int)) {
|
|
|
|
|
return XML_ERROR_NO_MEMORY;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
int *const new_scaff_index = (int *)REALLOC(
|
|
|
|
|
parser, dtd->scaffIndex, parser->m_groupSize * sizeof(int));
|
|
|
|
|
if (new_scaff_index == NULL)
|
|
|
|
@@ -6131,7 +6275,24 @@ defineAttribute(ELEMENT_TYPE *type, ATTRIBUTE_ID *attId, XML_Bool isCdata,
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
DEFAULT_ATTRIBUTE *temp;
|
|
|
|
|
|
|
|
|
|
/* Detect and prevent integer overflow */
|
|
|
|
|
if (type->allocDefaultAtts > INT_MAX / 2) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int count = type->allocDefaultAtts * 2;
|
|
|
|
|
|
|
|
|
|
/* Detect and prevent integer overflow.
|
|
|
|
|
* The preprocessor guard addresses the "always false" warning
|
|
|
|
|
* from -Wtype-limits on platforms where
|
|
|
|
|
* sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */
|
|
|
|
|
#if UINT_MAX >= SIZE_MAX
|
|
|
|
|
if ((unsigned)count > (size_t)(-1) / sizeof(DEFAULT_ATTRIBUTE)) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
temp = (DEFAULT_ATTRIBUTE *)REALLOC(parser, type->defaultAtts,
|
|
|
|
|
(count * sizeof(DEFAULT_ATTRIBUTE)));
|
|
|
|
|
if (temp == NULL)
|
|
|
|
@@ -6594,8 +6755,8 @@ dtdCopy(XML_Parser oldParser, DTD *newDtd, const DTD *oldDtd,
|
|
|
|
|
if (! newE)
|
|
|
|
|
return 0;
|
|
|
|
|
if (oldE->nDefaultAtts) {
|
|
|
|
|
newE->defaultAtts = (DEFAULT_ATTRIBUTE *)ms->malloc_fcn(
|
|
|
|
|
oldE->nDefaultAtts * sizeof(DEFAULT_ATTRIBUTE));
|
|
|
|
|
newE->defaultAtts = (DEFAULT_ATTRIBUTE *)
|
|
|
|
|
ms->malloc_fcn(oldE->nDefaultAtts * sizeof(DEFAULT_ATTRIBUTE));
|
|
|
|
|
if (! newE->defaultAtts) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
@@ -6782,8 +6943,20 @@ lookup(XML_Parser parser, HASH_TABLE *table, KEY name, size_t createSize) {
|
|
|
|
|
/* check for overflow (table is half full) */
|
|
|
|
|
if (table->used >> (table->power - 1)) {
|
|
|
|
|
unsigned char newPower = table->power + 1;
|
|
|
|
|
|
|
|
|
|
/* Detect and prevent invalid shift */
|
|
|
|
|
if (newPower >= sizeof(unsigned long) * 8 /* bits per byte */) {
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size_t newSize = (size_t)1 << newPower;
|
|
|
|
|
unsigned long newMask = (unsigned long)newSize - 1;
|
|
|
|
|
|
|
|
|
|
/* Detect and prevent integer overflow */
|
|
|
|
|
if (newSize > (size_t)(-1) / sizeof(NAMED *)) {
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size_t tsize = newSize * sizeof(NAMED *);
|
|
|
|
|
NAMED **newV = (NAMED **)table->mem->malloc_fcn(tsize);
|
|
|
|
|
if (! newV)
|
|
|
|
@@ -7133,6 +7306,20 @@ nextScaffoldPart(XML_Parser parser) {
|
|
|
|
|
if (dtd->scaffCount >= dtd->scaffSize) {
|
|
|
|
|
CONTENT_SCAFFOLD *temp;
|
|
|
|
|
if (dtd->scaffold) {
|
|
|
|
|
/* Detect and prevent integer overflow */
|
|
|
|
|
if (dtd->scaffSize > UINT_MAX / 2u) {
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
/* Detect and prevent integer overflow.
|
|
|
|
|
* The preprocessor guard addresses the "always false" warning
|
|
|
|
|
* from -Wtype-limits on platforms where
|
|
|
|
|
* sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */
|
|
|
|
|
#if UINT_MAX >= SIZE_MAX
|
|
|
|
|
if (dtd->scaffSize > (size_t)(-1) / 2u / sizeof(CONTENT_SCAFFOLD)) {
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
temp = (CONTENT_SCAFFOLD *)REALLOC(
|
|
|
|
|
parser, dtd->scaffold, dtd->scaffSize * 2 * sizeof(CONTENT_SCAFFOLD));
|
|
|
|
|
if (temp == NULL)
|
|
|
|
@@ -7164,55 +7351,115 @@ nextScaffoldPart(XML_Parser parser) {
|
|
|
|
|
return next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
build_node(XML_Parser parser, int src_node, XML_Content *dest,
|
|
|
|
|
XML_Content **contpos, XML_Char **strpos) {
|
|
|
|
|
DTD *const dtd = parser->m_dtd; /* save one level of indirection */
|
|
|
|
|
dest->type = dtd->scaffold[src_node].type;
|
|
|
|
|
dest->quant = dtd->scaffold[src_node].quant;
|
|
|
|
|
if (dest->type == XML_CTYPE_NAME) {
|
|
|
|
|
const XML_Char *src;
|
|
|
|
|
dest->name = *strpos;
|
|
|
|
|
src = dtd->scaffold[src_node].name;
|
|
|
|
|
for (;;) {
|
|
|
|
|
*(*strpos)++ = *src;
|
|
|
|
|
if (! *src)
|
|
|
|
|
break;
|
|
|
|
|
src++;
|
|
|
|
|
}
|
|
|
|
|
dest->numchildren = 0;
|
|
|
|
|
dest->children = NULL;
|
|
|
|
|
} else {
|
|
|
|
|
unsigned int i;
|
|
|
|
|
int cn;
|
|
|
|
|
dest->numchildren = dtd->scaffold[src_node].childcnt;
|
|
|
|
|
dest->children = *contpos;
|
|
|
|
|
*contpos += dest->numchildren;
|
|
|
|
|
for (i = 0, cn = dtd->scaffold[src_node].firstchild; i < dest->numchildren;
|
|
|
|
|
i++, cn = dtd->scaffold[cn].nextsib) {
|
|
|
|
|
build_node(parser, cn, &(dest->children[i]), contpos, strpos);
|
|
|
|
|
}
|
|
|
|
|
dest->name = NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static XML_Content *
|
|
|
|
|
build_model(XML_Parser parser) {
|
|
|
|
|
/* Function build_model transforms the existing parser->m_dtd->scaffold
|
|
|
|
|
* array of CONTENT_SCAFFOLD tree nodes into a new array of
|
|
|
|
|
* XML_Content tree nodes followed by a gapless list of zero-terminated
|
|
|
|
|
* strings. */
|
|
|
|
|
DTD *const dtd = parser->m_dtd; /* save one level of indirection */
|
|
|
|
|
XML_Content *ret;
|
|
|
|
|
XML_Content *cpos;
|
|
|
|
|
XML_Char *str;
|
|
|
|
|
int allocsize = (dtd->scaffCount * sizeof(XML_Content)
|
|
|
|
|
+ (dtd->contentStringLen * sizeof(XML_Char)));
|
|
|
|
|
XML_Char *str; /* the current string writing location */
|
|
|
|
|
|
|
|
|
|
/* Detect and prevent integer overflow.
|
|
|
|
|
* The preprocessor guard addresses the "always false" warning
|
|
|
|
|
* from -Wtype-limits on platforms where
|
|
|
|
|
* sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */
|
|
|
|
|
#if UINT_MAX >= SIZE_MAX
|
|
|
|
|
if (dtd->scaffCount > (size_t)(-1) / sizeof(XML_Content)) {
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
if (dtd->contentStringLen > (size_t)(-1) / sizeof(XML_Char)) {
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
if (dtd->scaffCount * sizeof(XML_Content)
|
|
|
|
|
> (size_t)(-1) - dtd->contentStringLen * sizeof(XML_Char)) {
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const size_t allocsize = (dtd->scaffCount * sizeof(XML_Content)
|
|
|
|
|
+ (dtd->contentStringLen * sizeof(XML_Char)));
|
|
|
|
|
|
|
|
|
|
ret = (XML_Content *)MALLOC(parser, allocsize);
|
|
|
|
|
if (! ret)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
str = (XML_Char *)(&ret[dtd->scaffCount]);
|
|
|
|
|
cpos = &ret[1];
|
|
|
|
|
/* What follows is an iterative implementation (of what was previously done
|
|
|
|
|
* recursively in a dedicated function called "build_node". The old recursive
|
|
|
|
|
* build_node could be forced into stack exhaustion from input as small as a
|
|
|
|
|
* few megabyte, and so that was a security issue. Hence, a function call
|
|
|
|
|
* stack is avoided now by resolving recursion.)
|
|
|
|
|
*
|
|
|
|
|
* The iterative approach works as follows:
|
|
|
|
|
*
|
|
|
|
|
* - We use space in the target array for building a temporary stack structure
|
|
|
|
|
* while that space is still unused.
|
|
|
|
|
* The stack grows from the array's end downwards and the "actual data"
|
|
|
|
|
* grows from the start upwards, sequentially.
|
|
|
|
|
* (Because stack grows downwards, pushing onto the stack is a decrement
|
|
|
|
|
* while popping off the stack is an increment.)
|
|
|
|
|
*
|
|
|
|
|
* - A stack element appears as a regular XML_Content node on the outside,
|
|
|
|
|
* but only uses a single field -- numchildren -- to store the source
|
|
|
|
|
* tree node array index. These are the breadcrumbs leading the way back
|
|
|
|
|
* during pre-order (node first) depth-first traversal.
|
|
|
|
|
*
|
|
|
|
|
* - The reason we know the stack will never grow into (or overlap with)
|
|
|
|
|
* the area with data of value at the start of the array is because
|
|
|
|
|
* the overall number of elements to process matches the size of the array,
|
|
|
|
|
* and the sum of fully processed nodes and yet-to-be processed nodes
|
|
|
|
|
* on the stack, cannot be more than the total number of nodes.
|
|
|
|
|
* It is possible for the top of the stack and the about-to-write node
|
|
|
|
|
* to meet, but that is safe because we get the source index out
|
|
|
|
|
* before doing any writes on that node.
|
|
|
|
|
*/
|
|
|
|
|
XML_Content *dest = ret; /* tree node writing location, moves upwards */
|
|
|
|
|
XML_Content *const destLimit = &ret[dtd->scaffCount];
|
|
|
|
|
XML_Content *const stackBottom = &ret[dtd->scaffCount];
|
|
|
|
|
XML_Content *stackTop = stackBottom; /* i.e. stack is initially empty */
|
|
|
|
|
str = (XML_Char *)&ret[dtd->scaffCount];
|
|
|
|
|
|
|
|
|
|
/* Push source tree root node index onto the stack */
|
|
|
|
|
(--stackTop)->numchildren = 0;
|
|
|
|
|
|
|
|
|
|
for (; dest < destLimit; dest++) {
|
|
|
|
|
/* Pop source tree node index off the stack */
|
|
|
|
|
const int src_node = (int)(stackTop++)->numchildren;
|
|
|
|
|
|
|
|
|
|
/* Convert item */
|
|
|
|
|
dest->type = dtd->scaffold[src_node].type;
|
|
|
|
|
dest->quant = dtd->scaffold[src_node].quant;
|
|
|
|
|
if (dest->type == XML_CTYPE_NAME) {
|
|
|
|
|
const XML_Char *src;
|
|
|
|
|
dest->name = str;
|
|
|
|
|
src = dtd->scaffold[src_node].name;
|
|
|
|
|
for (;;) {
|
|
|
|
|
*str++ = *src;
|
|
|
|
|
if (! *src)
|
|
|
|
|
break;
|
|
|
|
|
src++;
|
|
|
|
|
}
|
|
|
|
|
dest->numchildren = 0;
|
|
|
|
|
dest->children = NULL;
|
|
|
|
|
} else {
|
|
|
|
|
unsigned int i;
|
|
|
|
|
int cn;
|
|
|
|
|
dest->name = NULL;
|
|
|
|
|
dest->numchildren = dtd->scaffold[src_node].childcnt;
|
|
|
|
|
dest->children = &dest[1];
|
|
|
|
|
|
|
|
|
|
/* Push children to the stack
|
|
|
|
|
* in a way where the first child ends up at the top of the
|
|
|
|
|
* (downwards growing) stack, in order to be processed first. */
|
|
|
|
|
stackTop -= dest->numchildren;
|
|
|
|
|
for (i = 0, cn = dtd->scaffold[src_node].firstchild;
|
|
|
|
|
i < dest->numchildren; i++, cn = dtd->scaffold[cn].nextsib) {
|
|
|
|
|
(stackTop + i)->numchildren = (unsigned int)cn;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
build_node(parser, 0, ret, &cpos, &str);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -7241,7 +7488,7 @@ getElementType(XML_Parser parser, const ENCODING *enc, const char *ptr,
|
|
|
|
|
|
|
|
|
|
static XML_Char *
|
|
|
|
|
copyString(const XML_Char *s, const XML_Memory_Handling_Suite *memsuite) {
|
|
|
|
|
int charsRequired = 0;
|
|
|
|
|
size_t charsRequired = 0;
|
|
|
|
|
XML_Char *result;
|
|
|
|
|
|
|
|
|
|
/* First determine how long the string is */
|
|
|
|
|