Skip to content

Commit ca31eb4

Browse files
azurelinux-securityBinduSri-6522866jslobodzian
authored
[AutoPR- Security] Patch qt5-qtdeclarative for CVE-2025-12385 [HIGH] (#15274)
Co-authored-by: BinduSri-6522866 <v-badabala@microsoft.com> Co-authored-by: jslobodzian <joslobo@microsoft.com>
1 parent 1ed6319 commit ca31eb4

File tree

2 files changed

+236
-2
lines changed

2 files changed

+236
-2
lines changed
Lines changed: 230 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,230 @@
1+
Description: rich text: limit size of text object
2+
When we draw a text object, we need to store this in RAM
3+
since the QTextObjectInterface is QPainter-based. This
4+
could lead to over-allocation if the text object size
5+
was set to be very large. We use the existing image IO
6+
infrastructure for making sure allocations are within
7+
reasonable (and configurable) limits.
8+
Origin: upstream, https://code.qt.io/cgit/qt/qtdeclarative.git/commit/?id=144ce34e846b3f73
9+
Backported to 5.15 by Dmitry Shachnev: validate allocation manually
10+
instead of using QImageIOHandler::allocateImage().
11+
Last-Update: 2025-12-11
12+
13+
Upstream Patch Reference: https://salsa.debian.org/qt-kde-team/qt/qtdeclarative/-/raw/debian/5.15.17+dfsg-4/debian/patches/CVE-2025-12385-part2.patch?ref_type=tags and https://codereview.qt-project.org/changes/qt%2Fqtdeclarative~687239/revisions/7/patch?download&raw
14+
15+
---
16+
src/quick/items/qquicktextdocument.cpp | 4 +-
17+
src/quick/items/qquicktextnodeengine.cpp | 17 ++--
18+
src/quick/util/qquickstyledtext.cpp | 21 +++-
19+
.../auto/quick/qquicktext/tst_qquicktext.cpp | 97 +++++++++++++++++++
20+
4 files changed, 129 insertions(+), 10 deletions(-)
21+
22+
diff --git a/src/quick/items/qquicktextdocument.cpp b/src/quick/items/qquicktextdocument.cpp
23+
index 06ac5804..6610d1a6 100644
24+
--- a/src/quick/items/qquicktextdocument.cpp
25+
+++ b/src/quick/items/qquicktextdocument.cpp
26+
@@ -138,9 +138,9 @@ QSizeF QQuickTextDocumentWithImageResources::intrinsicSize(
27+
if (format.isImageFormat()) {
28+
QTextImageFormat imageFormat = format.toImageFormat();
29+
30+
- const int width = qRound(imageFormat.width());
31+
+ const int width = qRound(qBound(qreal(INT_MIN), imageFormat.width(), qreal(INT_MAX)));
32+
const bool hasWidth = imageFormat.hasProperty(QTextFormat::ImageWidth) && width > 0;
33+
- const int height = qRound(imageFormat.height());
34+
+ const int height = qRound(qBound(qreal(INT_MIN), imageFormat.height(), qreal(INT_MAX)));
35+
const bool hasHeight = imageFormat.hasProperty(QTextFormat::ImageHeight) && height > 0;
36+
37+
QSizeF size(width, height);
38+
diff --git a/src/quick/items/qquicktextnodeengine.cpp b/src/quick/items/qquicktextnodeengine.cpp
39+
index 5a4ef2b6..1bbf3778 100644
40+
--- a/src/quick/items/qquicktextnodeengine.cpp
41+
+++ b/src/quick/items/qquicktextnodeengine.cpp
42+
@@ -47,6 +47,7 @@
43+
#include <QtGui/qtextobject.h>
44+
#include <QtGui/qtexttable.h>
45+
#include <QtGui/qtextlist.h>
46+
+#include <QtGui/private/qimage_p.h>
47+
48+
#include <private/qquicktext_p.h>
49+
#include <private/qquicktextdocument_p.h>
50+
@@ -467,12 +468,16 @@ void QQuickTextNodeEngine::addTextObject(const QTextBlock &block, const QPointF
51+
}
52+
}
53+
54+
- if (image.isNull()) {
55+
- image = QImage(size.toSize(), QImage::Format_ARGB32_Premultiplied);
56+
- image.fill(Qt::transparent);
57+
- {
58+
- QPainter painter(&image);
59+
- handler->drawObject(&painter, image.rect(), textDocument, pos, format);
60+
+ if (image.isNull() && !size.isEmpty()) {
61+
+ QImageData::ImageSizeParameters szp =
62+
+ QImageData::calculateImageParameters(size.width(), size.height(), 32);
63+
+ if (szp.isValid() && szp.totalSize <= 268435456L /* 256 MB */) {
64+
+ image = QImage(size.toSize(), QImage::Format_ARGB32_Premultiplied);
65+
+ image.fill(Qt::transparent);
66+
+ {
67+
+ QPainter painter(&image);
68+
+ handler->drawObject(&painter, image.rect(), textDocument, pos, format);
69+
+ }
70+
}
71+
}
72+
73+
diff --git a/src/quick/util/qquickstyledtext.cpp b/src/quick/util/qquickstyledtext.cpp
74+
index 5e1aaf12..55c16944 100644
75+
--- a/src/quick/util/qquickstyledtext.cpp
76+
+++ b/src/quick/util/qquickstyledtext.cpp
77+
@@ -45,6 +45,13 @@
78+
#include <qmath.h>
79+
#include "qquickstyledtext_p.h"
80+
#include <QQmlContext>
81+
+#include <QtGui/private/qoutlinemapper_p.h>
82+
+
83+
+#ifndef QQUICKSTYLEDPARSER_COORD_LIMIT
84+
+# define QQUICKSTYLEDPARSER_COORD_LIMIT QT_RASTER_COORD_LIMIT
85+
+#endif
86+
+
87+
+Q_LOGGING_CATEGORY(lcStyledText, "qt.quick.styledtext")
88+
89+
/*
90+
QQuickStyledText supports few tags:
91+
@@ -688,9 +695,19 @@ void QQuickStyledTextPrivate::parseImageAttributes(const QChar *&ch, const QStri
92+
if (attr.first == QLatin1String("src")) {
93+
image->url = QUrl(attr.second.toString());
94+
} else if (attr.first == QLatin1String("width")) {
95+
- image->size.setWidth(attr.second.toString().toInt());
96+
+ bool ok;
97+
+ int v = attr.second.toString().toInt(&ok);
98+
+ if (ok && v <= QQUICKSTYLEDPARSER_COORD_LIMIT)
99+
+ image->size.setWidth(v);
100+
+ else
101+
+ qCWarning(lcStyledText) << "Invalid width provided for <img>";
102+
} else if (attr.first == QLatin1String("height")) {
103+
- image->size.setHeight(attr.second.toString().toInt());
104+
+ bool ok;
105+
+ int v = attr.second.toString().toInt(&ok);
106+
+ if (ok && v <= QQUICKSTYLEDPARSER_COORD_LIMIT)
107+
+ image->size.setHeight(v);
108+
+ else
109+
+ qCWarning(lcStyledText) << "Invalid height provided for <img>";
110+
} else if (attr.first == QLatin1String("align")) {
111+
if (attr.second.toString() == QLatin1String("top")) {
112+
image->align = QQuickStyledTextImgTag::Top;
113+
diff --git a/tests/auto/quick/qquicktext/tst_qquicktext.cpp b/tests/auto/quick/qquicktext/tst_qquicktext.cpp
114+
index eafa6cb0..addabadf 100644
115+
--- a/tests/auto/quick/qquicktext/tst_qquicktext.cpp
116+
+++ b/tests/auto/quick/qquicktext/tst_qquicktext.cpp
117+
@@ -127,6 +127,8 @@ private slots:
118+
void imgTagsElide();
119+
void imgTagsUpdates();
120+
void imgTagsError();
121+
+ void imgSize_data();
122+
+ void imgSize();
123+
void fontSizeMode_data();
124+
void fontSizeMode();
125+
void fontSizeModeMultiline_data();
126+
@@ -3126,6 +3128,101 @@ void tst_qquicktext::imgTagsError()
127+
delete textObject;
128+
}
129+
130+
+void tst_qquicktext::imgSize_data()
131+
+{
132+
+ QTest::addColumn<QString>("url");
133+
+ QTest::addColumn<qint64>("width");
134+
+ QTest::addColumn<qint64>("height");
135+
+ QTest::addColumn<QQuickText::TextFormat>("format");
136+
+
137+
+ QTest::newRow("negative (styled text)") << QStringLiteral("images/starfish_2.png")
138+
+ << qint64(-0x7FFFFF)
139+
+ << qint64(-0x7FFFFF)
140+
+ << QQuickText::StyledText;
141+
+ QTest::newRow("negative (rich text)") << QStringLiteral("images/starfish_2.png")
142+
+ << qint64(-0x7FFFFF)
143+
+ << qint64(-0x7FFFFF)
144+
+ << QQuickText::RichText;
145+
+ QTest::newRow("large (styled text)") << QStringLiteral("images/starfish_2.png")
146+
+ << qint64(0x7FFFFF)
147+
+ << qint64(0x7FFFFF)
148+
+ << QQuickText::StyledText;
149+
+ QTest::newRow("large (right text)") << QStringLiteral("images/starfish_2.png")
150+
+ << qint64(0x7FFFFF)
151+
+ << qint64(0x7FFFFF)
152+
+ << QQuickText::RichText;
153+
+ QTest::newRow("medium (styled text)") << QStringLiteral("images/starfish_2.png")
154+
+ << qint64(0x10000)
155+
+ << qint64(0x10000)
156+
+ << QQuickText::StyledText;
157+
+ QTest::newRow("medium (right text)") << QStringLiteral("images/starfish_2.png")
158+
+ << qint64(0x10000)
159+
+ << qint64(0x10000)
160+
+ << QQuickText::RichText;
161+
+ QTest::newRow("out-of-bounds (styled text)") << QStringLiteral("images/starfish_2.png")
162+
+ << (qint64(INT_MAX) + 1)
163+
+ << (qint64(INT_MAX) + 1)
164+
+ << QQuickText::StyledText;
165+
+ QTest::newRow("out-of-bounds (rich text)") << QStringLiteral("images/starfish_2.png")
166+
+ << (qint64(INT_MAX) + 1)
167+
+ << (qint64(INT_MAX) + 1)
168+
+ << QQuickText::RichText;
169+
+ QTest::newRow("negative out-of-bounds (styled text)") << QStringLiteral("images/starfish_2.png")
170+
+ << (qint64(INT_MIN) - 1)
171+
+ << (qint64(INT_MIN) - 1)
172+
+ << QQuickText::StyledText;
173+
+ QTest::newRow("negative out-of-bounds (rich text)") << QStringLiteral("images/starfish_2.png")
174+
+ << (qint64(INT_MIN) - 1)
175+
+ << (qint64(INT_MIN) - 1)
176+
+ << QQuickText::RichText;
177+
+ QTest::newRow("large non-existent (styled text)") << QStringLiteral("a")
178+
+ << qint64(0x7FFFFF)
179+
+ << qint64(0x7FFFFF)
180+
+ << QQuickText::StyledText;
181+
+ QTest::newRow("medium non-existent (styled text)") << QStringLiteral("a")
182+
+ << qint64(0x10000)
183+
+ << qint64(0x10000)
184+
+ << QQuickText::StyledText;
185+
+ QTest::newRow("out-of-bounds non-existent (styled text)") << QStringLiteral("a")
186+
+ << (qint64(INT_MAX) + 1)
187+
+ << (qint64(INT_MAX) + 1)
188+
+ << QQuickText::StyledText;
189+
+ QTest::newRow("large non-existent (rich text)") << QStringLiteral("a")
190+
+ << qint64(0x7FFFFF)
191+
+ << qint64(0x7FFFFF)
192+
+ << QQuickText::RichText;
193+
+ QTest::newRow("medium non-existent (rich text)") << QStringLiteral("a")
194+
+ << qint64(0x10000)
195+
+ << qint64(0x10000)
196+
+ << QQuickText::RichText;
197+
+}
198+
+
199+
+void tst_qquicktext::imgSize()
200+
+{
201+
+ QFETCH(QString, url);
202+
+ QFETCH(qint64, width);
203+
+ QFETCH(qint64, height);
204+
+ QFETCH(QQuickText::TextFormat, format);
205+
+
206+
+ // Reusing imgTagsUpdates.qml here, since it is just an empty Text component
207+
+ QScopedPointer<QQuickView> window(createView(testFile("imgTagsUpdates.qml")));
208+
+ window->show();
209+
+ QVERIFY(QTest::qWaitForWindowExposed(window.data()));
210+
+
211+
+ QScopedPointer<QQuickText> myText(window->rootObject()->findChild<QQuickText*>("myText"));
212+
+ QVERIFY(myText);
213+
+
214+
+ myText->setTextFormat(format);
215+
+
216+
+ QString imgStr = QStringLiteral("<img src=\"%1\" width=\"%2\" height=\"%3\" />")
217+
+ .arg(url)
218+
+ .arg(width)
219+
+ .arg(height);
220+
+ myText->setText(imgStr);
221+
+
222+
+ QVERIFY(QQuickTest::qWaitForItemPolished(myText.data()));
223+
+}
224+
+
225+
void tst_qquicktext::fontSizeMode_data()
226+
{
227+
QTest::addColumn<QString>("text");
228+
--
229+
2.45.4
230+

SPECS/qt5-qtdeclarative/qt5-qtdeclarative.spec

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
Summary: Qt5 - QtDeclarative component
22
Name: qt5-qtdeclarative
33
Version: 5.12.5
4-
Release: 5%{?dist}
4+
Release: 6%{?dist}
55
Vendor: Microsoft Corporation
66
Distribution: Mariner
77

@@ -10,6 +10,7 @@ License: LGPLv2 with exceptions or GPLv3 with exceptions
1010
Url: http://www.qt.io
1111
%global majmin %(echo %{version} | cut -d. -f1-2)
1212
Source0: https://download.qt.io/archive/qt/%{majmin}/%{version}/submodules/qtdeclarative-everywhere-src-%{version}.tar.xz
13+
Patch0: CVE-2025-12385.patch
1314

1415
## upstream patches
1516

@@ -48,7 +49,7 @@ Requires: %{name}%{?_isa} = %{version}-%{release}
4849
%{summary}.
4950

5051
%prep
51-
%setup -q -n qtdeclarative-everywhere-src-%{version}
52+
%autosetup -n qtdeclarative-everywhere-src-%{version} -p1
5253

5354
%build
5455

@@ -141,6 +142,9 @@ popd
141142

142143

143144
%changelog
145+
* Wed Mar 11 2026 Azure Linux Security Servicing Account <azurelinux-security@microsoft.com> - 5.12.5-6
146+
- Patch for CVE-2025-12385
147+
144148
* Wed Sep 20 2023 Jon Slobodzian <joslobo@microsoft.com> - 5.12.5-5
145149
- Recompile with stack-protection fixed gcc version (CVE-2023-4039)
146150

0 commit comments

Comments
 (0)