diff --git a/SPECS/python3/CVE-2025-12084.patch b/SPECS/python3/CVE-2025-12084.patch new file mode 100644 index 00000000000..86eb17faeeb --- /dev/null +++ b/SPECS/python3/CVE-2025-12084.patch @@ -0,0 +1,143 @@ +From f4eb9ab014545b521fb261b80adfa6d138e7e092 Mon Sep 17 00:00:00 2001 +From: Seth Michael Larson +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 +Co-authored-by: Jacob Walls <38668450+jacobtylerwalls@users.noreply.github.com> + +Signed-off-by: Azure Linux Security Servicing Account +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 + diff --git a/SPECS/python3/CVE-2026-0865.patch b/SPECS/python3/CVE-2026-0865.patch new file mode 100644 index 00000000000..3b8a92323e5 --- /dev/null +++ b/SPECS/python3/CVE-2026-0865.patch @@ -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 + +Signed-off-by: Azure Linux Security Servicing Account +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 + diff --git a/SPECS/python3/python3.spec b/SPECS/python3/python3.spec index 733524a5ec2..2d667dacd42 100644 --- a/SPECS/python3/python3.spec +++ b/SPECS/python3/python3.spec @@ -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 @@ -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 @@ -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 @@ -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 - 3.9.19-19 +- Patch for CVE-2026-0865, CVE-2025-12084 + * Wed Jan 28 2026 Azure Linux Security Servicing Account - 3.9.19-18 - Patch for CVE-2026-1299, CVE-2026-0672 diff --git a/toolkit/resources/manifests/package/pkggen_core_aarch64.txt b/toolkit/resources/manifests/package/pkggen_core_aarch64.txt index eab748377ea..7247ccd69cb 100644 --- a/toolkit/resources/manifests/package/pkggen_core_aarch64.txt +++ b/toolkit/resources/manifests/package/pkggen_core_aarch64.txt @@ -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 diff --git a/toolkit/resources/manifests/package/pkggen_core_x86_64.txt b/toolkit/resources/manifests/package/pkggen_core_x86_64.txt index ab676c8122f..c1556592e7e 100644 --- a/toolkit/resources/manifests/package/pkggen_core_x86_64.txt +++ b/toolkit/resources/manifests/package/pkggen_core_x86_64.txt @@ -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 diff --git a/toolkit/resources/manifests/package/toolchain_aarch64.txt b/toolkit/resources/manifests/package/toolchain_aarch64.txt index 01814143658..a216ededd63 100644 --- a/toolkit/resources/manifests/package/toolchain_aarch64.txt +++ b/toolkit/resources/manifests/package/toolchain_aarch64.txt @@ -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 diff --git a/toolkit/resources/manifests/package/toolchain_x86_64.txt b/toolkit/resources/manifests/package/toolchain_x86_64.txt index a718727b931..5f598b21d12 100644 --- a/toolkit/resources/manifests/package/toolchain_x86_64.txt +++ b/toolkit/resources/manifests/package/toolchain_x86_64.txt @@ -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