Fixed bz#2232359, CVE-2023-37369 qtbase: buffer overflow in QXmlStreamReader

This commit is contained in:
Than Ngo 2023-08-16 15:59:07 +02:00
parent f80d31e4bc
commit 829747ee2b
2 changed files with 210 additions and 1 deletions

View File

@ -0,0 +1,203 @@
diff --git a/src/corelib/serialization/qxmlstream.cpp b/src/corelib/serialization/qxmlstream.cpp
index 7cd457ba3a..11d162cb79 100644
--- a/src/corelib/serialization/qxmlstream.cpp
+++ b/src/corelib/serialization/qxmlstream.cpp
@@ -1302,15 +1302,18 @@ inline int QXmlStreamReaderPrivate::fastScanContentCharList()
return n;
}
-inline int QXmlStreamReaderPrivate::fastScanName(int *prefix)
+// Fast scan an XML attribute name (e.g. "xml:lang").
+inline QXmlStreamReaderPrivate::FastScanNameResult
+QXmlStreamReaderPrivate::fastScanName(Value *val)
{
int n = 0;
uint c;
while ((c = getChar()) != StreamEOF) {
if (n >= 4096) {
// This is too long to be a sensible name, and
- // can exhaust memory
- return 0;
+ // can exhaust memory, or the range of decltype(*prefix)
+ raiseNamePrefixTooLongError();
+ return {};
}
switch (c) {
case '\n':
@@ -1339,23 +1342,23 @@ inline int QXmlStreamReaderPrivate::fastScanName(int *prefix)
case '+':
case '*':
putChar(c);
- if (prefix && *prefix == n+1) {
- *prefix = 0;
+ if (val && val->prefix == n + 1) {
+ val->prefix = 0;
putChar(':');
--n;
}
- return n;
+ return FastScanNameResult(n);
case ':':
- if (prefix) {
- if (*prefix == 0) {
- *prefix = n+2;
+ if (val) {
+ if (val->prefix == 0) {
+ val->prefix = n + 2;
} else { // only one colon allowed according to the namespace spec.
putChar(c);
- return n;
+ return FastScanNameResult(n);
}
} else {
putChar(c);
- return n;
+ return FastScanNameResult(n);
}
Q_FALLTHROUGH();
default:
@@ -1364,12 +1367,12 @@ inline int QXmlStreamReaderPrivate::fastScanName(int *prefix)
}
}
- if (prefix)
- *prefix = 0;
+ if (val)
+ val->prefix = 0;
int pos = textBuffer.size() - n;
putString(textBuffer, pos);
textBuffer.resize(pos);
- return 0;
+ return FastScanNameResult(0);
}
enum NameChar { NameBeginning, NameNotBeginning, NotName };
@@ -1878,6 +1881,14 @@ void QXmlStreamReaderPrivate::raiseWellFormedError(const QString &message)
raiseError(QXmlStreamReader::NotWellFormedError, message);
}
+void QXmlStreamReaderPrivate::raiseNamePrefixTooLongError()
+{
+ // TODO: add a ImplementationLimitsExceededError and use it instead
+ raiseError(QXmlStreamReader::NotWellFormedError,
+ QXmlStream::tr("Length of XML attribute name exceeds implemnetation limits (4KiB "
+ "characters)."));
+}
+
void QXmlStreamReaderPrivate::parseError()
{
diff --git a/src/corelib/serialization/qxmlstream.g b/src/corelib/serialization/qxmlstream.g
index 4321fed68a..8c6a1a5887 100644
--- a/src/corelib/serialization/qxmlstream.g
+++ b/src/corelib/serialization/qxmlstream.g
@@ -516,7 +516,16 @@ public:
int fastScanLiteralContent();
int fastScanSpace();
int fastScanContentCharList();
- int fastScanName(int *prefix = nullptr);
+
+ struct FastScanNameResult {
+ FastScanNameResult() : ok(false) {}
+ explicit FastScanNameResult(int len) : addToLen(len), ok(true) { }
+ operator bool() { return ok; }
+ int operator*() { Q_ASSERT(ok); return addToLen; }
+ int addToLen;
+ bool ok;
+ };
+ FastScanNameResult fastScanName(Value *val = nullptr);
inline int fastScanNMTOKEN();
@@ -525,6 +534,7 @@ public:
void raiseError(QXmlStreamReader::Error error, const QString& message = QString());
void raiseWellFormedError(const QString &message);
+ void raiseNamePrefixTooLongError();
QXmlStreamEntityResolver *entityResolver;
@@ -1811,7 +1821,12 @@ space_opt ::= space;
qname ::= LETTER;
/.
case $rule_number: {
- sym(1).len += fastScanName(&sym(1).prefix);
+ Value &val = sym(1);
+ if (auto res = fastScanName(&val))
+ val.len += *res;
+ else
+ return false;
+
if (atEnd) {
resume($rule_number);
return false;
@@ -1822,7 +1837,11 @@ qname ::= LETTER;
name ::= LETTER;
/.
case $rule_number:
- sym(1).len += fastScanName();
+ if (auto res = fastScanName())
+ sym(1).len += *res;
+ else
+ return false;
+
if (atEnd) {
resume($rule_number);
return false;
diff --git a/src/corelib/serialization/qxmlstream_p.h b/src/corelib/serialization/qxmlstream_p.h
index e5bde7b98e..b01484cac3 100644
--- a/src/corelib/serialization/qxmlstream_p.h
+++ b/src/corelib/serialization/qxmlstream_p.h
@@ -1005,7 +1005,16 @@ public:
int fastScanLiteralContent();
int fastScanSpace();
int fastScanContentCharList();
- int fastScanName(int *prefix = nullptr);
+
+ struct FastScanNameResult {
+ FastScanNameResult() : ok(false) {}
+ explicit FastScanNameResult(int len) : addToLen(len), ok(true) { }
+ operator bool() { return ok; }
+ int operator*() { Q_ASSERT(ok); return addToLen; }
+ int addToLen;
+ bool ok;
+ };
+ FastScanNameResult fastScanName(Value *val = nullptr);
inline int fastScanNMTOKEN();
@@ -1014,6 +1023,7 @@ public:
void raiseError(QXmlStreamReader::Error error, const QString& message = QString());
void raiseWellFormedError(const QString &message);
+ void raiseNamePrefixTooLongError();
QXmlStreamEntityResolver *entityResolver;
@@ -1939,7 +1949,12 @@ bool QXmlStreamReaderPrivate::parse()
break;
case 262: {
- sym(1).len += fastScanName(&sym(1).prefix);
+ Value &val = sym(1);
+ if (auto res = fastScanName(&val))
+ val.len += *res;
+ else
+ return false;
+
if (atEnd) {
resume(262);
return false;
@@ -1947,7 +1962,11 @@ bool QXmlStreamReaderPrivate::parse()
} break;
case 263:
- sym(1).len += fastScanName();
+ if (auto res = fastScanName())
+ sym(1).len += *res;
+ else
+ return false;
+
if (atEnd) {
resume(263);
return false;

View File

@ -57,7 +57,7 @@
Name: qt5-qtbase Name: qt5-qtbase
Summary: Qt5 - QtBase components Summary: Qt5 - QtBase components
Version: 5.15.10 Version: 5.15.10
Release: 4%{?dist} Release: 5%{?dist}
# See LGPL_EXCEPTIONS.txt, for exception details # See LGPL_EXCEPTIONS.txt, for exception details
License: LGPL-3.0-only OR GPL-3.0-only WITH Qt-GPL-exception-1.0 License: LGPL-3.0-only OR GPL-3.0-only WITH Qt-GPL-exception-1.0
@ -151,6 +151,8 @@ Patch103: qtbase-QTBUG-112136.patch
# https://bugreports.qt.io/browse/QTBUG-103393 # https://bugreports.qt.io/browse/QTBUG-103393
Patch104: qtbase-QTBUG-103393.patch Patch104: qtbase-QTBUG-103393.patch
# upstream security fixes
Patch150: CVE-2023-37369-qtbase-5.15.diff
# Do not check any files in %%{_qt5_plugindir}/platformthemes/ for requires. # Do not check any files in %%{_qt5_plugindir}/platformthemes/ for requires.
# Those themes are there for platform integration. If the required libraries are # Those themes are there for platform integration. If the required libraries are
@ -432,6 +434,7 @@ Qt5 libraries used for drawing widgets and OpenGL items.
%patch -P102 -p1 %patch -P102 -p1
%patch -P103 -p1 %patch -P103 -p1
%patch -P104 -p1 %patch -P104 -p1
%patch -P150 -p1
# move some bundled libs to ensure they're not accidentally used # move some bundled libs to ensure they're not accidentally used
pushd src/3rdparty pushd src/3rdparty
@ -1111,6 +1114,9 @@ fi
%changelog %changelog
* Wed Aug 16 2023 Than Ngo <than@redhat.com> - 5.15.10-5
- Fixed bz#2232359, CVE-2023-37369 qtbase: buffer overflow in QXmlStreamReader
* Fri Jul 21 2023 Fedora Release Engineering <releng@fedoraproject.org> - 5.15.10-4 * Fri Jul 21 2023 Fedora Release Engineering <releng@fedoraproject.org> - 5.15.10-4
- Rebuilt for https://fedoraproject.org/wiki/Fedora_39_Mass_Rebuild - Rebuilt for https://fedoraproject.org/wiki/Fedora_39_Mass_Rebuild