|
|
|
@ -1,4 +1,4 @@
|
|
|
|
|
/* 8539b9040d9d901366a62560a064af7cb99811335784b363abc039c5b0ebc416 (2.4.1+)
|
|
|
|
|
/* 2722de33b8d95adcfb16db05afdec6ed1d40d51565cda2176c61806b5350eafe (2.4.8+)
|
|
|
|
|
__ __ _
|
|
|
|
|
___\ \/ /_ __ __ _| |_
|
|
|
|
|
/ _ \\ /| '_ \ / _` | __|
|
|
|
|
@ -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>
|
|
|
|
@ -32,6 +32,9 @@
|
|
|
|
|
Copyright (c) 2019 David Loffredo <loffredo@steptools.com>
|
|
|
|
|
Copyright (c) 2019-2020 Ben Wagner <bungeman@chromium.org>
|
|
|
|
|
Copyright (c) 2019 Vadim Zeitlin <vadim@zeitlins.org>
|
|
|
|
|
Copyright (c) 2021 Dong-hee Na <donghee.na@python.org>
|
|
|
|
|
Copyright (c) 2022 Samanta Navarro <ferivoz@riseup.net>
|
|
|
|
|
Copyright (c) 2022 Jeffrey Walton <noloader@gmail.com>
|
|
|
|
|
Licensed under the MIT license:
|
|
|
|
|
|
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining
|
|
|
|
@ -54,6 +57,10 @@
|
|
|
|
|
USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#define XML_BUILDING_EXPAT 1
|
|
|
|
|
|
|
|
|
|
#include <expat_config.h>
|
|
|
|
|
|
|
|
|
|
#if ! defined(_GNU_SOURCE)
|
|
|
|
|
# define _GNU_SOURCE 1 /* syscall prototype */
|
|
|
|
|
#endif
|
|
|
|
@ -84,14 +91,10 @@
|
|
|
|
|
# include <errno.h>
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#define XML_BUILDING_EXPAT 1
|
|
|
|
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
|
# include "winconfig.h"
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#include <expat_config.h>
|
|
|
|
|
|
|
|
|
|
#include "ascii.h"
|
|
|
|
|
#include "expat.h"
|
|
|
|
|
#include "siphash.h"
|
|
|
|
@ -131,7 +134,7 @@
|
|
|
|
|
* BSD / macOS (including <10.7) (arc4random): HAVE_ARC4RANDOM, \
|
|
|
|
|
* libbsd (arc4random_buf): HAVE_ARC4RANDOM_BUF + HAVE_LIBBSD, \
|
|
|
|
|
* libbsd (arc4random): HAVE_ARC4RANDOM + HAVE_LIBBSD, \
|
|
|
|
|
* Linux (including <3.17) / BSD / macOS (including <10.7) (/dev/urandom): XML_DEV_URANDOM, \
|
|
|
|
|
* Linux (including <3.17) / BSD / macOS (including <10.7) / Solaris >=8 (/dev/urandom): XML_DEV_URANDOM, \
|
|
|
|
|
* Windows >=Vista (rand_s): _WIN32. \
|
|
|
|
|
\
|
|
|
|
|
If insist on not using any of these, bypass this error by defining \
|
|
|
|
@ -716,11 +719,11 @@ 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);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// "xml=http://www.w3.org/XML/1998/namespace"
|
|
|
|
|
static const XML_Char implicitContext[]
|
|
|
|
|
= {ASCII_x, ASCII_m, ASCII_l, ASCII_EQUALS, ASCII_h,
|
|
|
|
|
ASCII_t, ASCII_t, ASCII_p, ASCII_COLON, ASCII_SLASH,
|
|
|
|
@ -973,7 +976,7 @@ parserCreate(const XML_Char *encodingName,
|
|
|
|
|
|
|
|
|
|
if (memsuite) {
|
|
|
|
|
XML_Memory_Handling_Suite *mtemp;
|
|
|
|
|
parser = (XML_Parser)memsuite->malloc_fcn(sizeof(struct XML_ParserStruct));
|
|
|
|
|
parser = memsuite->malloc_fcn(sizeof(struct XML_ParserStruct));
|
|
|
|
|
if (parser != NULL) {
|
|
|
|
|
mtemp = (XML_Memory_Handling_Suite *)&(parser->m_mem);
|
|
|
|
|
mtemp->malloc_fcn = memsuite->malloc_fcn;
|
|
|
|
@ -1342,8 +1345,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);
|
|
|
|
@ -2066,6 +2068,11 @@ XML_GetBuffer(XML_Parser parser, int len) {
|
|
|
|
|
keep = (int)EXPAT_SAFE_PTR_DIFF(parser->m_bufferPtr, parser->m_buffer);
|
|
|
|
|
if (keep > XML_CONTEXT_BYTES)
|
|
|
|
|
keep = XML_CONTEXT_BYTES;
|
|
|
|
|
/* Detect and prevent integer overflow */
|
|
|
|
|
if (keep > INT_MAX - neededSize) {
|
|
|
|
|
parser->m_errorCode = XML_ERROR_NO_MEMORY;
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
neededSize += keep;
|
|
|
|
|
#endif /* defined XML_CONTEXT_BYTES */
|
|
|
|
|
if (neededSize
|
|
|
|
@ -2556,6 +2563,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
|
|
|
|
@ -2567,7 +2575,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)
|
|
|
|
@ -3260,13 +3272,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) {
|
|
|
|
@ -3275,6 +3312,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) {
|
|
|
|
@ -3413,7 +3461,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)
|
|
|
|
@ -3424,7 +3478,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) {
|
|
|
|
@ -3582,9 +3657,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;
|
|
|
|
@ -3609,12 +3706,124 @@ storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr,
|
|
|
|
|
return XML_ERROR_NONE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static XML_Bool
|
|
|
|
|
is_rfc3986_uri_char(XML_Char candidate) {
|
|
|
|
|
// For the RFC 3986 ANBF grammar see
|
|
|
|
|
// https://datatracker.ietf.org/doc/html/rfc3986#appendix-A
|
|
|
|
|
|
|
|
|
|
switch (candidate) {
|
|
|
|
|
// From rule "ALPHA" (uppercase half)
|
|
|
|
|
case 'A':
|
|
|
|
|
case 'B':
|
|
|
|
|
case 'C':
|
|
|
|
|
case 'D':
|
|
|
|
|
case 'E':
|
|
|
|
|
case 'F':
|
|
|
|
|
case 'G':
|
|
|
|
|
case 'H':
|
|
|
|
|
case 'I':
|
|
|
|
|
case 'J':
|
|
|
|
|
case 'K':
|
|
|
|
|
case 'L':
|
|
|
|
|
case 'M':
|
|
|
|
|
case 'N':
|
|
|
|
|
case 'O':
|
|
|
|
|
case 'P':
|
|
|
|
|
case 'Q':
|
|
|
|
|
case 'R':
|
|
|
|
|
case 'S':
|
|
|
|
|
case 'T':
|
|
|
|
|
case 'U':
|
|
|
|
|
case 'V':
|
|
|
|
|
case 'W':
|
|
|
|
|
case 'X':
|
|
|
|
|
case 'Y':
|
|
|
|
|
case 'Z':
|
|
|
|
|
|
|
|
|
|
// From rule "ALPHA" (lowercase half)
|
|
|
|
|
case 'a':
|
|
|
|
|
case 'b':
|
|
|
|
|
case 'c':
|
|
|
|
|
case 'd':
|
|
|
|
|
case 'e':
|
|
|
|
|
case 'f':
|
|
|
|
|
case 'g':
|
|
|
|
|
case 'h':
|
|
|
|
|
case 'i':
|
|
|
|
|
case 'j':
|
|
|
|
|
case 'k':
|
|
|
|
|
case 'l':
|
|
|
|
|
case 'm':
|
|
|
|
|
case 'n':
|
|
|
|
|
case 'o':
|
|
|
|
|
case 'p':
|
|
|
|
|
case 'q':
|
|
|
|
|
case 'r':
|
|
|
|
|
case 's':
|
|
|
|
|
case 't':
|
|
|
|
|
case 'u':
|
|
|
|
|
case 'v':
|
|
|
|
|
case 'w':
|
|
|
|
|
case 'x':
|
|
|
|
|
case 'y':
|
|
|
|
|
case 'z':
|
|
|
|
|
|
|
|
|
|
// From rule "DIGIT"
|
|
|
|
|
case '0':
|
|
|
|
|
case '1':
|
|
|
|
|
case '2':
|
|
|
|
|
case '3':
|
|
|
|
|
case '4':
|
|
|
|
|
case '5':
|
|
|
|
|
case '6':
|
|
|
|
|
case '7':
|
|
|
|
|
case '8':
|
|
|
|
|
case '9':
|
|
|
|
|
|
|
|
|
|
// From rule "pct-encoded"
|
|
|
|
|
case '%':
|
|
|
|
|
|
|
|
|
|
// From rule "unreserved"
|
|
|
|
|
case '-':
|
|
|
|
|
case '.':
|
|
|
|
|
case '_':
|
|
|
|
|
case '~':
|
|
|
|
|
|
|
|
|
|
// From rule "gen-delims"
|
|
|
|
|
case ':':
|
|
|
|
|
case '/':
|
|
|
|
|
case '?':
|
|
|
|
|
case '#':
|
|
|
|
|
case '[':
|
|
|
|
|
case ']':
|
|
|
|
|
case '@':
|
|
|
|
|
|
|
|
|
|
// From rule "sub-delims"
|
|
|
|
|
case '!':
|
|
|
|
|
case '$':
|
|
|
|
|
case '&':
|
|
|
|
|
case '\'':
|
|
|
|
|
case '(':
|
|
|
|
|
case ')':
|
|
|
|
|
case '*':
|
|
|
|
|
case '+':
|
|
|
|
|
case ',':
|
|
|
|
|
case ';':
|
|
|
|
|
case '=':
|
|
|
|
|
return XML_TRUE;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
return XML_FALSE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* addBinding() overwrites the value of prefix->binding without checking.
|
|
|
|
|
Therefore one must keep track of the old value outside of addBinding().
|
|
|
|
|
*/
|
|
|
|
|
static enum XML_Error
|
|
|
|
|
addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId,
|
|
|
|
|
const XML_Char *uri, BINDING **bindingsPtr) {
|
|
|
|
|
// "http://www.w3.org/XML/1998/namespace"
|
|
|
|
|
static const XML_Char xmlNamespace[]
|
|
|
|
|
= {ASCII_h, ASCII_t, ASCII_t, ASCII_p, ASCII_COLON,
|
|
|
|
|
ASCII_SLASH, ASCII_SLASH, ASCII_w, ASCII_w, ASCII_w,
|
|
|
|
@ -3625,6 +3834,7 @@ addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId,
|
|
|
|
|
ASCII_e, ASCII_s, ASCII_p, ASCII_a, ASCII_c,
|
|
|
|
|
ASCII_e, '\0'};
|
|
|
|
|
static const int xmlLen = (int)sizeof(xmlNamespace) / sizeof(XML_Char) - 1;
|
|
|
|
|
// "http://www.w3.org/2000/xmlns/"
|
|
|
|
|
static const XML_Char xmlnsNamespace[]
|
|
|
|
|
= {ASCII_h, ASCII_t, ASCII_t, ASCII_p, ASCII_COLON, ASCII_SLASH,
|
|
|
|
|
ASCII_SLASH, ASCII_w, ASCII_w, ASCII_w, ASCII_PERIOD, ASCII_w,
|
|
|
|
@ -3664,6 +3874,29 @@ 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
|
|
|
|
|
// today (and is not REQUIRED to do so with regard to the XML 1.0
|
|
|
|
|
// namespaces specification) we have to at least make sure, that
|
|
|
|
|
// the application on top of Expat (that is likely splitting expanded
|
|
|
|
|
// element names ("qualified names") of form
|
|
|
|
|
// "[uri sep] local [sep prefix] '\0'" back into 1, 2 or 3 pieces
|
|
|
|
|
// in its element handler code) cannot be confused by an attacker
|
|
|
|
|
// putting additional namespace separator characters into namespace
|
|
|
|
|
// declarations. That would be ambiguous and not to be expected.
|
|
|
|
|
//
|
|
|
|
|
// While the HTML API docs of function XML_ParserCreateNS have been
|
|
|
|
|
// advising against use of a namespace separator character that can
|
|
|
|
|
// appear in a URI for >20 years now, some widespread applications
|
|
|
|
|
// are using URI characters (':' (colon) in particular) for a
|
|
|
|
|
// namespace separator, in practice. To keep these applications
|
|
|
|
|
// functional, we only reject namespaces URIs containing the
|
|
|
|
|
// application-chosen namespace separator if the chosen separator
|
|
|
|
|
// is a non-URI character with regard to RFC 3986.
|
|
|
|
|
if (parser->m_ns && (uri[len] == parser->m_namespaceSeparator)
|
|
|
|
|
&& ! is_rfc3986_uri_char(uri[len])) {
|
|
|
|
|
return XML_ERROR_SYNTAX;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
isXML = isXML && len == xmlLen;
|
|
|
|
|
isXMLNS = isXMLNS && len == xmlnsLen;
|
|
|
|
@ -3680,6 +3913,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)
|
|
|
|
@ -3692,6 +3940,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) {
|
|
|
|
@ -3976,7 +4239,7 @@ initializeEncoding(XML_Parser parser) {
|
|
|
|
|
const char *s;
|
|
|
|
|
#ifdef XML_UNICODE
|
|
|
|
|
char encodingBuf[128];
|
|
|
|
|
/* See comments abount `protoclEncodingName` in parserInit() */
|
|
|
|
|
/* See comments about `protocolEncodingName` in parserInit() */
|
|
|
|
|
if (! parser->m_protocolEncodingName)
|
|
|
|
|
s = NULL;
|
|
|
|
|
else {
|
|
|
|
@ -5018,6 +5281,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) {
|
|
|
|
@ -5028,6 +5296,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)
|
|
|
|
@ -5236,7 +5514,7 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end,
|
|
|
|
|
if (dtd->in_eldecl) {
|
|
|
|
|
ELEMENT_TYPE *el;
|
|
|
|
|
const XML_Char *name;
|
|
|
|
|
int nameLen;
|
|
|
|
|
size_t nameLen;
|
|
|
|
|
const char *nxt
|
|
|
|
|
= (quant == XML_CQUANT_NONE ? next : next - enc->minBytesPerChar);
|
|
|
|
|
int myindex = nextScaffoldPart(parser);
|
|
|
|
@ -5252,7 +5530,13 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end,
|
|
|
|
|
nameLen = 0;
|
|
|
|
|
for (; name[nameLen++];)
|
|
|
|
|
;
|
|
|
|
|
dtd->contentStringLen += nameLen;
|
|
|
|
|
|
|
|
|
|
/* Detect and prevent integer overflow */
|
|
|
|
|
if (nameLen > UINT_MAX - dtd->contentStringLen) {
|
|
|
|
|
return XML_ERROR_NO_MEMORY;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dtd->contentStringLen += (unsigned)nameLen;
|
|
|
|
|
if (parser->m_elementDeclHandler)
|
|
|
|
|
handleDefault = XML_FALSE;
|
|
|
|
|
}
|
|
|
|
@ -6098,7 +6382,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)
|
|
|
|
@ -6388,7 +6689,7 @@ normalizePublicId(XML_Char *publicId) {
|
|
|
|
|
|
|
|
|
|
static DTD *
|
|
|
|
|
dtdCreate(const XML_Memory_Handling_Suite *ms) {
|
|
|
|
|
DTD *p = (DTD *)ms->malloc_fcn(sizeof(DTD));
|
|
|
|
|
DTD *p = ms->malloc_fcn(sizeof(DTD));
|
|
|
|
|
if (p == NULL)
|
|
|
|
|
return p;
|
|
|
|
|
poolInit(&(p->pool), ms);
|
|
|
|
@ -6561,8 +6862,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
|
|
|
|
|
= ms->malloc_fcn(oldE->nDefaultAtts * sizeof(DEFAULT_ATTRIBUTE));
|
|
|
|
|
if (! newE->defaultAtts) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
@ -6724,7 +7025,7 @@ lookup(XML_Parser parser, HASH_TABLE *table, KEY name, size_t createSize) {
|
|
|
|
|
/* table->size is a power of 2 */
|
|
|
|
|
table->size = (size_t)1 << INIT_POWER;
|
|
|
|
|
tsize = table->size * sizeof(NAMED *);
|
|
|
|
|
table->v = (NAMED **)table->mem->malloc_fcn(tsize);
|
|
|
|
|
table->v = table->mem->malloc_fcn(tsize);
|
|
|
|
|
if (! table->v) {
|
|
|
|
|
table->size = 0;
|
|
|
|
|
return NULL;
|
|
|
|
@ -6749,10 +7050,22 @@ 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);
|
|
|
|
|
NAMED **newV = table->mem->malloc_fcn(tsize);
|
|
|
|
|
if (! newV)
|
|
|
|
|
return NULL;
|
|
|
|
|
memset(newV, 0, tsize);
|
|
|
|
@ -6781,7 +7094,7 @@ lookup(XML_Parser parser, HASH_TABLE *table, KEY name, size_t createSize) {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
table->v[i] = (NAMED *)table->mem->malloc_fcn(createSize);
|
|
|
|
|
table->v[i] = table->mem->malloc_fcn(createSize);
|
|
|
|
|
if (! table->v[i])
|
|
|
|
|
return NULL;
|
|
|
|
|
memset(table->v[i], 0, createSize);
|
|
|
|
@ -7069,7 +7382,7 @@ poolGrow(STRING_POOL *pool) {
|
|
|
|
|
if (bytesToAllocate == 0)
|
|
|
|
|
return XML_FALSE;
|
|
|
|
|
|
|
|
|
|
tem = (BLOCK *)pool->mem->malloc_fcn(bytesToAllocate);
|
|
|
|
|
tem = pool->mem->malloc_fcn(bytesToAllocate);
|
|
|
|
|
if (! tem)
|
|
|
|
|
return XML_FALSE;
|
|
|
|
|
tem->size = blockSize;
|
|
|
|
@ -7100,6 +7413,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)
|
|
|
|
@ -7131,55 +7458,130 @@ 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 have two writing pointers, both walking up the result array; one does
|
|
|
|
|
* the work, the other creates "jobs" for its colleague to do, and leads
|
|
|
|
|
* the way:
|
|
|
|
|
*
|
|
|
|
|
* - The faster one, pointer jobDest, always leads and writes "what job
|
|
|
|
|
* to do" by the other, once they reach that place in the
|
|
|
|
|
* array: leader "jobDest" stores the source node array index (relative
|
|
|
|
|
* to array dtd->scaffold) in field "numchildren".
|
|
|
|
|
*
|
|
< |