main/libxml2: mitigate cves

- CVE-2022-40303
- CVE-2022-40304
This commit is contained in:
psykose 2022-10-16 00:08:35 +00:00
parent 49b2ca3f49
commit c021ebde2b
3 changed files with 724 additions and 1 deletions

View File

@ -2,7 +2,7 @@
# Maintainer: Carlo Landmeter <clandmeter@alpinelinux.org>
pkgname=libxml2
pkgver=2.9.14
pkgrel=1
pkgrel=2
pkgdesc="XML parsing library, version 2"
url="http://www.xmlsoft.org/"
arch="all"
@ -21,9 +21,14 @@ source="https://download.gnome.org/sources/libxml2/${pkgver%.*}/libxml2-$pkgver.
libxml2-2.9.8-python3-unicode-errors.patch
$pkgname-CVE-2022-3209-1.patch::https://gitlab.gnome.org/GNOME/libxml2/-/commit/5930fe01963136ab92125feec0c6204d9c9225dc.patch
$pkgname-CVE-2022-3209-2.patch::https://gitlab.gnome.org/GNOME/libxml2/-/commit/a82ea25fc83f563c574ddb863d6c17d9c5abdbd2.patch
CVE-2022-40303.patch
CVE-2022-40304.patch
"
# secfixes:
# 2.9.14-r2:
# - CVE-2022-40303
# - CVE-2022-40304
# 2.9.14-r1:
# - CVE-2022-2309
# 2.9.14-r0:
@ -113,4 +118,6 @@ d08e6cafb289c499fdc5b3a12181e032a34f7a249bc66758859f964d3e71e19fd69be79921e1a9d8
a205c97fa1488fb8907cfa08b5f82e2055c80b86213dc3cc5c4b526fe6aa786bcc4e4eeb226c44635a1d021307b39e3940f706c42fb60e9e3e9b490a84164df7 libxml2-2.9.8-python3-unicode-errors.patch
17741ee5fcddb1a5d802a90fdbd7bd38a6f6e03ce11c2fe2fb92c0420e94dffd50846c653ffd69425517ccf287ec8830698201dd1cfd34200ea1fd7c5e115de8 libxml2-CVE-2022-3209-1.patch
5c02cc54bf3f1507f2851468397d28922d9d6aac32a8c4b31ca96792da56ba17b8bb3c4e1aca2b4bd720d922d761635d53d29791b0066b3329c48aa0359dbb1e libxml2-CVE-2022-3209-2.patch
feca63825d3678027f9be1b9f7377d95e067ae2ebc7556e4259cb89baa2a93b890fef2280be6db91017e8492eb08752f37f2620d9ef2a4684691d22fc3b3025d CVE-2022-40303.patch
5000106b69d8c10d018f9f5f0942e6565728b3ccbc2830d1f5076651e6e018c30281d481a76dcb5304bbed6f65663a2bff385eec941491b6d950e8de478947b0 CVE-2022-40304.patch
"

View File

@ -0,0 +1,615 @@
From ffaec75809a315457891a0e54f8828bc6e056067 Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
Date: Thu, 25 Aug 2022 17:43:08 +0200
Subject: [PATCH] Fix integer overflows with XML_PARSE_HUGE
Also impose size limits when XML_PARSE_HUGE is set. Limit size of names
to XML_MAX_TEXT_LENGTH (10 million bytes) and other content to
XML_MAX_HUGE_LENGTH (1 billion bytes).
Move some the length checks to the end of the respective loop to make
them strict.
xmlParseEntityValue didn't have a length limitation at all. But without
XML_PARSE_HUGE, this should eventually trigger an error in xmlGROW.
Thanks to Maddie Stone working with Google Project Zero for the report!
---
parser.c | 233 +++++++++++++++++++++++++++++--------------------------
1 file changed, 121 insertions(+), 112 deletions(-)
diff --git a/parser.c b/parser.c
index af2af68..f214c1c 100644
--- a/parser.c
+++ b/parser.c
@@ -115,6 +115,8 @@ xmlParseElementEnd(xmlParserCtxtPtr ctxt);
* *
************************************************************************/
+#define XML_MAX_HUGE_LENGTH 1000000000
+
#define XML_PARSER_BIG_ENTITY 1000
#define XML_PARSER_LOT_ENTITY 5000
@@ -565,7 +567,7 @@ xmlFatalErr(xmlParserCtxtPtr ctxt, xmlParserErrors error, const char *info)
errmsg = "Malformed declaration expecting version";
break;
case XML_ERR_NAME_TOO_LONG:
- errmsg = "Name too long use XML_PARSE_HUGE option";
+ errmsg = "Name too long";
break;
#if 0
case:
@@ -3210,6 +3212,9 @@ xmlParseNameComplex(xmlParserCtxtPtr ctxt) {
int len = 0, l;
int c;
int count = 0;
+ int maxLength = (ctxt->options & XML_PARSE_HUGE) ?
+ XML_MAX_TEXT_LENGTH :
+ XML_MAX_NAME_LENGTH;
#ifdef DEBUG
nbParseNameComplex++;
@@ -3275,7 +3280,8 @@ xmlParseNameComplex(xmlParserCtxtPtr ctxt) {
if (ctxt->instate == XML_PARSER_EOF)
return(NULL);
}
- len += l;
+ if (len <= INT_MAX - l)
+ len += l;
NEXTL(l);
c = CUR_CHAR(l);
}
@@ -3301,13 +3307,13 @@ xmlParseNameComplex(xmlParserCtxtPtr ctxt) {
if (ctxt->instate == XML_PARSER_EOF)
return(NULL);
}
- len += l;
+ if (len <= INT_MAX - l)
+ len += l;
NEXTL(l);
c = CUR_CHAR(l);
}
}
- if ((len > XML_MAX_NAME_LENGTH) &&
- ((ctxt->options & XML_PARSE_HUGE) == 0)) {
+ if (len > maxLength) {
xmlFatalErr(ctxt, XML_ERR_NAME_TOO_LONG, "Name");
return(NULL);
}
@@ -3346,7 +3352,10 @@ const xmlChar *
xmlParseName(xmlParserCtxtPtr ctxt) {
const xmlChar *in;
const xmlChar *ret;
- int count = 0;
+ size_t count = 0;
+ size_t maxLength = (ctxt->options & XML_PARSE_HUGE) ?
+ XML_MAX_TEXT_LENGTH :
+ XML_MAX_NAME_LENGTH;
GROW;
@@ -3370,8 +3379,7 @@ xmlParseName(xmlParserCtxtPtr ctxt) {
in++;
if ((*in > 0) && (*in < 0x80)) {
count = in - ctxt->input->cur;
- if ((count > XML_MAX_NAME_LENGTH) &&
- ((ctxt->options & XML_PARSE_HUGE) == 0)) {
+ if (count > maxLength) {
xmlFatalErr(ctxt, XML_ERR_NAME_TOO_LONG, "Name");
return(NULL);
}
@@ -3392,6 +3400,9 @@ xmlParseNCNameComplex(xmlParserCtxtPtr ctxt) {
int len = 0, l;
int c;
int count = 0;
+ int maxLength = (ctxt->options & XML_PARSE_HUGE) ?
+ XML_MAX_TEXT_LENGTH :
+ XML_MAX_NAME_LENGTH;
size_t startPosition = 0;
#ifdef DEBUG
@@ -3412,17 +3423,13 @@ xmlParseNCNameComplex(xmlParserCtxtPtr ctxt) {
while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
(xmlIsNameChar(ctxt, c) && (c != ':'))) {
if (count++ > XML_PARSER_CHUNK_SIZE) {
- if ((len > XML_MAX_NAME_LENGTH) &&
- ((ctxt->options & XML_PARSE_HUGE) == 0)) {
- xmlFatalErr(ctxt, XML_ERR_NAME_TOO_LONG, "NCName");
- return(NULL);
- }
count = 0;
GROW;
if (ctxt->instate == XML_PARSER_EOF)
return(NULL);
}
- len += l;
+ if (len <= INT_MAX - l)
+ len += l;
NEXTL(l);
c = CUR_CHAR(l);
if (c == 0) {
@@ -3440,8 +3447,7 @@ xmlParseNCNameComplex(xmlParserCtxtPtr ctxt) {
c = CUR_CHAR(l);
}
}
- if ((len > XML_MAX_NAME_LENGTH) &&
- ((ctxt->options & XML_PARSE_HUGE) == 0)) {
+ if (len > maxLength) {
xmlFatalErr(ctxt, XML_ERR_NAME_TOO_LONG, "NCName");
return(NULL);
}
@@ -3467,7 +3473,10 @@ static const xmlChar *
xmlParseNCName(xmlParserCtxtPtr ctxt) {
const xmlChar *in, *e;
const xmlChar *ret;
- int count = 0;
+ size_t count = 0;
+ size_t maxLength = (ctxt->options & XML_PARSE_HUGE) ?
+ XML_MAX_TEXT_LENGTH :
+ XML_MAX_NAME_LENGTH;
#ifdef DEBUG
nbParseNCName++;
@@ -3492,8 +3501,7 @@ xmlParseNCName(xmlParserCtxtPtr ctxt) {
goto complex;
if ((*in > 0) && (*in < 0x80)) {
count = in - ctxt->input->cur;
- if ((count > XML_MAX_NAME_LENGTH) &&
- ((ctxt->options & XML_PARSE_HUGE) == 0)) {
+ if (count > maxLength) {
xmlFatalErr(ctxt, XML_ERR_NAME_TOO_LONG, "NCName");
return(NULL);
}
@@ -3575,6 +3583,9 @@ xmlParseStringName(xmlParserCtxtPtr ctxt, const xmlChar** str) {
const xmlChar *cur = *str;
int len = 0, l;
int c;
+ int maxLength = (ctxt->options & XML_PARSE_HUGE) ?
+ XML_MAX_TEXT_LENGTH :
+ XML_MAX_NAME_LENGTH;
#ifdef DEBUG
nbParseStringName++;
@@ -3610,12 +3621,6 @@ xmlParseStringName(xmlParserCtxtPtr ctxt, const xmlChar** str) {
if (len + 10 > max) {
xmlChar *tmp;
- if ((len > XML_MAX_NAME_LENGTH) &&
- ((ctxt->options & XML_PARSE_HUGE) == 0)) {
- xmlFatalErr(ctxt, XML_ERR_NAME_TOO_LONG, "NCName");
- xmlFree(buffer);
- return(NULL);
- }
max *= 2;
tmp = (xmlChar *) xmlRealloc(buffer,
max * sizeof(xmlChar));
@@ -3629,14 +3634,18 @@ xmlParseStringName(xmlParserCtxtPtr ctxt, const xmlChar** str) {
COPY_BUF(l,buffer,len,c);
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;
*str = cur;
return(buffer);
}
}
- if ((len > XML_MAX_NAME_LENGTH) &&
- ((ctxt->options & XML_PARSE_HUGE) == 0)) {
+ if (len > maxLength) {
xmlFatalErr(ctxt, XML_ERR_NAME_TOO_LONG, "NCName");
return(NULL);
}
@@ -3663,6 +3672,9 @@ xmlParseNmtoken(xmlParserCtxtPtr ctxt) {
int len = 0, l;
int c;
int count = 0;
+ int maxLength = (ctxt->options & XML_PARSE_HUGE) ?
+ XML_MAX_TEXT_LENGTH :
+ XML_MAX_NAME_LENGTH;
#ifdef DEBUG
nbParseNmToken++;
@@ -3714,12 +3726,6 @@ xmlParseNmtoken(xmlParserCtxtPtr ctxt) {
if (len + 10 > max) {
xmlChar *tmp;
- if ((max > XML_MAX_NAME_LENGTH) &&
- ((ctxt->options & XML_PARSE_HUGE) == 0)) {
- xmlFatalErr(ctxt, XML_ERR_NAME_TOO_LONG, "NmToken");
- xmlFree(buffer);
- return(NULL);
- }
max *= 2;
tmp = (xmlChar *) xmlRealloc(buffer,
max * sizeof(xmlChar));
@@ -3733,6 +3739,11 @@ xmlParseNmtoken(xmlParserCtxtPtr ctxt) {
COPY_BUF(l,buffer,len,c);
NEXTL(l);
c = CUR_CHAR(l);
+ if (len > maxLength) {
+ xmlFatalErr(ctxt, XML_ERR_NAME_TOO_LONG, "NmToken");
+ xmlFree(buffer);
+ return(NULL);
+ }
}
buffer[len] = 0;
return(buffer);
@@ -3740,8 +3751,7 @@ xmlParseNmtoken(xmlParserCtxtPtr ctxt) {
}
if (len == 0)
return(NULL);
- if ((len > XML_MAX_NAME_LENGTH) &&
- ((ctxt->options & XML_PARSE_HUGE) == 0)) {
+ if (len > maxLength) {
xmlFatalErr(ctxt, XML_ERR_NAME_TOO_LONG, "NmToken");
return(NULL);
}
@@ -3767,6 +3777,9 @@ xmlParseEntityValue(xmlParserCtxtPtr ctxt, xmlChar **orig) {
int len = 0;
int size = XML_PARSER_BUFFER_SIZE;
int c, l;
+ int maxLength = (ctxt->options & XML_PARSE_HUGE) ?
+ XML_MAX_HUGE_LENGTH :
+ XML_MAX_TEXT_LENGTH;
xmlChar stop;
xmlChar *ret = NULL;
const xmlChar *cur = NULL;
@@ -3826,6 +3839,12 @@ xmlParseEntityValue(xmlParserCtxtPtr ctxt, xmlChar **orig) {
GROW;
c = CUR_CHAR(l);
}
+
+ if (len > maxLength) {
+ xmlFatalErrMsg(ctxt, XML_ERR_ENTITY_NOT_FINISHED,
+ "entity value too long\n");
+ goto error;
+ }
}
buf[len] = 0;
if (ctxt->instate == XML_PARSER_EOF)
@@ -3913,6 +3932,9 @@ xmlParseAttValueComplex(xmlParserCtxtPtr ctxt, int *attlen, int normalize) {
xmlChar *rep = NULL;
size_t len = 0;
size_t buf_size = 0;
+ size_t maxLength = (ctxt->options & XML_PARSE_HUGE) ?
+ XML_MAX_HUGE_LENGTH :
+ XML_MAX_TEXT_LENGTH;
int c, l, in_space = 0;
xmlChar *current = NULL;
xmlEntityPtr ent;
@@ -3944,16 +3966,6 @@ xmlParseAttValueComplex(xmlParserCtxtPtr ctxt, int *attlen, int normalize) {
while (((NXT(0) != limit) && /* checked */
(IS_CHAR(c)) && (c != '<')) &&
(ctxt->instate != XML_PARSER_EOF)) {
- /*
- * Impose a reasonable limit on attribute size, unless XML_PARSE_HUGE
- * special option is given
- */
- if ((len > XML_MAX_TEXT_LENGTH) &&
- ((ctxt->options & XML_PARSE_HUGE) == 0)) {
- xmlFatalErrMsg(ctxt, XML_ERR_ATTRIBUTE_NOT_FINISHED,
- "AttValue length too long\n");
- goto mem_error;
- }
if (c == '&') {
in_space = 0;
if (NXT(1) == '#') {
@@ -4101,6 +4113,11 @@ xmlParseAttValueComplex(xmlParserCtxtPtr ctxt, int *attlen, int normalize) {
}
GROW;
c = CUR_CHAR(l);
+ if (len > maxLength) {
+ xmlFatalErrMsg(ctxt, XML_ERR_ATTRIBUTE_NOT_FINISHED,
+ "AttValue length too long\n");
+ goto mem_error;
+ }
}
if (ctxt->instate == XML_PARSER_EOF)
goto error;
@@ -4122,16 +4139,6 @@ xmlParseAttValueComplex(xmlParserCtxtPtr ctxt, int *attlen, int normalize) {
} else
NEXT;
- /*
- * There we potentially risk an overflow, don't allow attribute value of
- * length more than INT_MAX it is a very reasonable assumption !
- */
- if (len >= INT_MAX) {
- xmlFatalErrMsg(ctxt, XML_ERR_ATTRIBUTE_NOT_FINISHED,
- "AttValue length too long\n");
- goto mem_error;
- }
-
if (attlen != NULL) *attlen = (int) len;
return(buf);
@@ -4202,6 +4209,9 @@ xmlParseSystemLiteral(xmlParserCtxtPtr ctxt) {
int len = 0;
int size = XML_PARSER_BUFFER_SIZE;
int cur, l;
+ int maxLength = (ctxt->options & XML_PARSE_HUGE) ?
+ XML_MAX_TEXT_LENGTH :
+ XML_MAX_NAME_LENGTH;
xmlChar stop;
int state = ctxt->instate;
int count = 0;
@@ -4229,13 +4239,6 @@ xmlParseSystemLiteral(xmlParserCtxtPtr ctxt) {
if (len + 5 >= size) {
xmlChar *tmp;
- if ((size > XML_MAX_NAME_LENGTH) &&
- ((ctxt->options & XML_PARSE_HUGE) == 0)) {
- xmlFatalErr(ctxt, XML_ERR_NAME_TOO_LONG, "SystemLiteral");
- xmlFree(buf);
- ctxt->instate = (xmlParserInputState) state;
- return(NULL);
- }
size *= 2;
tmp = (xmlChar *) xmlRealloc(buf, size * sizeof(xmlChar));
if (tmp == NULL) {
@@ -4264,6 +4267,12 @@ xmlParseSystemLiteral(xmlParserCtxtPtr ctxt) {
SHRINK;
cur = CUR_CHAR(l);
}
+ if (len > maxLength) {
+ xmlFatalErr(ctxt, XML_ERR_NAME_TOO_LONG, "SystemLiteral");
+ xmlFree(buf);
+ ctxt->instate = (xmlParserInputState) state;
+ return(NULL);
+ }
}
buf[len] = 0;
ctxt->instate = (xmlParserInputState) state;
@@ -4291,6 +4300,9 @@ xmlParsePubidLiteral(xmlParserCtxtPtr ctxt) {
xmlChar *buf = NULL;
int len = 0;
int size = XML_PARSER_BUFFER_SIZE;
+ int maxLength = (ctxt->options & XML_PARSE_HUGE) ?
+ XML_MAX_TEXT_LENGTH :
+ XML_MAX_NAME_LENGTH;
xmlChar cur;
xmlChar stop;
int count = 0;
@@ -4318,12 +4330,6 @@ xmlParsePubidLiteral(xmlParserCtxtPtr ctxt) {
if (len + 1 >= size) {
xmlChar *tmp;
- if ((size > XML_MAX_NAME_LENGTH) &&
- ((ctxt->options & XML_PARSE_HUGE) == 0)) {
- xmlFatalErr(ctxt, XML_ERR_NAME_TOO_LONG, "Public ID");
- xmlFree(buf);
- return(NULL);
- }
size *= 2;
tmp = (xmlChar *) xmlRealloc(buf, size * sizeof(xmlChar));
if (tmp == NULL) {
@@ -4351,6 +4357,11 @@ xmlParsePubidLiteral(xmlParserCtxtPtr ctxt) {
SHRINK;
cur = CUR;
}
+ if (len > maxLength) {
+ xmlFatalErr(ctxt, XML_ERR_NAME_TOO_LONG, "Public ID");
+ xmlFree(buf);
+ return(NULL);
+ }
}
buf[len] = 0;
if (cur != stop) {
@@ -4750,6 +4761,9 @@ xmlParseCommentComplex(xmlParserCtxtPtr ctxt, xmlChar *buf,
int r, rl;
int cur, l;
size_t count = 0;
+ size_t maxLength = (ctxt->options & XML_PARSE_HUGE) ?
+ XML_MAX_HUGE_LENGTH :
+ XML_MAX_TEXT_LENGTH;
int inputid;
inputid = ctxt->input->id;
@@ -4795,13 +4809,6 @@ xmlParseCommentComplex(xmlParserCtxtPtr ctxt, xmlChar *buf,
if ((r == '-') && (q == '-')) {
xmlFatalErr(ctxt, XML_ERR_HYPHEN_IN_COMMENT, NULL);
}
- if ((len > XML_MAX_TEXT_LENGTH) &&
- ((ctxt->options & XML_PARSE_HUGE) == 0)) {
- xmlFatalErrMsgStr(ctxt, XML_ERR_COMMENT_NOT_FINISHED,
- "Comment too big found", NULL);
- xmlFree (buf);
- return;
- }
if (len + 5 >= size) {
xmlChar *new_buf;
size_t new_size;
@@ -4839,6 +4846,13 @@ xmlParseCommentComplex(xmlParserCtxtPtr ctxt, xmlChar *buf,
GROW;
cur = CUR_CHAR(l);
}
+
+ if (len > maxLength) {
+ xmlFatalErrMsgStr(ctxt, XML_ERR_COMMENT_NOT_FINISHED,
+ "Comment too big found", NULL);
+ xmlFree (buf);
+ return;
+ }
}
buf[len] = 0;
if (cur == 0) {
@@ -4883,6 +4897,9 @@ xmlParseComment(xmlParserCtxtPtr ctxt) {
xmlChar *buf = NULL;
size_t size = XML_PARSER_BUFFER_SIZE;
size_t len = 0;
+ size_t maxLength = (ctxt->options & XML_PARSE_HUGE) ?
+ XML_MAX_HUGE_LENGTH :
+ XML_MAX_TEXT_LENGTH;
xmlParserInputState state;
const xmlChar *in;
size_t nbchar = 0;
@@ -4966,8 +4983,7 @@ get_more:
buf[len] = 0;
}
}
- if ((len > XML_MAX_TEXT_LENGTH) &&
- ((ctxt->options & XML_PARSE_HUGE) == 0)) {
+ if (len > maxLength) {
xmlFatalErrMsgStr(ctxt, XML_ERR_COMMENT_NOT_FINISHED,
"Comment too big found", NULL);
xmlFree (buf);
@@ -5167,6 +5183,9 @@ xmlParsePI(xmlParserCtxtPtr ctxt) {
xmlChar *buf = NULL;
size_t len = 0;
size_t size = XML_PARSER_BUFFER_SIZE;
+ size_t maxLength = (ctxt->options & XML_PARSE_HUGE) ?
+ XML_MAX_HUGE_LENGTH :
+ XML_MAX_TEXT_LENGTH;
int cur, l;
const xmlChar *target;
xmlParserInputState state;
@@ -5242,14 +5261,6 @@ xmlParsePI(xmlParserCtxtPtr ctxt) {
return;
}
count = 0;
- if ((len > XML_MAX_TEXT_LENGTH) &&
- ((ctxt->options & XML_PARSE_HUGE) == 0)) {
- xmlFatalErrMsgStr(ctxt, XML_ERR_PI_NOT_FINISHED,
- "PI %s too big found", target);
- xmlFree(buf);
- ctxt->instate = state;
- return;
- }
}
COPY_BUF(l,buf,len,cur);
NEXTL(l);
@@ -5259,15 +5270,14 @@ xmlParsePI(xmlParserCtxtPtr ctxt) {
GROW;
cur = CUR_CHAR(l);
}
+ if (len > maxLength) {
+ xmlFatalErrMsgStr(ctxt, XML_ERR_PI_NOT_FINISHED,
+ "PI %s too big found", target);
+ xmlFree(buf);
+ ctxt->instate = state;
+ return;
+ }
}
- if ((len > XML_MAX_TEXT_LENGTH) &&
- ((ctxt->options & XML_PARSE_HUGE) == 0)) {
- xmlFatalErrMsgStr(ctxt, XML_ERR_PI_NOT_FINISHED,
- "PI %s too big found", target);
- xmlFree(buf);
- ctxt->instate = state;
- return;
- }
buf[len] = 0;
if (cur != '?') {
xmlFatalErrMsgStr(ctxt, XML_ERR_PI_NOT_FINISHED,
@@ -8959,6 +8969,9 @@ xmlParseAttValueInternal(xmlParserCtxtPtr ctxt, int *len, int *alloc,
const xmlChar *in = NULL, *start, *end, *last;
xmlChar *ret = NULL;
int line, col;
+ int maxLength = (ctxt->options & XML_PARSE_HUGE) ?
+ XML_MAX_HUGE_LENGTH :
+ XML_MAX_TEXT_LENGTH;
GROW;
in = (xmlChar *) CUR_PTR;
@@ -8998,8 +9011,7 @@ xmlParseAttValueInternal(xmlParserCtxtPtr ctxt, int *len, int *alloc,
start = in;
if (in >= end) {
GROW_PARSE_ATT_VALUE_INTERNAL(ctxt, in, start, end)
- if (((in - start) > XML_MAX_TEXT_LENGTH) &&
- ((ctxt->options & XML_PARSE_HUGE) == 0)) {
+ if ((in - start) > maxLength) {
xmlFatalErrMsg(ctxt, XML_ERR_ATTRIBUTE_NOT_FINISHED,
"AttValue length too long\n");
return(NULL);
@@ -9012,8 +9024,7 @@ xmlParseAttValueInternal(xmlParserCtxtPtr ctxt, int *len, int *alloc,
if ((*in++ == 0x20) && (*in == 0x20)) break;
if (in >= end) {
GROW_PARSE_ATT_VALUE_INTERNAL(ctxt, in, start, end)
- if (((in - start) > XML_MAX_TEXT_LENGTH) &&
- ((ctxt->options & XML_PARSE_HUGE) == 0)) {
+ if ((in - start) > maxLength) {
xmlFatalErrMsg(ctxt, XML_ERR_ATTRIBUTE_NOT_FINISHED,
"AttValue length too long\n");
return(NULL);
@@ -9046,16 +9057,14 @@ xmlParseAttValueInternal(xmlParserCtxtPtr ctxt, int *len, int *alloc,
last = last + delta;
}
end = ctxt->input->end;
- if (((in - start) > XML_MAX_TEXT_LENGTH) &&
- ((ctxt->options & XML_PARSE_HUGE) == 0)) {
+ if ((in - start) > maxLength) {
xmlFatalErrMsg(ctxt, XML_ERR_ATTRIBUTE_NOT_FINISHED,
"AttValue length too long\n");
return(NULL);
}
}
}
- if (((in - start) > XML_MAX_TEXT_LENGTH) &&
- ((ctxt->options & XML_PARSE_HUGE) == 0)) {
+ if ((in - start) > maxLength) {
xmlFatalErrMsg(ctxt, XML_ERR_ATTRIBUTE_NOT_FINISHED,
"AttValue length too long\n");
return(NULL);
@@ -9068,8 +9077,7 @@ xmlParseAttValueInternal(xmlParserCtxtPtr ctxt, int *len, int *alloc,
col++;
if (in >= end) {
GROW_PARSE_ATT_VALUE_INTERNAL(ctxt, in, start, end)
- if (((in - start) > XML_MAX_TEXT_LENGTH) &&
- ((ctxt->options & XML_PARSE_HUGE) == 0)) {
+ if ((in - start) > maxLength) {
xmlFatalErrMsg(ctxt, XML_ERR_ATTRIBUTE_NOT_FINISHED,
"AttValue length too long\n");
return(NULL);
@@ -9077,8 +9085,7 @@ xmlParseAttValueInternal(xmlParserCtxtPtr ctxt, int *len, int *alloc,
}
}
last = in;
- if (((in - start) > XML_MAX_TEXT_LENGTH) &&
- ((ctxt->options & XML_PARSE_HUGE) == 0)) {
+ if ((in - start) > maxLength) {
xmlFatalErrMsg(ctxt, XML_ERR_ATTRIBUTE_NOT_FINISHED,
"AttValue length too long\n");
return(NULL);
@@ -9768,6 +9775,9 @@ xmlParseCDSect(xmlParserCtxtPtr ctxt) {
int s, sl;
int cur, l;
int count = 0;
+ int maxLength = (ctxt->options & XML_PARSE_HUGE) ?
+ XML_MAX_HUGE_LENGTH :
+ XML_MAX_TEXT_LENGTH;
/* Check 2.6.0 was NXT(0) not RAW */
if (CMP9(CUR_PTR, '<', '!', '[', 'C', 'D', 'A', 'T', 'A', '[')) {
@@ -9801,13 +9811,6 @@ xmlParseCDSect(xmlParserCtxtPtr ctxt) {
if (len + 5 >= size) {
xmlChar *tmp;
- if ((size > XML_MAX_TEXT_LENGTH) &&
- ((ctxt->options & XML_PARSE_HUGE) == 0)) {
- xmlFatalErrMsgStr(ctxt, XML_ERR_CDATA_NOT_FINISHED,
- "CData section too big found", NULL);
- xmlFree (buf);
- return;
- }
tmp = (xmlChar *) xmlRealloc(buf, size * 2 * sizeof(xmlChar));
if (tmp == NULL) {
xmlFree(buf);
@@ -9834,6 +9837,12 @@ xmlParseCDSect(xmlParserCtxtPtr ctxt) {
}
NEXTL(l);
cur = CUR_CHAR(l);
+ if (len > maxLength) {
+ xmlFatalErrMsg(ctxt, XML_ERR_CDATA_NOT_FINISHED,
+ "CData section too big found\n");
+ xmlFree(buf);
+ return;
+ }
}
buf[len] = 0;
ctxt->instate = XML_PARSER_CONTENT;

View File

@ -0,0 +1,101 @@
From 644a89e080bced793295f61f18aac8cfad6bece2 Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
Date: Wed, 31 Aug 2022 22:11:25 +0200
Subject: [PATCH] [CVE-2022-40304] Fix dict corruption caused by entity
reference cycles
When an entity reference cycle is detected, the entity content is
cleared by setting its first byte to zero. But the entity content might
be allocated from a dict. In this case, the dict entry becomes corrupted
leading to all kinds of logic errors, including memory errors like
double-frees.
Stop storing entity content, orig, ExternalID and SystemID in a dict.
These values are unlikely to occur multiple times in a document, so they
shouldn't have been stored in a dict in the first place.
Thanks to Ned Williamson and Nathan Wachholz working with Google Project
Zero for the report!
---
entities.c | 55 ++++++++++++++++--------------------------------------
1 file changed, 16 insertions(+), 39 deletions(-)
diff --git a/entities.c b/entities.c
index 7876f708..063a02fa 100644
--- a/entities.c
+++ b/entities.c
@@ -129,36 +129,19 @@ xmlFreeEntity(xmlEntityPtr entity)
if ((entity->children) && (entity->owner == 1) &&
(entity == (xmlEntityPtr) entity->children->parent))
xmlFreeNodeList(entity->children);
- if (dict != NULL) {
- if ((entity->name != NULL) && (!xmlDictOwns(dict, entity->name)))
- xmlFree((char *) entity->name);
- if ((entity->ExternalID != NULL) &&
- (!xmlDictOwns(dict, entity->ExternalID)))
- xmlFree((char *) entity->ExternalID);
- if ((entity->SystemID != NULL) &&
- (!xmlDictOwns(dict, entity->SystemID)))
- xmlFree((char *) entity->SystemID);
- if ((entity->URI != NULL) && (!xmlDictOwns(dict, entity->URI)))
- xmlFree((char *) entity->URI);
- if ((entity->content != NULL)
- && (!xmlDictOwns(dict, entity->content)))
- xmlFree((char *) entity->content);
- if ((entity->orig != NULL) && (!xmlDictOwns(dict, entity->orig)))
- xmlFree((char *) entity->orig);
- } else {
- if (entity->name != NULL)
- xmlFree((char *) entity->name);
- if (entity->ExternalID != NULL)
- xmlFree((char *) entity->ExternalID);
- if (entity->SystemID != NULL)
- xmlFree((char *) entity->SystemID);
- if (entity->URI != NULL)
- xmlFree((char *) entity->URI);
- if (entity->content != NULL)
- xmlFree((char *) entity->content);
- if (entity->orig != NULL)
- xmlFree((char *) entity->orig);
- }
+ if ((entity->name != NULL) &&
+ ((dict == NULL) || (!xmlDictOwns(dict, entity->name))))
+ xmlFree((char *) entity->name);
+ if (entity->ExternalID != NULL)
+ xmlFree((char *) entity->ExternalID);
+ if (entity->SystemID != NULL)
+ xmlFree((char *) entity->SystemID);
+ if (entity->URI != NULL)
+ xmlFree((char *) entity->URI);
+ if (entity->content != NULL)
+ xmlFree((char *) entity->content);
+ if (entity->orig != NULL)
+ xmlFree((char *) entity->orig);
xmlFree(entity);
}
@@ -194,18 +177,12 @@ xmlCreateEntity(xmlDictPtr dict, const xmlChar *name, int type,
ret->SystemID = xmlStrdup(SystemID);
} else {
ret->name = xmlDictLookup(dict, name, -1);
- if (ExternalID != NULL)
- ret->ExternalID = xmlDictLookup(dict, ExternalID, -1);
- if (SystemID != NULL)
- ret->SystemID = xmlDictLookup(dict, SystemID, -1);
+ ret->ExternalID = xmlStrdup(ExternalID);
+ ret->SystemID = xmlStrdup(SystemID);
}
if (content != NULL) {
ret->length = xmlStrlen(content);
- if ((dict != NULL) && (ret->length < 5))
- ret->content = (xmlChar *)
- xmlDictLookup(dict, content, ret->length);
- else
- ret->content = xmlStrndup(content, ret->length);
+ ret->content = xmlStrndup(content, ret->length);
} else {
ret->length = 0;
ret->content = NULL;
--
GitLab