Skip to content

Commit c27e29c

Browse files
[AutoPR- Security] Patch qtbase for CVE-2026-11573 [HIGH] (#18810)
Co-authored-by: Kanishk Bansal <103916909+Kanishk-Bansal@users.noreply.github.com>
1 parent aa00c20 commit c27e29c

2 files changed

Lines changed: 193 additions & 1 deletion

File tree

SPECS/qtbase/CVE-2026-11573.patch

Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
From 9cd02680196c5d4198cfa8056219ee343b7e6fb7 Mon Sep 17 00:00:00 2001
2+
From: Tatiana Borisova <tatiana.borisova@qt.io>
3+
Date: Tue, 26 Nov 2024 21:18:40 +0100
4+
Subject: [PATCH] QDomDocument::toByteArray() crashed in case of high XML
5+
nesting level
6+
7+
The issue the combination of:
8+
- 300+ XML nesting level
9+
- Small stack size, by default on Windows (1 MB)
10+
- Unexpected and unexplained large stack frames with MSVC (3.5 kB)
11+
12+
The described factors combination leads to the stack overflow on
13+
Windows + MSVC.
14+
15+
To fix the problem, I got rid of the recursive call from
16+
QDomElementPrivate::save() and removed QDomNodePrivate::save()
17+
implementation.
18+
19+
Instead of those I added the method that iterates through the tree not
20+
using recursion.
21+
22+
[ChangeLog][QtXml] QDomDocument::toByteArray() now iterates the
23+
nodes of the document instead of recursing into subnodes. This avoids
24+
a stack-overflow crash that used to arise with deeply-nested document
25+
structures.
26+
27+
Fixes: QTBUG-131151
28+
Pick-to: 6.8
29+
Change-Id: Ib74aaef1422716f2aafcb89dfc8c05ef334e2a54
30+
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
31+
Signed-off-by: Azure Linux Security Servicing Account <azurelinux-security@microsoft.com>
32+
Upstream-reference: https://github.com/qt/qtbase/commit/387633a6069a5e0e9b976971691b1b82725b6132.patch
33+
---
34+
src/xml/dom/qdom.cpp | 70 +++++++++++++++++++++++++++++++++-----------
35+
src/xml/dom/qdom_p.h | 5 +++-
36+
2 files changed, 57 insertions(+), 18 deletions(-)
37+
38+
diff --git a/src/xml/dom/qdom.cpp b/src/xml/dom/qdom.cpp
39+
index 1dd1ff7b..3913f920 100644
40+
--- a/src/xml/dom/qdom.cpp
41+
+++ b/src/xml/dom/qdom.cpp
42+
@@ -1356,16 +1356,40 @@ void QDomNodePrivate::normalize()
43+
qNormalizeNode(this);
44+
}
45+
46+
-/*! \internal
47+
- \a depth is used for indentation, it seems.
48+
- */
49+
-void QDomNodePrivate::save(QTextStream& s, int depth, int indent) const
50+
+void QDomNodePrivate::saveSubTree(const QDomNodePrivate *n, QTextStream &s,
51+
+ int depth, int indent) const
52+
{
53+
- const QDomNodePrivate* n = first;
54+
- while (n) {
55+
- n->save(s, depth, indent);
56+
- n = n->next;
57+
+ if (!n)
58+
+ return;
59+
+
60+
+ const QDomNodePrivate *root = n->first;
61+
+ n->save(s, depth, indent);
62+
+ if (root) {
63+
+ const int branchDepth = depth + 1;
64+
+ int layerDepth = 0;
65+
+ while (root) {
66+
+ root->save(s, layerDepth + branchDepth, indent);
67+
+ // A flattened (non-recursive) depth-first walk through the node tree.
68+
+ if (root->first) {
69+
+ layerDepth ++;
70+
+ root = root->first;
71+
+ continue;
72+
+ }
73+
+ root->afterSave(s, layerDepth + branchDepth, indent);
74+
+ const QDomNodePrivate *prev = root;
75+
+ root = root->next;
76+
+ // Close QDomElementPrivate groups
77+
+ while (!root && prev && (layerDepth > 0)) {
78+
+ root = prev->parent();
79+
+ layerDepth --;
80+
+ root->afterSave(s, layerDepth + branchDepth, indent);
81+
+ prev = root;
82+
+ root = root->next;
83+
+ }
84+
+ }
85+
+ Q_ASSERT(layerDepth == 0);
86+
}
87+
+ n->afterSave(s, depth, indent);
88+
}
89+
90+
void QDomNodePrivate::setLocation(int lineNumber, int columnNumber)
91+
@@ -2154,7 +2178,7 @@ void QDomNode::save(QTextStream& stream, int indent, EncodingPolicy encodingPoli
92+
if (isDocument())
93+
static_cast<const QDomDocumentPrivate *>(impl)->saveDocument(stream, indent, encodingPolicy);
94+
else
95+
- IMPL->save(stream, 1, indent);
96+
+ IMPL->saveSubTree(IMPL, stream, 1, indent);
97+
}
98+
99+
/*!
100+
@@ -3071,11 +3095,11 @@ void QDomDocumentTypePrivate::save(QTextStream& s, int, int indent) const
101+
102+
auto it2 = notations->map.constBegin();
103+
for (; it2 != notations->map.constEnd(); ++it2)
104+
- it2.value()->save(s, 0, indent);
105+
+ it2.value()->saveSubTree(it2.value(), s, 0, indent);
106+
107+
auto it = entities->map.constBegin();
108+
for (; it != entities->map.constEnd(); ++it)
109+
- it.value()->save(s, 0, indent);
110+
+ it.value()->saveSubTree(it.value(), s, 0, indent);
111+
112+
s << ']';
113+
}
114+
@@ -4128,13 +4152,25 @@ void QDomElementPrivate::save(QTextStream& s, int depth, int indent) const
115+
if (indent != -1)
116+
s << Qt::endl;
117+
}
118+
- QDomNodePrivate::save(s, depth + 1, indent); if (!last->isText())
119+
+ } else {
120+
+ s << "/>";
121+
+ }
122+
+}
123+
+
124+
+void QDomElementPrivate::afterSave(QTextStream &s, int depth, int indent) const
125+
+{
126+
+ if (last) {
127+
+ QString qName(name);
128+
+
129+
+ if (!prefix.isEmpty())
130+
+ qName = prefix + u':' + name;
131+
+
132+
+ if (!last->isText())
133+
s << QString(indent < 1 ? 0 : depth * indent, u' ');
134+
135+
s << "</" << qName << '>';
136+
- } else {
137+
- s << "/>";
138+
}
139+
+
140+
if (!(next && next->isText())) {
141+
/* -1 disables new lines. */
142+
if (indent != -1)
143+
@@ -5916,7 +5952,7 @@ void QDomDocumentPrivate::saveDocument(QTextStream& s, const int indent, QDomNod
144+
type->save(s, 0, indent);
145+
doc = true;
146+
}
147+
- n->save(s, 0, indent);
148+
+ n->saveSubTree(n, s, 0, indent);
149+
n = n->next;
150+
}
151+
}
152+
@@ -5943,8 +5979,8 @@ void QDomDocumentPrivate::saveDocument(QTextStream& s, const int indent, QDomNod
153+
}
154+
155+
// Now we serialize all the nodes after the faked XML declaration(the PI).
156+
- while(startNode) {
157+
- startNode->save(s, 0, indent);
158+
+ while (startNode) {
159+
+ startNode->saveSubTree(startNode, s, 0, indent);
160+
startNode = startNode->next;
161+
}
162+
}
163+
diff --git a/src/xml/dom/qdom_p.h b/src/xml/dom/qdom_p.h
164+
index fb71f8ce..5a592b15 100644
165+
--- a/src/xml/dom/qdom_p.h
166+
+++ b/src/xml/dom/qdom_p.h
167+
@@ -108,7 +108,9 @@ public:
168+
169+
virtual QDomNode::NodeType nodeType() const { return QDomNode::BaseNode; }
170+
171+
- virtual void save(QTextStream &, int, int) const;
172+
+ void saveSubTree(const QDomNodePrivate *n, QTextStream &s, int depth, int indent) const;
173+
+ virtual void save(QTextStream &, int, int) const {}
174+
+ virtual void afterSave(QTextStream &, int, int) const {}
175+
176+
void setLocation(int lineNumber, int columnNumber);
177+
178+
@@ -327,6 +329,7 @@ public:
179+
QDomNode::NodeType nodeType() const override { return QDomNode::ElementNode; }
180+
QDomNodePrivate *cloneNode(bool deep = true) override;
181+
virtual void save(QTextStream &s, int, int) const override;
182+
+ virtual void afterSave(QTextStream &s, int, int) const override;
183+
184+
// Variables
185+
QDomNamedNodeMapPrivate *m_attr;
186+
--
187+
2.45.4
188+

SPECS/qtbase/qtbase.spec

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
Name: qtbase
3636
Summary: Qt6 - QtBase components
3737
Version: 6.6.3
38-
Release: 5%{?dist}
38+
Release: 6%{?dist}
3939
# See LICENSE.GPL3-EXCEPT.txt, for exception details
4040
License: GFDL AND LGPLv3 AND GPLv2 AND GPLv3 with exceptions AND QT License Agreement 4.0
4141
Vendor: Microsoft Corporation
@@ -100,6 +100,7 @@ Patch65: qtbase-mysql.patch
100100
Patch66: CVE-2025-30348.patch
101101
Patch67: CVE-2025-5455.patch
102102
Patch68: CVE-2026-15037.patch
103+
Patch69: CVE-2026-11573.patch
103104

104105
# Do not check any files in %%{_qt_plugindir}/platformthemes/ for requires.
105106
# Those themes are there for platform integration. If the required libraries are
@@ -704,6 +705,9 @@ fi
704705
%{_qt_plugindir}/platformthemes/libqxdgdesktopportal.so
705706

706707
%changelog
708+
* Mon Sep 14 2026 Azure Linux Security Servicing Account <azurelinux-security@microsoft.com> - 6.6.3-6
709+
- Patch for CVE-2026-11573
710+
707711
* Wed Jul 29 2026 Azure Linux Security Servicing Account <azurelinux-security@microsoft.com> - 6.6.3-5
708712
- Patch for CVE-2026-15037
709713

0 commit comments

Comments
 (0)