Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
143 changes: 143 additions & 0 deletions SPECS/python3/CVE-2025-12084.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
From f4eb9ab014545b521fb261b80adfa6d138e7e092 Mon Sep 17 00:00:00 2001
From: Seth Michael Larson <seth@python.org>
Date: Wed, 3 Dec 2025 01:16:37 -0600
Subject: [PATCH 1/4] 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

---------
(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>

Signed-off-by: Azure Linux Security Servicing Account <azurelinux-security@microsoft.com>
Upstream-reference: https://github.com/python/cpython/pull/142213.patch
---
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 9762025..9f7f5b2 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, 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

@@ -163,6 +164,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 d09ef5e..e4e8b42 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
@@ -678,6 +672,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
@@ -1537,7 +1532,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 0000000..05c7df3
--- /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.
--
2.45.4

103 changes: 103 additions & 0 deletions SPECS/python3/CVE-2026-0865.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
From 123bfbbe9074ef7fa28e1e7b25575665296560fa Mon Sep 17 00:00:00 2001
From: "Gregory P. Smith" <68491+gpshead@users.noreply.github.com>
Date: Sat, 17 Jan 2026 10:23:57 -0800
Subject: [PATCH] [3.10] gh-143916: Reject control characters in
wsgiref.headers.Headers (GH-143917) (GH-143973)

gh-143916: Reject control characters in wsgiref.headers.Headers (GH-143917)

* Add 'test.support' fixture for C0 control characters
* gh-143916: Reject control characters in wsgiref.headers.Headers

(cherry picked from commit f7fceed79ca1bceae8dbe5ba5bc8928564da7211)
(cherry picked from commit 22e4d55285cee52bc4dbe061324e5f30bd4dee58)

Co-authored-by: Gregory P. Smith <68491+gpshead@users.noreply.github.com>
Co-authored-by: Seth Michael Larson <seth@python.org>

Signed-off-by: Azure Linux Security Servicing Account <azurelinux-security@microsoft.com>
Upstream-reference: https://github.com/python/cpython/pull/143976.patch
---
Lib/test/support/__init__.py | 7 +++++++
Lib/test/test_wsgiref.py | 12 +++++++++++-
Lib/wsgiref/headers.py | 3 +++
.../2026-01-16-11-07-36.gh-issue-143916.dpWeOD.rst | 2 ++
4 files changed, 23 insertions(+), 1 deletion(-)
create mode 100644 Misc/NEWS.d/next/Security/2026-01-16-11-07-36.gh-issue-143916.dpWeOD.rst

diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py
index 6dc0813..ea9a88d 100644
--- a/Lib/test/support/__init__.py
+++ b/Lib/test/support/__init__.py
@@ -3305,3 +3305,10 @@ def adjust_int_max_str_digits(max_digits):
yield
finally:
sys.set_int_max_str_digits(current)
+
+
+def control_characters_c0() -> list[str]:
+ """Returns a list of C0 control characters as strings.
+ C0 control characters defined as the byte range 0x00-0x1F, and 0x7F.
+ """
+ return [chr(c) for c in range(0x00, 0x20)] + ["\x7F"]
diff --git a/Lib/test/test_wsgiref.py b/Lib/test/test_wsgiref.py
index 3e76e01..d5d3f65 100644
--- a/Lib/test/test_wsgiref.py
+++ b/Lib/test/test_wsgiref.py
@@ -1,6 +1,6 @@
from unittest import mock
from test import support
-from test.support import socket_helper
+from test.support import socket_helper, control_characters_c0
from test.test_httpservers import NoLogRequestHandler
from unittest import TestCase
from wsgiref.util import setup_testing_defaults
@@ -526,6 +526,16 @@ class HeaderTests(TestCase):
'\r\n'
)

+ def testRaisesControlCharacters(self):
+ headers = Headers()
+ for c0 in control_characters_c0():
+ self.assertRaises(ValueError, headers.__setitem__, f"key{c0}", "val")
+ self.assertRaises(ValueError, headers.__setitem__, "key", f"val{c0}")
+ self.assertRaises(ValueError, headers.add_header, f"key{c0}", "val", param="param")
+ self.assertRaises(ValueError, headers.add_header, "key", f"val{c0}", param="param")
+ self.assertRaises(ValueError, headers.add_header, "key", "val", param=f"param{c0}")
+
+
class ErrorHandler(BaseCGIHandler):
"""Simple handler subclass for testing BaseHandler"""

diff --git a/Lib/wsgiref/headers.py b/Lib/wsgiref/headers.py
index fab851c..fd98e85 100644
--- a/Lib/wsgiref/headers.py
+++ b/Lib/wsgiref/headers.py
@@ -9,6 +9,7 @@ written by Barry Warsaw.
# existence of which force quoting of the parameter value.
import re
tspecials = re.compile(r'[ \(\)<>@,;:\\"/\[\]\?=]')
+_control_chars_re = re.compile(r'[\x00-\x1F\x7F]')

def _formatparam(param, value=None, quote=1):
"""Convenience function to format and return a key=value pair.
@@ -41,6 +42,8 @@ class Headers:
def _convert_string_type(self, value):
"""Convert/check value type."""
if type(value) is str:
+ if _control_chars_re.search(value):
+ raise ValueError("Control characters not allowed in headers")
return value
raise AssertionError("Header names/values must be"
" of type str (got {0})".format(repr(value)))
diff --git a/Misc/NEWS.d/next/Security/2026-01-16-11-07-36.gh-issue-143916.dpWeOD.rst b/Misc/NEWS.d/next/Security/2026-01-16-11-07-36.gh-issue-143916.dpWeOD.rst
new file mode 100644
index 0000000..44bd0b2
--- /dev/null
+++ b/Misc/NEWS.d/next/Security/2026-01-16-11-07-36.gh-issue-143916.dpWeOD.rst
@@ -0,0 +1,2 @@
+Reject C0 control characters within wsgiref.headers.Headers fields, values,
+and parameters.
--
2.45.4

9 changes: 8 additions & 1 deletion SPECS/python3/python3.spec
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
Summary: A high-level scripting language
Name: python3
Version: 3.9.19
Release: 18%{?dist}
Release: 19%{?dist}
License: PSF
Vendor: Microsoft Corporation
Distribution: Mariner
Expand Down Expand Up @@ -41,6 +41,8 @@ Patch17: CVE-2025-8291.patch
Patch18: CVE-2025-6075.patch
Patch19: CVE-2026-0672.patch
Patch20: CVE-2026-1299.patch
Patch21: CVE-2025-12084.patch
Patch22: CVE-2026-0865.patch

# Patch for setuptools, resolved in 65.5.1
Patch1000: CVE-2022-40897.patch
Expand Down Expand Up @@ -208,6 +210,8 @@ The test package contains all regression tests for Python as well as the modules
%patch18 -p1
%patch19 -p1
%patch20 -p1
%patch21 -p1
%patch22 -p1

%build
# Remove GCC specs and build environment linker scripts
Expand Down Expand Up @@ -383,6 +387,9 @@ make test TESTOPTS="-x test_multiprocessing_spawn -x test_socket -x test_email"
%{_libdir}/python%{majmin}/test/*

%changelog
* Fri Jan 30 2026 Azure Linux Security Servicing Account <azurelinux-security@microsoft.com> - 3.9.19-19
- Patch for CVE-2026-0865, CVE-2025-12084

* Wed Jan 28 2026 Azure Linux Security Servicing Account <azurelinux-security@microsoft.com> - 3.9.19-18
- Patch for CVE-2026-1299, CVE-2026-0672

Expand Down
8 changes: 4 additions & 4 deletions toolkit/resources/manifests/package/pkggen_core_aarch64.txt
Original file line number Diff line number Diff line change
Expand Up @@ -237,10 +237,10 @@ ca-certificates-base-2.0.0-25.cm2.noarch.rpm
ca-certificates-2.0.0-25.cm2.noarch.rpm
dwz-0.14-2.cm2.aarch64.rpm
unzip-6.0-22.cm2.aarch64.rpm
python3-3.9.19-18.cm2.aarch64.rpm
python3-devel-3.9.19-18.cm2.aarch64.rpm
python3-libs-3.9.19-18.cm2.aarch64.rpm
python3-setuptools-3.9.19-18.cm2.noarch.rpm
python3-3.9.19-19.cm2.aarch64.rpm
python3-devel-3.9.19-19.cm2.aarch64.rpm
python3-libs-3.9.19-19.cm2.aarch64.rpm
python3-setuptools-3.9.19-19.cm2.noarch.rpm
python3-pygments-2.4.2-7.cm2.noarch.rpm
which-2.21-8.cm2.aarch64.rpm
libselinux-3.2-1.cm2.aarch64.rpm
Expand Down
8 changes: 4 additions & 4 deletions toolkit/resources/manifests/package/pkggen_core_x86_64.txt
Original file line number Diff line number Diff line change
Expand Up @@ -237,10 +237,10 @@ ca-certificates-base-2.0.0-25.cm2.noarch.rpm
ca-certificates-2.0.0-25.cm2.noarch.rpm
dwz-0.14-2.cm2.x86_64.rpm
unzip-6.0-22.cm2.x86_64.rpm
python3-3.9.19-18.cm2.x86_64.rpm
python3-devel-3.9.19-18.cm2.x86_64.rpm
python3-libs-3.9.19-18.cm2.x86_64.rpm
python3-setuptools-3.9.19-18.cm2.noarch.rpm
python3-3.9.19-19.cm2.x86_64.rpm
python3-devel-3.9.19-19.cm2.x86_64.rpm
python3-libs-3.9.19-19.cm2.x86_64.rpm
python3-setuptools-3.9.19-19.cm2.noarch.rpm
python3-pygments-2.4.2-7.cm2.noarch.rpm
which-2.21-8.cm2.x86_64.rpm
libselinux-3.2-1.cm2.x86_64.rpm
Expand Down
18 changes: 9 additions & 9 deletions toolkit/resources/manifests/package/toolchain_aarch64.txt
Original file line number Diff line number Diff line change
Expand Up @@ -510,28 +510,28 @@ procps-ng-devel-3.3.17-2.cm2.aarch64.rpm
procps-ng-lang-3.3.17-2.cm2.aarch64.rpm
pyproject-rpm-macros-1.0.0~rc1-4.cm2.noarch.rpm
python-markupsafe-debuginfo-2.1.0-1.cm2.aarch64.rpm
python3-3.9.19-18.cm2.aarch64.rpm
python3-3.9.19-19.cm2.aarch64.rpm
python3-audit-3.0.6-8.cm2.aarch64.rpm
python3-cracklib-2.9.7-5.cm2.aarch64.rpm
python3-curses-3.9.19-18.cm2.aarch64.rpm
python3-curses-3.9.19-19.cm2.aarch64.rpm
python3-Cython-0.29.33-2.cm2.aarch64.rpm
python3-debuginfo-3.9.19-18.cm2.aarch64.rpm
python3-devel-3.9.19-18.cm2.aarch64.rpm
python3-debuginfo-3.9.19-19.cm2.aarch64.rpm
python3-devel-3.9.19-19.cm2.aarch64.rpm
python3-gpg-1.16.0-2.cm2.aarch64.rpm
python3-jinja2-3.0.3-7.cm2.noarch.rpm
python3-libcap-ng-0.8.2-2.cm2.aarch64.rpm
python3-libs-3.9.19-18.cm2.aarch64.rpm
python3-libs-3.9.19-19.cm2.aarch64.rpm
python3-libxml2-2.10.4-10.cm2.aarch64.rpm
python3-lxml-4.9.1-1.cm2.aarch64.rpm
python3-magic-5.40-3.cm2.noarch.rpm
python3-markupsafe-2.1.0-1.cm2.aarch64.rpm
python3-newt-0.52.21-5.cm2.aarch64.rpm
python3-pip-3.9.19-18.cm2.noarch.rpm
python3-pip-3.9.19-19.cm2.noarch.rpm
python3-pygments-2.4.2-7.cm2.noarch.rpm
python3-rpm-4.18.0-4.cm2.aarch64.rpm
python3-setuptools-3.9.19-18.cm2.noarch.rpm
python3-test-3.9.19-18.cm2.aarch64.rpm
python3-tools-3.9.19-18.cm2.aarch64.rpm
python3-setuptools-3.9.19-19.cm2.noarch.rpm
python3-test-3.9.19-19.cm2.aarch64.rpm
python3-tools-3.9.19-19.cm2.aarch64.rpm
readline-8.1-1.cm2.aarch64.rpm
readline-debuginfo-8.1-1.cm2.aarch64.rpm
readline-devel-8.1-1.cm2.aarch64.rpm
Expand Down
18 changes: 9 additions & 9 deletions toolkit/resources/manifests/package/toolchain_x86_64.txt
Original file line number Diff line number Diff line change
Expand Up @@ -516,28 +516,28 @@ procps-ng-devel-3.3.17-2.cm2.x86_64.rpm
procps-ng-lang-3.3.17-2.cm2.x86_64.rpm
pyproject-rpm-macros-1.0.0~rc1-4.cm2.noarch.rpm
python-markupsafe-debuginfo-2.1.0-1.cm2.x86_64.rpm
python3-3.9.19-18.cm2.x86_64.rpm
python3-3.9.19-19.cm2.x86_64.rpm
python3-audit-3.0.6-8.cm2.x86_64.rpm
python3-cracklib-2.9.7-5.cm2.x86_64.rpm
python3-curses-3.9.19-18.cm2.x86_64.rpm
python3-curses-3.9.19-19.cm2.x86_64.rpm
python3-Cython-0.29.33-2.cm2.x86_64.rpm
python3-debuginfo-3.9.19-18.cm2.x86_64.rpm
python3-devel-3.9.19-18.cm2.x86_64.rpm
python3-debuginfo-3.9.19-19.cm2.x86_64.rpm
python3-devel-3.9.19-19.cm2.x86_64.rpm
python3-gpg-1.16.0-2.cm2.x86_64.rpm
python3-jinja2-3.0.3-7.cm2.noarch.rpm
python3-libcap-ng-0.8.2-2.cm2.x86_64.rpm
python3-libs-3.9.19-18.cm2.x86_64.rpm
python3-libs-3.9.19-19.cm2.x86_64.rpm
python3-libxml2-2.10.4-10.cm2.x86_64.rpm
python3-lxml-4.9.1-1.cm2.x86_64.rpm
python3-magic-5.40-3.cm2.noarch.rpm
python3-markupsafe-2.1.0-1.cm2.x86_64.rpm
python3-newt-0.52.21-5.cm2.x86_64.rpm
python3-pip-3.9.19-18.cm2.noarch.rpm
python3-pip-3.9.19-19.cm2.noarch.rpm
python3-pygments-2.4.2-7.cm2.noarch.rpm
python3-rpm-4.18.0-4.cm2.x86_64.rpm
python3-setuptools-3.9.19-18.cm2.noarch.rpm
python3-test-3.9.19-18.cm2.x86_64.rpm
python3-tools-3.9.19-18.cm2.x86_64.rpm
python3-setuptools-3.9.19-19.cm2.noarch.rpm
python3-test-3.9.19-19.cm2.x86_64.rpm
python3-tools-3.9.19-19.cm2.x86_64.rpm
readline-8.1-1.cm2.x86_64.rpm
readline-debuginfo-8.1-1.cm2.x86_64.rpm
readline-devel-8.1-1.cm2.x86_64.rpm
Expand Down
Loading