Skip to content

Commit 7a790e9

Browse files
[AUTO-CHERRYPICK] [MEDIUM] Patch qt5-qtbase to fix CVE-2024-25580 - branch main (#12960)
Co-authored-by: Archana Shettigar <v-shettigara@microsoft.com>
1 parent 117f635 commit 7a790e9

3 files changed

Lines changed: 258 additions & 1 deletion

File tree

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
From 65be775b3b9f7acd20c6bf1f2c1bdbfd14174281 Mon Sep 17 00:00:00 2001
2+
From: archana25-ms <v-shettigara@microsoft.com>
3+
Date: Tue, 18 Feb 2025 04:08:46 +0000
4+
Subject: [PATCH] Address CVE-2023-34410
5+
6+
Source link: https://sources.debian.org/patches/qt6-base/6.4.2%2Bdfsg-11~bpo11%2B1/
7+
8+
---
9+
src/network/ssl/qsslsocket.cpp | 5 +++++
10+
1 file changed, 5 insertions(+)
11+
12+
diff --git a/src/network/ssl/qsslsocket.cpp b/src/network/ssl/qsslsocket.cpp
13+
index 9f9eaf3d..e3eb3883 100644
14+
--- a/src/network/ssl/qsslsocket.cpp
15+
+++ b/src/network/ssl/qsslsocket.cpp
16+
@@ -2087,6 +2087,10 @@ QSslSocketPrivate::QSslSocketPrivate()
17+
, flushTriggered(false)
18+
{
19+
QSslConfigurationPrivate::deepCopyDefaultConfiguration(&configuration);
20+
+ // If the global configuration doesn't allow root certificates to be loaded
21+
+ // on demand then we have to disable it for this socket as well.
22+
+ if (!configuration.allowRootCertOnDemandLoading)
23+
+ allowRootCertOnDemandLoading = false;
24+
}
25+
26+
/*!
27+
@@ -2315,6 +2319,7 @@ void QSslConfigurationPrivate::deepCopyDefaultConfiguration(QSslConfigurationPri
28+
ptr->sessionProtocol = global->sessionProtocol;
29+
ptr->ciphers = global->ciphers;
30+
ptr->caCertificates = global->caCertificates;
31+
+ ptr->allowRootCertOnDemandLoading = global->allowRootCertOnDemandLoading;
32+
ptr->protocol = global->protocol;
33+
ptr->peerVerifyMode = global->peerVerifyMode;
34+
ptr->peerVerifyDepth = global->peerVerifyDepth;
35+
--
36+
2.45.3
37+
Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
From 35e9912533b298ee913f9250f80160e534457d57 Mon Sep 17 00:00:00 2001
2+
From: archana25-ms <v-shettigara@microsoft.com>
3+
Date: Sun, 16 Feb 2025 07:55:11 +0000
4+
Subject: [PATCH] Address CVE-2024-25580
5+
6+
Source link: https://download.qt.io/official_releases/qt/5.15/CVE-2024-25580-qtbase-5.15.diff
7+
8+
---
9+
src/gui/util/qktxhandler.cpp | 138 +++++++++++++++++++++++++++--------
10+
src/gui/util/qktxhandler_p.h | 2 +-
11+
2 files changed, 110 insertions(+), 30 deletions(-)
12+
13+
diff --git a/src/gui/util/qktxhandler.cpp b/src/gui/util/qktxhandler.cpp
14+
index 7eda4c46..2853e46c 100644
15+
--- a/src/gui/util/qktxhandler.cpp
16+
+++ b/src/gui/util/qktxhandler.cpp
17+
@@ -73,7 +73,7 @@ struct KTXHeader {
18+
quint32 bytesOfKeyValueData;
19+
};
20+
21+
-static const quint32 headerSize = sizeof(KTXHeader);
22+
+static constexpr quint32 qktxh_headerSize = sizeof(KTXHeader);
23+
24+
// Currently unused, declared for future reference
25+
struct KTXKeyValuePairItem {
26+
@@ -103,11 +103,36 @@ struct KTXMipmapLevel {
27+
*/
28+
};
29+
30+
-bool QKtxHandler::canRead(const QByteArray &suffix, const QByteArray &block)
31+
+static bool qAddOverflow(quint32 v1, quint32 v2, quint32 *r) {
32+
+ // unsigned additions are well-defined
33+
+ *r = v1 + v2;
34+
+ return v1 > quint32(v1 + v2);
35+
+}
36+
+
37+
+// Returns the nearest multiple of 4 greater than or equal to 'value'
38+
+static bool nearestMultipleOf4(quint32 value, quint32 *result)
39+
+{
40+
+ constexpr quint32 rounding = 4;
41+
+ *result = 0;
42+
+ if (qAddOverflow(value, rounding - 1, result))
43+
+ return true;
44+
+ *result &= ~(rounding - 1);
45+
+ return false;
46+
+}
47+
+
48+
+// Returns a slice with prechecked bounds
49+
+static QByteArray safeSlice(const QByteArray& array, quint32 start, quint32 length)
50+
{
51+
- Q_UNUSED(suffix)
52+
+ quint32 end = 0;
53+
+ if (qAddOverflow(start, length, &end) || end > quint32(array.length()))
54+
+ return {};
55+
+ return QByteArray(array.data() + start, length);
56+
+}
57+
58+
- return (qstrncmp(block.constData(), ktxIdentifier, KTX_IDENTIFIER_LENGTH) == 0);
59+
+bool QKtxHandler::canRead(const QByteArray &suffix, const QByteArray &block)
60+
+{
61+
+ Q_UNUSED(suffix);
62+
+ return block.startsWith(QByteArray::fromRawData(ktxIdentifier, KTX_IDENTIFIER_LENGTH));
63+
}
64+
65+
QTextureFileData QKtxHandler::read()
66+
@@ -115,42 +140,97 @@ QTextureFileData QKtxHandler::read()
67+
if (!device())
68+
return QTextureFileData();
69+
70+
- QByteArray buf = device()->readAll();
71+
- const quint32 dataSize = quint32(buf.size());
72+
- if (dataSize < headerSize || !canRead(QByteArray(), buf)) {
73+
- qCDebug(lcQtGuiTextureIO, "Invalid KTX file %s", logName().constData());
74+
+ const QByteArray buf = device()->readAll();
75+
+ if (size_t(buf.size()) > std::numeric_limits<quint32>::max()) {
76+
+ qWarning(lcQtGuiTextureIO, "Too big KTX file %s", logName().constData());
77+
+ return QTextureFileData();
78+
+ }
79+
+
80+
+ if (!canRead(QByteArray(), buf)) {
81+
+ qWarning(lcQtGuiTextureIO, "Invalid KTX file %s", logName().constData());
82+
+ return QTextureFileData();
83+
+ }
84+
+
85+
+ if (buf.size() < qsizetype(qktxh_headerSize)) {
86+
+ qWarning(lcQtGuiTextureIO, "Invalid KTX header size in %s", logName().constData());
87+
return QTextureFileData();
88+
}
89+
90+
- const KTXHeader *header = reinterpret_cast<const KTXHeader *>(buf.constData());
91+
- if (!checkHeader(*header)) {
92+
- qCDebug(lcQtGuiTextureIO, "Unsupported KTX file format in %s", logName().constData());
93+
+ KTXHeader header;
94+
+ memcpy(&header, buf.data(), qktxh_headerSize);
95+
+ if (!checkHeader(header)) {
96+
+ qWarning(lcQtGuiTextureIO, "Unsupported KTX file format in %s", logName().constData());
97+
return QTextureFileData();
98+
}
99+
100+
QTextureFileData texData;
101+
texData.setData(buf);
102+
103+
- texData.setSize(QSize(decode(header->pixelWidth), decode(header->pixelHeight)));
104+
- texData.setGLFormat(decode(header->glFormat));
105+
- texData.setGLInternalFormat(decode(header->glInternalFormat));
106+
- texData.setGLBaseInternalFormat(decode(header->glBaseInternalFormat));
107+
-
108+
- texData.setNumLevels(decode(header->numberOfMipmapLevels));
109+
- quint32 offset = headerSize + decode(header->bytesOfKeyValueData);
110+
- const int maxLevels = qMin(texData.numLevels(), 32); // Cap iterations in case of corrupt file.
111+
- for (int i = 0; i < maxLevels; i++) {
112+
- if (offset + sizeof(KTXMipmapLevel) > dataSize) // Corrupt file; avoid oob read
113+
- break;
114+
- const KTXMipmapLevel *level = reinterpret_cast<const KTXMipmapLevel *>(buf.constData() + offset);
115+
- quint32 levelLen = decode(level->imageSize);
116+
- texData.setDataOffset(offset + sizeof(KTXMipmapLevel::imageSize), i);
117+
- texData.setDataLength(levelLen, i);
118+
- offset += sizeof(KTXMipmapLevel::imageSize) + levelLen + (3 - ((levelLen + 3) % 4));
119+
+ texData.setSize(QSize(decode(header.pixelWidth), decode(header.pixelHeight)));
120+
+ texData.setGLFormat(decode(header.glFormat));
121+
+ texData.setGLInternalFormat(decode(header.glInternalFormat));
122+
+ texData.setGLBaseInternalFormat(decode(header.glBaseInternalFormat));
123+
+
124+
+ texData.setNumLevels(decode(header.numberOfMipmapLevels));
125+
+
126+
+ const quint32 bytesOfKeyValueData = decode(header.bytesOfKeyValueData);
127+
+ quint32 headerKeyValueSize;
128+
+ if (qAddOverflow(qktxh_headerSize, bytesOfKeyValueData, &headerKeyValueSize)) {
129+
+ qWarning(lcQtGuiTextureIO, "Overflow in size of key value data in header of KTX file %s",
130+
+ logName().constData());
131+
+ return QTextureFileData();
132+
+ }
133+
+
134+
+ if (headerKeyValueSize >= quint32(buf.size())) {
135+
+ qWarning(lcQtGuiTextureIO, "OOB request in KTX file %s", logName().constData());
136+
+ return QTextureFileData();
137+
+ }
138+
+
139+
+ // Technically, any number of levels is allowed but if the value is bigger than
140+
+ // what is possible in KTX V2 (and what makes sense) we return an error.
141+
+ // maxLevels = log2(max(width, height, depth))
142+
+ const int maxLevels = (sizeof(quint32) * 8)
143+
+ - qCountLeadingZeroBits(std::max(
144+
+ { header.pixelWidth, header.pixelHeight, header.pixelDepth }));
145+
+
146+
+ if (texData.numLevels() > maxLevels) {
147+
+ qWarning(lcQtGuiTextureIO, "Too many levels in KTX file %s", logName().constData());
148+
+ return QTextureFileData();
149+
+ }
150+
+
151+
+ quint32 offset = headerKeyValueSize;
152+
+ for (int level = 0; level < texData.numLevels(); level++) {
153+
+ const auto imageSizeSlice = safeSlice(buf, offset, sizeof(quint32));
154+
+ if (imageSizeSlice.isEmpty()) {
155+
+ qWarning(lcQtGuiTextureIO, "OOB request in KTX file %s", logName().constData());
156+
+ return QTextureFileData();
157+
+ }
158+
+
159+
+ const quint32 imageSize = decode(qFromUnaligned<quint32>(imageSizeSlice.data()));
160+
+ offset += sizeof(quint32); // overflow checked indirectly above
161+
+
162+
+ texData.setDataOffset(offset, level);
163+
+ texData.setDataLength(imageSize, level);
164+
+
165+
+ // Add image data and padding to offset
166+
+ quint32 padded = 0;
167+
+ if (nearestMultipleOf4(imageSize, &padded)) {
168+
+ qWarning(lcQtGuiTextureIO, "Overflow in KTX file %s", logName().constData());
169+
+ return QTextureFileData();
170+
+ }
171+
+
172+
+ quint32 offsetNext;
173+
+ if (qAddOverflow(offset, padded, &offsetNext)) {
174+
+ qWarning(lcQtGuiTextureIO, "OOB request in KTX file %s", logName().constData());
175+
+ return QTextureFileData();
176+
+ }
177+
+
178+
+ offset = offsetNext;
179+
}
180+
181+
if (!texData.isValid()) {
182+
- qCDebug(lcQtGuiTextureIO, "Invalid values in header of KTX file %s", logName().constData());
183+
+ qWarning(lcQtGuiTextureIO, "Invalid values in header of KTX file %s",
184+
+ logName().constData());
185+
return QTextureFileData();
186+
}
187+
188+
@@ -191,7 +271,7 @@ bool QKtxHandler::checkHeader(const KTXHeader &header)
189+
(decode(header.numberOfFaces) == 1));
190+
}
191+
192+
-quint32 QKtxHandler::decode(quint32 val)
193+
+quint32 QKtxHandler::decode(quint32 val) const
194+
{
195+
return inverseEndian ? qbswap<quint32>(val) : val;
196+
}
197+
diff --git a/src/gui/util/qktxhandler_p.h b/src/gui/util/qktxhandler_p.h
198+
index 19f7b0e7..8da990aa 100644
199+
--- a/src/gui/util/qktxhandler_p.h
200+
+++ b/src/gui/util/qktxhandler_p.h
201+
@@ -68,7 +68,7 @@ public:
202+
203+
private:
204+
bool checkHeader(const KTXHeader &header);
205+
- quint32 decode(quint32 val);
206+
+ quint32 decode(quint32 val) const;
207+
208+
bool inverseEndian = false;
209+
};
210+
--
211+
2.45.3
212+

SPECS/qt5-qtbase/qt5-qtbase.spec

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
Name: qt5-qtbase
3434
Summary: Qt5 - QtBase components
3535
Version: 5.12.11
36-
Release: 14%{?dist}
36+
Release: 15%{?dist}
3737
# See LICENSE.GPL3-EXCEPT.txt, for exception details
3838
License: GFDL AND LGPLv3 AND GPLv2 AND GPLv3 with exceptions AND QT License Agreement 4.0
3939
Vendor: Microsoft Corporation
@@ -165,6 +165,9 @@ Patch92: CVE-2024-39936.patch
165165

166166
Patch93: CVE-2022-25255.patch
167167

168+
Patch94: CVE-2024-25580.patch
169+
Patch95: CVE-2023-34410.patch
170+
168171
# Do not check any files in %%{_qt5_plugindir}/platformthemes/ for requires.
169172
# Those themes are there for platform integration. If the required libraries are
170173
# not there, the platform to integrate with isn't either. Then Qt will just
@@ -279,6 +282,8 @@ Qt5 libraries used for drawing widgets and OpenGL items.
279282
%patch91 -p1
280283
%patch92 -p1
281284
%patch93 -p1
285+
%patch94 -p1
286+
%patch95 -p1
282287

283288
## upstream patches
284289

@@ -784,6 +789,9 @@ fi
784789
%{_qt5_libdir}/cmake/Qt5Gui/Qt5Gui_QXdgDesktopPortalThemePlugin.cmake
785790

786791
%changelog
792+
* Fri Feb 14 2025 Archana Shettigar <v-shettigara@microsoft.com> - 5.12.11-15
793+
- Add patch to resolve CVE-2024-25580 & CVE-2023-34410
794+
787795
* Wed Oct 23 2024 Mykhailo Bykhovtsev <mbykhovtsev@microsoft.com> - 5.12.11-14
788796
- Add patch to resolve CVE-2022-25255.
789797

0 commit comments

Comments
 (0)