Compare commits
10 Commits
6d2b7426c0
...
ef711c9a38
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ef711c9a38 | ||
|
|
b909fad45d | ||
|
|
7981f583be | ||
|
|
6263a803ea | ||
|
|
49d2e2863d | ||
|
|
8599b82591 | ||
|
|
bd6017e999 | ||
|
|
48fc7145fc | ||
|
|
bcf7713937 | ||
|
|
1271181beb |
31
CVE-2023-45935.patch
Normal file
31
CVE-2023-45935.patch
Normal file
@ -0,0 +1,31 @@
|
||||
From b349ef7d08deb9d7ee64cf161fdf3a92b0f3f706 Mon Sep 17 00:00:00 2001
|
||||
From: Liang Qi <liang.qi@qt.io>
|
||||
Date: 2023-07-31 05:35:11 +0200
|
||||
Subject: [PATCH] CVE-2023-45935
|
||||
|
||||
port invokeMethodImpl() from QScopeGuard to SlotObjUniquePtr
|
||||
|
||||
---
|
||||
src/plugins/platforms/xcb/qxcbatom.cpp | 6 ++++--
|
||||
1 file changed, 4 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/src/plugins/platforms/xcb/qxcbatom.cpp b/src/plugins/platforms/xcb/qxcbatom.cpp
|
||||
index 78081660..11d356dd 100644
|
||||
--- a/src/plugins/platforms/xcb/qxcbatom.cpp
|
||||
+++ b/src/plugins/platforms/xcb/qxcbatom.cpp
|
||||
@@ -268,8 +268,10 @@ void QXcbAtom::initializeAllAtoms(xcb_connection_t *connection) {
|
||||
|
||||
for (i = 0; i < QXcbAtom::NAtoms; ++i) {
|
||||
xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(connection, cookies[i], nullptr);
|
||||
- m_allAtoms[i] = reply->atom;
|
||||
- free(reply);
|
||||
+ if (reply) {
|
||||
+ m_allAtoms[i] = reply->atom;
|
||||
+ free(reply);
|
||||
+ }
|
||||
}
|
||||
}
|
||||
|
||||
--
|
||||
2.27.0
|
||||
|
||||
197
CVE-2024-25580-qtbase-5.15.diff
Normal file
197
CVE-2024-25580-qtbase-5.15.diff
Normal file
@ -0,0 +1,197 @@
|
||||
diff --git a/src/gui/util/qktxhandler.cpp b/src/gui/util/qktxhandler.cpp
|
||||
index 0d98e97453..6a79e55109 100644
|
||||
--- a/src/gui/util/qktxhandler.cpp
|
||||
+++ b/src/gui/util/qktxhandler.cpp
|
||||
@@ -73,7 +73,7 @@ struct KTXHeader {
|
||||
quint32 bytesOfKeyValueData;
|
||||
};
|
||||
|
||||
-static const quint32 headerSize = sizeof(KTXHeader);
|
||||
+static constexpr quint32 qktxh_headerSize = sizeof(KTXHeader);
|
||||
|
||||
// Currently unused, declared for future reference
|
||||
struct KTXKeyValuePairItem {
|
||||
@@ -103,11 +103,36 @@ struct KTXMipmapLevel {
|
||||
*/
|
||||
};
|
||||
|
||||
-bool QKtxHandler::canRead(const QByteArray &suffix, const QByteArray &block)
|
||||
+static bool qAddOverflow(quint32 v1, quint32 v2, quint32 *r) {
|
||||
+ // unsigned additions are well-defined
|
||||
+ *r = v1 + v2;
|
||||
+ return v1 > quint32(v1 + v2);
|
||||
+}
|
||||
+
|
||||
+// Returns the nearest multiple of 4 greater than or equal to 'value'
|
||||
+static bool nearestMultipleOf4(quint32 value, quint32 *result)
|
||||
+{
|
||||
+ constexpr quint32 rounding = 4;
|
||||
+ *result = 0;
|
||||
+ if (qAddOverflow(value, rounding - 1, result))
|
||||
+ return true;
|
||||
+ *result &= ~(rounding - 1);
|
||||
+ return false;
|
||||
+}
|
||||
+
|
||||
+// Returns a slice with prechecked bounds
|
||||
+static QByteArray safeSlice(const QByteArray& array, quint32 start, quint32 length)
|
||||
{
|
||||
- Q_UNUSED(suffix)
|
||||
+ quint32 end = 0;
|
||||
+ if (qAddOverflow(start, length, &end) || end > quint32(array.length()))
|
||||
+ return {};
|
||||
+ return QByteArray(array.data() + start, length);
|
||||
+}
|
||||
|
||||
- return (qstrncmp(block.constData(), ktxIdentifier, KTX_IDENTIFIER_LENGTH) == 0);
|
||||
+bool QKtxHandler::canRead(const QByteArray &suffix, const QByteArray &block)
|
||||
+{
|
||||
+ Q_UNUSED(suffix);
|
||||
+ return block.startsWith(QByteArray::fromRawData(ktxIdentifier, KTX_IDENTIFIER_LENGTH));
|
||||
}
|
||||
|
||||
QTextureFileData QKtxHandler::read()
|
||||
@@ -115,42 +140,97 @@ QTextureFileData QKtxHandler::read()
|
||||
if (!device())
|
||||
return QTextureFileData();
|
||||
|
||||
- QByteArray buf = device()->readAll();
|
||||
- const quint32 dataSize = quint32(buf.size());
|
||||
- if (dataSize < headerSize || !canRead(QByteArray(), buf)) {
|
||||
- qCDebug(lcQtGuiTextureIO, "Invalid KTX file %s", logName().constData());
|
||||
+ const QByteArray buf = device()->readAll();
|
||||
+ if (size_t(buf.size()) > std::numeric_limits<quint32>::max()) {
|
||||
+ qWarning(lcQtGuiTextureIO, "Too big KTX file %s", logName().constData());
|
||||
+ return QTextureFileData();
|
||||
+ }
|
||||
+
|
||||
+ if (!canRead(QByteArray(), buf)) {
|
||||
+ qWarning(lcQtGuiTextureIO, "Invalid KTX file %s", logName().constData());
|
||||
+ return QTextureFileData();
|
||||
+ }
|
||||
+
|
||||
+ if (buf.size() < qsizetype(qktxh_headerSize)) {
|
||||
+ qWarning(lcQtGuiTextureIO, "Invalid KTX header size in %s", logName().constData());
|
||||
return QTextureFileData();
|
||||
}
|
||||
|
||||
- const KTXHeader *header = reinterpret_cast<const KTXHeader *>(buf.constData());
|
||||
- if (!checkHeader(*header)) {
|
||||
- qCDebug(lcQtGuiTextureIO, "Unsupported KTX file format in %s", logName().constData());
|
||||
+ KTXHeader header;
|
||||
+ memcpy(&header, buf.data(), qktxh_headerSize);
|
||||
+ if (!checkHeader(header)) {
|
||||
+ qWarning(lcQtGuiTextureIO, "Unsupported KTX file format in %s", logName().constData());
|
||||
return QTextureFileData();
|
||||
}
|
||||
|
||||
QTextureFileData texData;
|
||||
texData.setData(buf);
|
||||
|
||||
- texData.setSize(QSize(decode(header->pixelWidth), decode(header->pixelHeight)));
|
||||
- texData.setGLFormat(decode(header->glFormat));
|
||||
- texData.setGLInternalFormat(decode(header->glInternalFormat));
|
||||
- texData.setGLBaseInternalFormat(decode(header->glBaseInternalFormat));
|
||||
-
|
||||
- texData.setNumLevels(decode(header->numberOfMipmapLevels));
|
||||
- quint32 offset = headerSize + decode(header->bytesOfKeyValueData);
|
||||
- const int maxLevels = qMin(texData.numLevels(), 32); // Cap iterations in case of corrupt file.
|
||||
- for (int i = 0; i < maxLevels; i++) {
|
||||
- if (offset + sizeof(KTXMipmapLevel) > dataSize) // Corrupt file; avoid oob read
|
||||
- break;
|
||||
- const KTXMipmapLevel *level = reinterpret_cast<const KTXMipmapLevel *>(buf.constData() + offset);
|
||||
- quint32 levelLen = decode(level->imageSize);
|
||||
- texData.setDataOffset(offset + sizeof(KTXMipmapLevel::imageSize), i);
|
||||
- texData.setDataLength(levelLen, i);
|
||||
- offset += sizeof(KTXMipmapLevel::imageSize) + levelLen + (3 - ((levelLen + 3) % 4));
|
||||
+ texData.setSize(QSize(decode(header.pixelWidth), decode(header.pixelHeight)));
|
||||
+ texData.setGLFormat(decode(header.glFormat));
|
||||
+ texData.setGLInternalFormat(decode(header.glInternalFormat));
|
||||
+ texData.setGLBaseInternalFormat(decode(header.glBaseInternalFormat));
|
||||
+
|
||||
+ texData.setNumLevels(decode(header.numberOfMipmapLevels));
|
||||
+
|
||||
+ const quint32 bytesOfKeyValueData = decode(header.bytesOfKeyValueData);
|
||||
+ quint32 headerKeyValueSize;
|
||||
+ if (qAddOverflow(qktxh_headerSize, bytesOfKeyValueData, &headerKeyValueSize)) {
|
||||
+ qWarning(lcQtGuiTextureIO, "Overflow in size of key value data in header of KTX file %s",
|
||||
+ logName().constData());
|
||||
+ return QTextureFileData();
|
||||
+ }
|
||||
+
|
||||
+ if (headerKeyValueSize >= quint32(buf.size())) {
|
||||
+ qWarning(lcQtGuiTextureIO, "OOB request in KTX file %s", logName().constData());
|
||||
+ return QTextureFileData();
|
||||
+ }
|
||||
+
|
||||
+ // Technically, any number of levels is allowed but if the value is bigger than
|
||||
+ // what is possible in KTX V2 (and what makes sense) we return an error.
|
||||
+ // maxLevels = log2(max(width, height, depth))
|
||||
+ const int maxLevels = (sizeof(quint32) * 8)
|
||||
+ - qCountLeadingZeroBits(std::max(
|
||||
+ { header.pixelWidth, header.pixelHeight, header.pixelDepth }));
|
||||
+
|
||||
+ if (texData.numLevels() > maxLevels) {
|
||||
+ qWarning(lcQtGuiTextureIO, "Too many levels in KTX file %s", logName().constData());
|
||||
+ return QTextureFileData();
|
||||
+ }
|
||||
+
|
||||
+ quint32 offset = headerKeyValueSize;
|
||||
+ for (int level = 0; level < texData.numLevels(); level++) {
|
||||
+ const auto imageSizeSlice = safeSlice(buf, offset, sizeof(quint32));
|
||||
+ if (imageSizeSlice.isEmpty()) {
|
||||
+ qWarning(lcQtGuiTextureIO, "OOB request in KTX file %s", logName().constData());
|
||||
+ return QTextureFileData();
|
||||
+ }
|
||||
+
|
||||
+ const quint32 imageSize = decode(qFromUnaligned<quint32>(imageSizeSlice.data()));
|
||||
+ offset += sizeof(quint32); // overflow checked indirectly above
|
||||
+
|
||||
+ texData.setDataOffset(offset, level);
|
||||
+ texData.setDataLength(imageSize, level);
|
||||
+
|
||||
+ // Add image data and padding to offset
|
||||
+ quint32 padded = 0;
|
||||
+ if (nearestMultipleOf4(imageSize, &padded)) {
|
||||
+ qWarning(lcQtGuiTextureIO, "Overflow in KTX file %s", logName().constData());
|
||||
+ return QTextureFileData();
|
||||
+ }
|
||||
+
|
||||
+ quint32 offsetNext;
|
||||
+ if (qAddOverflow(offset, padded, &offsetNext)) {
|
||||
+ qWarning(lcQtGuiTextureIO, "OOB request in KTX file %s", logName().constData());
|
||||
+ return QTextureFileData();
|
||||
+ }
|
||||
+
|
||||
+ offset = offsetNext;
|
||||
}
|
||||
|
||||
if (!texData.isValid()) {
|
||||
- qCDebug(lcQtGuiTextureIO, "Invalid values in header of KTX file %s", logName().constData());
|
||||
+ qWarning(lcQtGuiTextureIO, "Invalid values in header of KTX file %s",
|
||||
+ logName().constData());
|
||||
return QTextureFileData();
|
||||
}
|
||||
|
||||
@@ -191,7 +271,7 @@ bool QKtxHandler::checkHeader(const KTXHeader &header)
|
||||
(decode(header.numberOfFaces) == 1));
|
||||
}
|
||||
|
||||
-quint32 QKtxHandler::decode(quint32 val)
|
||||
+quint32 QKtxHandler::decode(quint32 val) const
|
||||
{
|
||||
return inverseEndian ? qbswap<quint32>(val) : val;
|
||||
}
|
||||
diff --git a/src/gui/util/qktxhandler_p.h b/src/gui/util/qktxhandler_p.h
|
||||
index f831e59d95..cdf1b2eaf8 100644
|
||||
--- a/src/gui/util/qktxhandler_p.h
|
||||
+++ b/src/gui/util/qktxhandler_p.h
|
||||
@@ -68,7 +68,7 @@ public:
|
||||
|
||||
private:
|
||||
bool checkHeader(const KTXHeader &header);
|
||||
- quint32 decode(quint32 val);
|
||||
+ quint32 decode(quint32 val) const;
|
||||
|
||||
bool inverseEndian = false;
|
||||
};
|
||||
@ -34,7 +34,7 @@ BuildRequires: pkgconfig(libsystemd)
|
||||
Name: qt5-qtbase
|
||||
Summary: Qt5 - QtBase components
|
||||
Version: 5.15.2
|
||||
Release: 11
|
||||
Release: 16
|
||||
|
||||
|
||||
# See LGPL_EXCEPTIONS.txt, for exception details
|
||||
@ -124,9 +124,16 @@ Patch0026: CVE-2023-37369-pre.patch
|
||||
Patch0027: CVE-2023-37369.patch
|
||||
Patch0028: CVE-2023-33285.patch
|
||||
Patch0029: qtbase5.15-CVE-2023-34410.patch
|
||||
|
||||
##https://codereview.qt-project.org/c/qt/qtbase/+/488960
|
||||
Patch0030: qtbase5.15.2-CVE-2023-38197.patch
|
||||
#https://codereview.qt-project.org/c/qt/qtbase/+/503026
|
||||
Patch0031: qtbase5.15.2-CVE-2023-43114.patch
|
||||
Patch0032: CVE-2024-25580-qtbase-5.15.diff
|
||||
|
||||
Patch1000: 1000-add-loongarch64-support-for-syscall_fork.patch
|
||||
Patch1001: 1001-add-sw_64-support-for-syscall_fork.patch
|
||||
Patch1002: qtbase5.15-CVE-2023-51714.patch
|
||||
Patch1003: CVE-2023-45935.patch
|
||||
|
||||
# Do not check any files in %%{_qt5_plugindir}/platformthemes/ for requires.
|
||||
# Those themes are there for platform integration. If the required libraries are
|
||||
@ -392,8 +399,13 @@ Qt5 libraries used for drawing widgets and OpenGL items.
|
||||
%patch0027 -p1
|
||||
%patch0028 -p1
|
||||
%patch0029 -p1
|
||||
%patch0030 -p1
|
||||
%patch0031 -p1
|
||||
%patch0032 -p1
|
||||
%patch1000 -p1
|
||||
%patch1001 -p1
|
||||
%patch1002 -p1
|
||||
%patch1003 -p1
|
||||
|
||||
# move some bundled libs to ensure they're not accidentally used
|
||||
pushd src/3rdparty
|
||||
@ -1036,6 +1048,21 @@ fi
|
||||
|
||||
|
||||
%changelog
|
||||
* Wed Apr 24 2024 lvfei <lvfei@kylinos.cn> - 5.15.2-16
|
||||
- Fix CVE-2023-45935
|
||||
|
||||
* Wed Apr 17 2024 peijiankang <peijiankang@kylinos.cn> - 5.15.2-15
|
||||
- add CVE-2024-25580-qtbase-5.15.diff
|
||||
|
||||
* Wed Jan 31 2024 douyan <douyan@kylinos.cn> - 5.15.2-14
|
||||
- add qtbase5.15-CVE-2023-51714.patch
|
||||
|
||||
* Sat Nov 25 2023 hua_yadong <huayadong@kylinos.cn> - 5.15.2-13
|
||||
- fix qtbase5.15.2-CVE-2023-43114.patch
|
||||
|
||||
* Fri Nov 24 2023 hua_yadong <huayadong@kylinos.cn> - 5.15.2-12
|
||||
- fix qtbase5.15.2-CVE-2023-38197.patch
|
||||
|
||||
* Thu Nov 02 2023 peijiankang <peijiankang@kylinos.cn> - 5.15.2-11
|
||||
- fix CVE-2023-34410
|
||||
|
||||
|
||||
37
qtbase5.15-CVE-2023-51714.patch
Normal file
37
qtbase5.15-CVE-2023-51714.patch
Normal file
@ -0,0 +1,37 @@
|
||||
From 061cbe5796a9ff1e998bd5753bb5b44e4481df11 Mon Sep 17 00:00:00 2001
|
||||
From: peijiankang <peijiankang@kylinos.cn>
|
||||
Date: Wed, 31 Jan 2024 13:38:10 +0800
|
||||
Subject: [PATCH] qtbase5.15-CVE-2023-51714
|
||||
|
||||
---
|
||||
src/network/access/http2/hpacktable.cpp | 7 +++++--
|
||||
1 file changed, 5 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/src/network/access/http2/hpacktable.cpp b/src/network/access/http2/hpacktable.cpp
|
||||
index fddb5fec..315f3e23 100644
|
||||
--- a/src/network/access/http2/hpacktable.cpp
|
||||
+++ b/src/network/access/http2/hpacktable.cpp
|
||||
@@ -40,6 +40,7 @@
|
||||
#include "hpacktable_p.h"
|
||||
|
||||
#include <QtCore/qdebug.h>
|
||||
+#include <QtCore/private/qnumeric_p.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
@@ -62,8 +63,10 @@ HeaderSize entry_size(const QByteArray &name, const QByteArray &value)
|
||||
// for counting the number of references to the name and value would have
|
||||
// 32 octets of overhead."
|
||||
|
||||
- const unsigned sum = unsigned(name.size() + value.size());
|
||||
- if (std::numeric_limits<unsigned>::max() - 32 < sum)
|
||||
+ size_t sum;
|
||||
+ if (add_overflow(size_t(name.size()), size_t(value.size()), &sum))
|
||||
+ return HeaderSize();
|
||||
+ if (sum > (std::numeric_limits<unsigned>::max() - 32))
|
||||
return HeaderSize();
|
||||
return HeaderSize(true, quint32(sum + 32));
|
||||
}
|
||||
--
|
||||
2.41.0
|
||||
|
||||
374
qtbase5.15.2-CVE-2023-38197.patch
Normal file
374
qtbase5.15.2-CVE-2023-38197.patch
Normal file
@ -0,0 +1,374 @@
|
||||
From 4fb3cf1ad0efe261a7a6fb0b36224baccc407143 Mon Sep 17 00:00:00 2001
|
||||
From: hua_yadong <huayadong@kylinos.cn>
|
||||
Date: Fri, 24 Nov 2023 14:23:58 +0800
|
||||
Subject: [PATCH] qtbase5.15.2-CVE-2023-38197
|
||||
|
||||
---
|
||||
src/corelib/serialization/qxmlstream.cpp | 140 +++++++++++++++++-
|
||||
src/corelib/serialization/qxmlstream_p.h | 11 ++
|
||||
.../qxmlstream/tokenError/dtdInBody.xml | 21 +++
|
||||
.../qxmlstream/tokenError/multipleDtd.xml | 21 +++
|
||||
.../qxmlstream/tokenError/wellFormed.xml | 16 ++
|
||||
.../qxmlstream/tst_qxmlstream.cpp | 39 +++++
|
||||
6 files changed, 240 insertions(+), 8 deletions(-)
|
||||
create mode 100644 tests/auto/corelib/serialization/qxmlstream/tokenError/dtdInBody.xml
|
||||
create mode 100644 tests/auto/corelib/serialization/qxmlstream/tokenError/multipleDtd.xml
|
||||
create mode 100644 tests/auto/corelib/serialization/qxmlstream/tokenError/wellFormed.xml
|
||||
|
||||
diff --git a/src/corelib/serialization/qxmlstream.cpp b/src/corelib/serialization/qxmlstream.cpp
|
||||
index 6c98e7c0..3172239e 100644
|
||||
--- a/src/corelib/serialization/qxmlstream.cpp
|
||||
+++ b/src/corelib/serialization/qxmlstream.cpp
|
||||
@@ -43,6 +43,7 @@
|
||||
|
||||
#include "qxmlutils_p.h"
|
||||
#include <qdebug.h>
|
||||
+#include <QtCore/private/qoffsetstringarray_p.h>
|
||||
#include <qfile.h>
|
||||
#include <stdio.h>
|
||||
#if QT_CONFIG(textcodec)
|
||||
@@ -160,7 +161,7 @@ enum { StreamEOF = ~0U };
|
||||
addData() or by waiting for it to arrive on the device().
|
||||
|
||||
\value UnexpectedElementError The parser encountered an element
|
||||
- that was different to those it expected.
|
||||
+ or token that was different to those it expected.
|
||||
|
||||
*/
|
||||
|
||||
@@ -295,13 +296,34 @@ QXmlStreamEntityResolver *QXmlStreamReader::entityResolver() const
|
||||
|
||||
QXmlStreamReader is a well-formed XML 1.0 parser that does \e not
|
||||
include external parsed entities. As long as no error occurs, the
|
||||
- application code can thus be assured that the data provided by the
|
||||
- stream reader satisfies the W3C's criteria for well-formed XML. For
|
||||
- example, you can be certain that all tags are indeed nested and
|
||||
- closed properly, that references to internal entities have been
|
||||
- replaced with the correct replacement text, and that attributes have
|
||||
- been normalized or added according to the internal subset of the
|
||||
- DTD.
|
||||
+ application code can thus be assured, that
|
||||
+ \list
|
||||
+ \li the data provided by the stream reader satisfies the W3C's
|
||||
+ criteria for well-formed XML,
|
||||
+ \li tokens are provided in a valid order.
|
||||
+ \endlist
|
||||
+
|
||||
+ Unless QXmlStreamReader raises an error, it guarantees the following:
|
||||
+ \list
|
||||
+ \li All tags are nested and closed properly.
|
||||
+ \li References to internal entities have been replaced with the
|
||||
+ correct replacement text.
|
||||
+ \li Attributes have been normalized or added according to the
|
||||
+ internal subset of the \l DTD.
|
||||
+ \li Tokens of type \l StartDocument happen before all others,
|
||||
+ aside from comments and processing instructions.
|
||||
+ \li At most one DOCTYPE element (a token of type \l DTD) is present.
|
||||
+ \li If present, the DOCTYPE appears before all other elements,
|
||||
+ aside from StartDocument, comments and processing instructions.
|
||||
+ \endlist
|
||||
+
|
||||
+ In particular, once any token of type \l StartElement, \l EndElement,
|
||||
+ \l Characters, \l EntityReference or \l EndDocument is seen, no
|
||||
+ tokens of type StartDocument or DTD will be seen. If one is present in
|
||||
+ the input stream, out of order, an error is raised.
|
||||
+
|
||||
+ \note The token types \l Comment and \l ProcessingInstruction may appear
|
||||
+ anywhere in the stream.
|
||||
|
||||
If an error occurs while parsing, atEnd() and hasError() return
|
||||
true, and error() returns the error that occurred. The functions
|
||||
@@ -620,6 +642,7 @@ QXmlStreamReader::TokenType QXmlStreamReader::readNext()
|
||||
d->token = -1;
|
||||
return readNext();
|
||||
}
|
||||
+ d->checkToken();
|
||||
return d->type;
|
||||
}
|
||||
|
||||
@@ -739,6 +762,10 @@ static const short QXmlStreamReader_tokenTypeString_indices[] = {
|
||||
0, 8, 16, 30, 42, 55, 66, 77, 85, 89, 105, 0
|
||||
};
|
||||
|
||||
+static constexpr auto QXmlStreamReader_XmlContextString = qOffsetStringArray(
|
||||
+ "Prolog",
|
||||
+ "Body"
|
||||
+);
|
||||
|
||||
/*!
|
||||
\property QXmlStreamReader::namespaceProcessing
|
||||
@@ -775,6 +802,15 @@ QString QXmlStreamReader::tokenString() const
|
||||
QXmlStreamReader_tokenTypeString_indices[d->type]);
|
||||
}
|
||||
|
||||
+/*!
|
||||
+ \internal
|
||||
+ \return \param loc (Prolog/Body) as a string.
|
||||
+ */
|
||||
+static constexpr QLatin1String contextString(QXmlStreamReaderPrivate::XmlContext ctxt)
|
||||
+{
|
||||
+ return QLatin1String(QXmlStreamReader_XmlContextString.at(static_cast<int>(ctxt)));
|
||||
+}
|
||||
+
|
||||
#endif // QT_NO_XMLSTREAMREADER
|
||||
|
||||
QXmlStreamPrivateTagStack::QXmlStreamPrivateTagStack()
|
||||
@@ -866,6 +902,8 @@ void QXmlStreamReaderPrivate::init()
|
||||
|
||||
type = QXmlStreamReader::NoToken;
|
||||
error = QXmlStreamReader::NoError;
|
||||
+ currentContext = XmlContext::Prolog;
|
||||
+ foundDTD = false;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -4061,6 +4099,92 @@ void QXmlStreamWriter::writeCurrentToken(const QXmlStreamReader &reader)
|
||||
}
|
||||
}
|
||||
|
||||
+static bool isTokenAllowedInContext(QXmlStreamReader::TokenType type,
|
||||
+ QXmlStreamReaderPrivate::XmlContext loc)
|
||||
+{
|
||||
+ switch (type) {
|
||||
+ case QXmlStreamReader::StartDocument:
|
||||
+ case QXmlStreamReader::DTD:
|
||||
+ return loc == QXmlStreamReaderPrivate::XmlContext::Prolog;
|
||||
+
|
||||
+ case QXmlStreamReader::StartElement:
|
||||
+ case QXmlStreamReader::EndElement:
|
||||
+ case QXmlStreamReader::Characters:
|
||||
+ case QXmlStreamReader::EntityReference:
|
||||
+ case QXmlStreamReader::EndDocument:
|
||||
+ return loc == QXmlStreamReaderPrivate::XmlContext::Body;
|
||||
+
|
||||
+ case QXmlStreamReader::Comment:
|
||||
+ case QXmlStreamReader::ProcessingInstruction:
|
||||
+ return true;
|
||||
+
|
||||
+ case QXmlStreamReader::NoToken:
|
||||
+ case QXmlStreamReader::Invalid:
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ return false;
|
||||
+}
|
||||
+
|
||||
+/*!
|
||||
+ \internal
|
||||
+ \brief QXmlStreamReader::isValidToken
|
||||
+ \return \c true if \param type is a valid token type.
|
||||
+ \return \c false if \param type is an unexpected token,
|
||||
+ which indicates a non-well-formed or invalid XML stream.
|
||||
+ */
|
||||
+bool QXmlStreamReaderPrivate::isValidToken(QXmlStreamReader::TokenType type)
|
||||
+{
|
||||
+ // Don't change currentContext, if Invalid or NoToken occur in the prolog
|
||||
+ if (type == QXmlStreamReader::Invalid || type == QXmlStreamReader::NoToken)
|
||||
+ return false;
|
||||
+
|
||||
+ // If a token type gets rejected in the body, there is no recovery
|
||||
+ const bool result = isTokenAllowedInContext(type, currentContext);
|
||||
+ if (result || currentContext == XmlContext::Body)
|
||||
+ return result;
|
||||
+
|
||||
+ // First non-Prolog token observed => switch context to body and check again.
|
||||
+ currentContext = XmlContext::Body;
|
||||
+ return isTokenAllowedInContext(type, currentContext);
|
||||
+}
|
||||
+
|
||||
+/*!
|
||||
+ \internal
|
||||
+ Checks token type and raises an error, if it is invalid
|
||||
+ in the current context (prolog/body).
|
||||
+ */
|
||||
+void QXmlStreamReaderPrivate::checkToken()
|
||||
+{
|
||||
+ Q_Q(QXmlStreamReader);
|
||||
+
|
||||
+ // The token type must be consumed, to keep track if the body has been reached.
|
||||
+ const XmlContext context = currentContext;
|
||||
+ const bool ok = isValidToken(type);
|
||||
+
|
||||
+ // Do nothing if an error has been raised already (going along with an unexpected token)
|
||||
+ if (error != QXmlStreamReader::Error::NoError)
|
||||
+ return;
|
||||
+
|
||||
+ if (!ok) {
|
||||
+ raiseError(QXmlStreamReader::UnexpectedElementError,
|
||||
+ QStringLiteral("Unexpected token type %1 in %2.")
|
||||
+ .arg(q->tokenString(), contextString(context)));
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ if (type != QXmlStreamReader::DTD)
|
||||
+ return;
|
||||
+
|
||||
+ // Raise error on multiple DTD tokens
|
||||
+ if (foundDTD) {
|
||||
+ raiseError(QXmlStreamReader::UnexpectedElementError,
|
||||
+ QStringLiteral("Found second DTD token in %1.").arg(contextString(context)));
|
||||
+ } else {
|
||||
+ foundDTD = true;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
/*!
|
||||
\fn bool QXmlStreamAttributes::hasAttribute(const QString &qualifiedName) const
|
||||
\since 4.5
|
||||
diff --git a/src/corelib/serialization/qxmlstream_p.h b/src/corelib/serialization/qxmlstream_p.h
|
||||
index 80e7f740..6db58386 100644
|
||||
--- a/src/corelib/serialization/qxmlstream_p.h
|
||||
+++ b/src/corelib/serialization/qxmlstream_p.h
|
||||
@@ -804,6 +804,17 @@ public:
|
||||
#endif
|
||||
bool atEnd;
|
||||
|
||||
+ enum class XmlContext
|
||||
+ {
|
||||
+ Prolog,
|
||||
+ Body,
|
||||
+ };
|
||||
+
|
||||
+ XmlContext currentContext = XmlContext::Prolog;
|
||||
+ bool foundDTD = false;
|
||||
+ bool isValidToken(QXmlStreamReader::TokenType type);
|
||||
+ void checkToken();
|
||||
+
|
||||
/*!
|
||||
\sa setType()
|
||||
*/
|
||||
diff --git a/tests/auto/corelib/serialization/qxmlstream/tokenError/dtdInBody.xml b/tests/auto/corelib/serialization/qxmlstream/tokenError/dtdInBody.xml
|
||||
new file mode 100644
|
||||
index 00000000..68ef2962
|
||||
--- /dev/null
|
||||
+++ b/tests/auto/corelib/serialization/qxmlstream/tokenError/dtdInBody.xml
|
||||
@@ -0,0 +1,21 @@
|
||||
+<!DOCTYPE TEST [
|
||||
+ <!ELEMENT TESTATTRIBUTE (CASE+)>
|
||||
+ <!ELEMENT CASE (CLASS, FUNCTION)>
|
||||
+ <!ELEMENT CLASS (#PCDATA)>
|
||||
+
|
||||
+ <!-- adding random ENTITY statement, as this is typical DTD content -->
|
||||
+ <!ENTITY unite "∪">
|
||||
+
|
||||
+ <!ATTLIST CASE CLASS CDATA #REQUIRED>
|
||||
+]>
|
||||
+<TEST>
|
||||
+ <CASE>
|
||||
+ <CLASS>tst_QXmlStream</CLASS>
|
||||
+ </CASE>
|
||||
+ <!-- invalid DTD in XML body follows -->
|
||||
+ <!DOCTYPE DTDTEST [
|
||||
+ <!ELEMENT RESULT (CASE+)>
|
||||
+ <!ATTLIST RESULT OUTPUT CDATA #REQUIRED>
|
||||
+ ]>
|
||||
+</TEST>
|
||||
+
|
||||
diff --git a/tests/auto/corelib/serialization/qxmlstream/tokenError/multipleDtd.xml b/tests/auto/corelib/serialization/qxmlstream/tokenError/multipleDtd.xml
|
||||
new file mode 100644
|
||||
index 00000000..1dbe75c4
|
||||
--- /dev/null
|
||||
+++ b/tests/auto/corelib/serialization/qxmlstream/tokenError/multipleDtd.xml
|
||||
@@ -0,0 +1,21 @@
|
||||
+<!DOCTYPE TEST [
|
||||
+ <!ELEMENT TESTATTRIBUTE (CASE+)>
|
||||
+ <!ELEMENT CASE (CLASS, FUNCTION, DATASET, COMMENTS)>
|
||||
+ <!ELEMENT CLASS (#PCDATA)>
|
||||
+
|
||||
+ <!-- adding random ENTITY statements, as this is typical DTD content -->
|
||||
+ <!ENTITY iff "⇔">
|
||||
+
|
||||
+ <!ATTLIST CASE CLASS CDATA #REQUIRED>
|
||||
+]>
|
||||
+<!-- invalid second DTD follows -->
|
||||
+<!DOCTYPE SECOND [
|
||||
+ <!ELEMENT SECONDATTRIBUTE (#PCDATA)>
|
||||
+ <!ENTITY on "∘">
|
||||
+]>
|
||||
+<TEST>
|
||||
+ <CASE>
|
||||
+ <CLASS>tst_QXmlStream</CLASS>
|
||||
+ </CASE>
|
||||
+</TEST>
|
||||
+
|
||||
diff --git a/tests/auto/corelib/serialization/qxmlstream/tokenError/wellFormed.xml b/tests/auto/corelib/serialization/qxmlstream/tokenError/wellFormed.xml
|
||||
new file mode 100644
|
||||
index 00000000..9dfbc0f9
|
||||
--- /dev/null
|
||||
+++ b/tests/auto/corelib/serialization/qxmlstream/tokenError/wellFormed.xml
|
||||
@@ -0,0 +1,16 @@
|
||||
+<!DOCTYPE TEST [
|
||||
+ <!ELEMENT TESTATTRIBUTE (CASE+)>
|
||||
+ <!ELEMENT CASE (CLASS, FUNCTION, DATASET, COMMENTS)>
|
||||
+ <!ELEMENT CLASS (#PCDATA)>
|
||||
+
|
||||
+ <!-- adding random ENTITY statements, as this is typical DTD content -->
|
||||
+ <!ENTITY unite "∪">
|
||||
+
|
||||
+ <!ATTLIST CASE CLASS CDATA #REQUIRED>
|
||||
+]>
|
||||
+<TEST>
|
||||
+ <CASE>
|
||||
+ <CLASS>tst_QXmlStream</CLASS>
|
||||
+ </CASE>
|
||||
+</TEST>
|
||||
+
|
||||
diff --git a/tests/auto/corelib/serialization/qxmlstream/tst_qxmlstream.cpp b/tests/auto/corelib/serialization/qxmlstream/tst_qxmlstream.cpp
|
||||
index 28922574..abbdc9fc 100644
|
||||
--- a/tests/auto/corelib/serialization/qxmlstream/tst_qxmlstream.cpp
|
||||
+++ b/tests/auto/corelib/serialization/qxmlstream/tst_qxmlstream.cpp
|
||||
@@ -583,6 +583,9 @@ private slots:
|
||||
|
||||
void entityExpansionLimit() const;
|
||||
|
||||
+ void tokenErrorHandling_data() const;
|
||||
+ void tokenErrorHandling() const;
|
||||
+
|
||||
private:
|
||||
static QByteArray readFile(const QString &filename);
|
||||
|
||||
@@ -1812,5 +1815,41 @@ void tst_QXmlStream::roundTrip() const
|
||||
QCOMPARE(out, in);
|
||||
}
|
||||
|
||||
+void tst_QXmlStream::tokenErrorHandling_data() const
|
||||
+{
|
||||
+ QTest::addColumn<QString>("fileName");
|
||||
+ QTest::addColumn<QXmlStreamReader::Error>("expectedError");
|
||||
+ QTest::addColumn<QString>("errorKeyWord");
|
||||
+
|
||||
+ constexpr auto invalid = QXmlStreamReader::Error::UnexpectedElementError;
|
||||
+ constexpr auto valid = QXmlStreamReader::Error::NoError;
|
||||
+ QTest::newRow("DtdInBody") << "dtdInBody.xml" << invalid << "DTD";
|
||||
+ QTest::newRow("multipleDTD") << "multipleDtd.xml" << invalid << "second DTD";
|
||||
+ QTest::newRow("wellFormed") << "wellFormed.xml" << valid << "";
|
||||
+}
|
||||
+
|
||||
+void tst_QXmlStream::tokenErrorHandling() const
|
||||
+{
|
||||
+ QFETCH(const QString, fileName);
|
||||
+ QFETCH(const QXmlStreamReader::Error, expectedError);
|
||||
+ QFETCH(const QString, errorKeyWord);
|
||||
+
|
||||
+ const QDir dir(QFINDTESTDATA("tokenError"));
|
||||
+ QFile file(dir.absoluteFilePath(fileName));
|
||||
+
|
||||
+ // Cross-compiling: File will be on host only
|
||||
+ if (!file.exists())
|
||||
+ QSKIP("Testfile not found.");
|
||||
+
|
||||
+ file.open(QIODevice::ReadOnly);
|
||||
+ QXmlStreamReader reader(&file);
|
||||
+ while (!reader.atEnd())
|
||||
+ reader.readNext();
|
||||
+
|
||||
+ QCOMPARE(reader.error(), expectedError);
|
||||
+ if (expectedError != QXmlStreamReader::Error::NoError)
|
||||
+ QVERIFY(reader.errorString().contains(errorKeyWord));
|
||||
+}
|
||||
+
|
||||
#include "tst_qxmlstream.moc"
|
||||
// vim: et:ts=4:sw=4:sts=4
|
||||
--
|
||||
2.41.0
|
||||
|
||||
129
qtbase5.15.2-CVE-2023-43114.patch
Normal file
129
qtbase5.15.2-CVE-2023-43114.patch
Normal file
@ -0,0 +1,129 @@
|
||||
From 2cfb68acb1a3f6d9e5dcc14ec210f46208daa21b Mon Sep 17 00:00:00 2001
|
||||
From: hua_yadong <huayadong@kylinos.cn>
|
||||
Date: Sat, 25 Nov 2023 11:22:22 +0800
|
||||
Subject: [PATCH] qtbase5.15.2-CVE-2023-43114
|
||||
|
||||
---
|
||||
.../windows/qwindowsfontdatabase.cpp | 67 ++++++++++++++-----
|
||||
1 file changed, 51 insertions(+), 16 deletions(-)
|
||||
|
||||
diff --git a/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase.cpp b/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase.cpp
|
||||
index a7345a13..8e7176b6 100644
|
||||
--- a/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase.cpp
|
||||
+++ b/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase.cpp
|
||||
@@ -1469,36 +1469,70 @@ QT_WARNING_POP
|
||||
return fontEngine;
|
||||
}
|
||||
|
||||
-static QList<quint32> getTrueTypeFontOffsets(const uchar *fontData)
|
||||
+static QList<quint32> getTrueTypeFontOffsets(const uchar *fontData, const uchar *fileEndSentinel)
|
||||
{
|
||||
QList<quint32> offsets;
|
||||
- const quint32 headerTag = *reinterpret_cast<const quint32 *>(fontData);
|
||||
+ if (fileEndSentinel - fontData < 12) {
|
||||
+ qCWarning(lcQpaFonts) << "Corrupted font data detected";
|
||||
+ return offsets;
|
||||
+ }
|
||||
+
|
||||
+ const quint32 headerTag = qFromUnaligned<quint32>(fontData);
|
||||
if (headerTag != MAKE_TAG('t', 't', 'c', 'f')) {
|
||||
if (headerTag != MAKE_TAG(0, 1, 0, 0)
|
||||
&& headerTag != MAKE_TAG('O', 'T', 'T', 'O')
|
||||
&& headerTag != MAKE_TAG('t', 'r', 'u', 'e')
|
||||
- && headerTag != MAKE_TAG('t', 'y', 'p', '1'))
|
||||
+ && headerTag != MAKE_TAG('t', 'y', 'p', '1')) {
|
||||
return offsets;
|
||||
+ }
|
||||
offsets << 0;
|
||||
return offsets;
|
||||
}
|
||||
+
|
||||
+ const quint32 maximumNumFonts = 0xffff;
|
||||
const quint32 numFonts = qFromBigEndian<quint32>(fontData + 8);
|
||||
- for (uint i = 0; i < numFonts; ++i) {
|
||||
- offsets << qFromBigEndian<quint32>(fontData + 12 + i * 4);
|
||||
+ if (numFonts > maximumNumFonts) {
|
||||
+ qCWarning(lcQpaFonts) << "Font collection of" << numFonts << "fonts is too large. Aborting.";
|
||||
+ return offsets;
|
||||
}
|
||||
+
|
||||
+ if (quintptr(fileEndSentinel - fontData) > 12 + (numFonts - 1) * 4) {
|
||||
+ for (quint32 i = 0; i < numFonts; ++i)
|
||||
+ offsets << qFromBigEndian<quint32>(fontData + 12 + i * 4);
|
||||
+ } else {
|
||||
+ qCWarning(lcQpaFonts) << "Corrupted font data detected";
|
||||
+ }
|
||||
+
|
||||
return offsets;
|
||||
}
|
||||
|
||||
-static void getFontTable(const uchar *fileBegin, const uchar *data, quint32 tag, const uchar **table, quint32 *length)
|
||||
+static void getFontTable(const uchar *fileBegin, const uchar *fileEndSentinel, const uchar *data, quint32 tag, const uchar **table, quint32 *length)
|
||||
{
|
||||
- const quint16 numTables = qFromBigEndian<quint16>(data + 4);
|
||||
- for (uint i = 0; i < numTables; ++i) {
|
||||
- const quint32 offset = 12 + 16 * i;
|
||||
- if (*reinterpret_cast<const quint32 *>(data + offset) == tag) {
|
||||
- *table = fileBegin + qFromBigEndian<quint32>(data + offset + 8);
|
||||
- *length = qFromBigEndian<quint32>(data + offset + 12);
|
||||
- return;
|
||||
+ if (fileEndSentinel - data >= 6) {
|
||||
+ const quint16 numTables = qFromBigEndian<quint16>(data + 4);
|
||||
+ if (fileEndSentinel - data >= 28 + 16 * (numTables - 1)) {
|
||||
+ for (quint32 i = 0; i < numTables; ++i) {
|
||||
+ const quint32 offset = 12 + 16 * i;
|
||||
+ if (qFromUnaligned<quint32>(data + offset) == tag) {
|
||||
+ const quint32 tableOffset = qFromBigEndian<quint32>(data + offset + 8);
|
||||
+ if (quintptr(fileEndSentinel - fileBegin) <= tableOffset) {
|
||||
+ qCWarning(lcQpaFonts) << "Corrupted font data detected";
|
||||
+ break;
|
||||
+ }
|
||||
+ *table = fileBegin + tableOffset;
|
||||
+ *length = qFromBigEndian<quint32>(data + offset + 12);
|
||||
+ if (quintptr(fileEndSentinel - *table) < *length) {
|
||||
+ qCWarning(lcQpaFonts) << "Corrupted font data detected";
|
||||
+ break;
|
||||
+ }
|
||||
+ return;
|
||||
+ }
|
||||
+ }
|
||||
+ } else {
|
||||
+ qCWarning(lcQpaFonts) << "Corrupted font data detected";
|
||||
}
|
||||
+ } else {
|
||||
+ qCWarning(lcQpaFonts) << "Corrupted font data detected";
|
||||
}
|
||||
*table = 0;
|
||||
*length = 0;
|
||||
@@ -1511,8 +1545,9 @@ static void getFamiliesAndSignatures(const QByteArray &fontData,
|
||||
QVector<QFontValues> *values)
|
||||
{
|
||||
const uchar *data = reinterpret_cast<const uchar *>(fontData.constData());
|
||||
+ const uchar *dataEndSentinel = data + fontData.size();
|
||||
|
||||
- QList<quint32> offsets = getTrueTypeFontOffsets(data);
|
||||
+ QList<quint32> offsets = getTrueTypeFontOffsets(data, dataEndSentinel);
|
||||
if (offsets.isEmpty())
|
||||
return;
|
||||
|
||||
@@ -1520,7 +1555,7 @@ static void getFamiliesAndSignatures(const QByteArray &fontData,
|
||||
const uchar *font = data + offsets.at(i);
|
||||
const uchar *table;
|
||||
quint32 length;
|
||||
- getFontTable(data, font, MAKE_TAG('n', 'a', 'm', 'e'), &table, &length);
|
||||
+ getFontTable(data, dataEndSentinel, font, MAKE_TAG('n', 'a', 'm', 'e'), &table, &length);
|
||||
if (!table)
|
||||
continue;
|
||||
QFontNames names = qt_getCanonicalFontNames(table, length);
|
||||
@@ -1530,7 +1565,7 @@ static void getFamiliesAndSignatures(const QByteArray &fontData,
|
||||
families->append(std::move(names));
|
||||
|
||||
if (values || signatures)
|
||||
- getFontTable(data, font, MAKE_TAG('O', 'S', '/', '2'), &table, &length);
|
||||
+ getFontTable(data, dataEndSentinel, font, MAKE_TAG('O', 'S', '/', '2'), &table, &length);
|
||||
|
||||
if (values) {
|
||||
QFontValues fontValues;
|
||||
--
|
||||
2.41.0
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user