summaryrefslogtreecommitdiffstats
path: root/meta/recipes-devtools/python/python3/CVE-2025-12084.patch
blob: 0c9bb435edfedd5373be9b3eccbb97b0a2982c4a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
From c97e87593063d84a2bd9fe7068b30eb44de23dc0 Mon Sep 17 00:00:00 2001
From: "Miss Islington (bot)"
 <31488909+miss-islington@users.noreply.github.com>
Date: Sun, 25 Jan 2026 18:10:49 +0100
Subject: [PATCH] [3.10] gh-142145: Remove quadratic behavior in node ID cache
 clearing (GH-142146) (#142213)

* gh-142145: Remove quadratic behavior in node ID cache clearing (GH-142146)

* Remove quadratic behavior in node ID cache clearing

Co-authored-by: Jacob Walls <38668450+jacobtylerwalls@users.noreply.github.com>

* Add news fragment

CVE: CVE-2025-12084
Upstream-Status: Backport [https://github.com/python/cpython/commit/c97e87593063d84a2bd9fe7068b30eb44de23dc0]
Signed-off-by: Peter Marko <peter.marko@siemens.com>
---------
(cherry picked from commit 08d8e18ad81cd45bc4a27d6da478b51ea49486e4)

Co-authored-by: Seth Michael Larson <seth@python.org>
Co-authored-by: Jacob Walls <38668450+jacobtylerwalls@users.noreply.github.com>

* [3.14] gh-142754: Ensure that Element & Attr instances have the ownerDocument attribute (GH-142794) (#142818)

gh-142754: Ensure that Element & Attr instances have the ownerDocument attribute (GH-142794)
(cherry picked from commit 1cc7551b3f9f71efbc88d96dce90f82de98b2454)

Co-authored-by: Petr Viktorin <encukou@gmail.com>
Co-authored-by: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com>

* gh-142145: relax the no-longer-quadratic test timing (GH-143030)

* gh-142145: relax the no-longer-quadratic test timing

* require cpu resource
(cherry picked from commit 8d2d7bb2e754f8649a68ce4116271a4932f76907)

Co-authored-by: Gregory P. Smith <68491+gpshead@users.noreply.github.com>

* merge NEWS entries into one

---------

Co-authored-by: Seth Michael Larson <seth@python.org>
Co-authored-by: Jacob Walls <38668450+jacobtylerwalls@users.noreply.github.com>
Co-authored-by: Petr Viktorin <encukou@gmail.com>
Co-authored-by: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com>
Co-authored-by: Gregory P. Smith <68491+gpshead@users.noreply.github.com>
Co-authored-by: Gregory P. Smith <greg@krypto.org>
---
 Lib/test/test_minidom.py                      | 33 ++++++++++++++++++-
 Lib/xml/dom/minidom.py                        | 11 ++-----
 ...-12-01-09-36-45.gh-issue-142145.tcAUhg.rst |  6 ++++
 3 files changed, 41 insertions(+), 9 deletions(-)
 create mode 100644 Misc/NEWS.d/next/Security/2025-12-01-09-36-45.gh-issue-142145.tcAUhg.rst

diff --git a/Lib/test/test_minidom.py b/Lib/test/test_minidom.py
index ef38c36210..c68bd990f7 100644
--- a/Lib/test/test_minidom.py
+++ b/Lib/test/test_minidom.py
@@ -2,6 +2,7 @@
 
 import copy
 import pickle
+import time
 import io
 from test import support
 import unittest
@@ -9,7 +10,7 @@ import unittest
 import pyexpat
 import xml.dom.minidom
 
-from xml.dom.minidom import parse, Attr, Node, Document, parseString
+from xml.dom.minidom import parse, Attr, Node, Document, Element, parseString
 from xml.dom.minidom import getDOMImplementation
 from xml.parsers.expat import ExpatError
 
@@ -177,6 +178,36 @@ class MinidomTest(unittest.TestCase):
         self.confirm(dom.documentElement.childNodes[-1].data == "Hello")
         dom.unlink()
 
+    @support.requires_resource('cpu')
+    def testAppendChildNoQuadraticComplexity(self):
+        impl = getDOMImplementation()
+
+        newdoc = impl.createDocument(None, "some_tag", None)
+        top_element = newdoc.documentElement
+        children = [newdoc.createElement(f"child-{i}") for i in range(1, 2 ** 15 + 1)]
+        element = top_element
+
+        start = time.monotonic()
+        for child in children:
+            element.appendChild(child)
+            element = child
+        end = time.monotonic()
+
+        # This example used to take at least 30 seconds.
+        # Conservative assertion due to the wide variety of systems and
+        # build configs timing based tests wind up run under.
+        # A --with-address-sanitizer --with-pydebug build on a rpi5 still
+        # completes this loop in <0.5 seconds.
+        self.assertLess(end - start, 4)
+
+    def testSetAttributeNodeWithoutOwnerDocument(self):
+        # regression test for gh-142754
+        elem = Element("test")
+        attr = Attr("id")
+        attr.value = "test-id"
+        elem.setAttributeNode(attr)
+        self.assertEqual(elem.getAttribute("id"), "test-id")
+
     def testAppendChildFragment(self):
         dom, orig, c1, c2, c3, frag = self._create_fragment_test_nodes()
         dom.documentElement.appendChild(frag)
diff --git a/Lib/xml/dom/minidom.py b/Lib/xml/dom/minidom.py
index ef8a159833..cada981f39 100644
--- a/Lib/xml/dom/minidom.py
+++ b/Lib/xml/dom/minidom.py
@@ -292,13 +292,6 @@ def _append_child(self, node):
     childNodes.append(node)
     node.parentNode = self
 
-def _in_document(node):
-    # return True iff node is part of a document tree
-    while node is not None:
-        if node.nodeType == Node.DOCUMENT_NODE:
-            return True
-        node = node.parentNode
-    return False
 
 def _write_data(writer, data):
     "Writes datachars to writer."
@@ -355,6 +348,7 @@ class Attr(Node):
     def __init__(self, qName, namespaceURI=EMPTY_NAMESPACE, localName=None,
                  prefix=None):
         self.ownerElement = None
+        self.ownerDocument = None
         self._name = qName
         self.namespaceURI = namespaceURI
         self._prefix = prefix
@@ -680,6 +674,7 @@ class Element(Node):
 
     def __init__(self, tagName, namespaceURI=EMPTY_NAMESPACE, prefix=None,
                  localName=None):
+        self.ownerDocument = None
         self.parentNode = None
         self.tagName = self.nodeName = tagName
         self.prefix = prefix
@@ -1539,7 +1534,7 @@ def _clear_id_cache(node):
     if node.nodeType == Node.DOCUMENT_NODE:
         node._id_cache.clear()
         node._id_search_stack = None
-    elif _in_document(node):
+    elif node.ownerDocument:
         node.ownerDocument._id_cache.clear()
         node.ownerDocument._id_search_stack= None
 
diff --git a/Misc/NEWS.d/next/Security/2025-12-01-09-36-45.gh-issue-142145.tcAUhg.rst b/Misc/NEWS.d/next/Security/2025-12-01-09-36-45.gh-issue-142145.tcAUhg.rst
new file mode 100644
index 0000000000..05c7df35d1
--- /dev/null
+++ b/Misc/NEWS.d/next/Security/2025-12-01-09-36-45.gh-issue-142145.tcAUhg.rst
@@ -0,0 +1,6 @@
+Remove quadratic behavior in ``xml.minidom`` node ID cache clearing.  In order
+to do this without breaking existing users, we also add the *ownerDocument*
+attribute to :mod:`xml.dom.minidom` elements and attributes created by directly
+instantiating the ``Element`` or ``Attr`` class. Note that this way of creating
+nodes is not supported; creator functions like
+:py:meth:`xml.dom.Document.documentElement` should be used instead.