diff --git a/1459d1f1f1f00f36a25f616c0cea1b6d1609ff7d.patch b/1459d1f1f1f00f36a25f616c0cea1b6d1609ff7d.patch new file mode 100644 index 0000000000000000000000000000000000000000..a34f6c586c88ca25fb71b8d280b1093ee6ee44cd --- /dev/null +++ b/1459d1f1f1f00f36a25f616c0cea1b6d1609ff7d.patch @@ -0,0 +1,131 @@ +From 1459d1f1f1f00f36a25f616c0cea1b6d1609ff7d Mon Sep 17 00:00:00 2001 +From: Sebastian Pipping +Date: Tue, 7 Oct 2025 01:34:05 +0200 +Subject: [PATCH] [3.11] gh-139400: Make sure that parent parsers outlive their + subparsers in `pyexpat` (GH-139403) (#139612) + +* gh-139400: Make sure that parent parsers outlive their subparsers in `pyexpat` (#139403) + +* Modules/pyexpat.c: Disallow collection of in-use parent parsers. + +Within libexpat, a parser created via `XML_ExternalEntityParserCreate` +is relying on its parent parser throughout its entire lifetime. +Prior to this fix, is was possible for the parent parser to be +garbage-collected too early. + +(cherry picked from commit 6edb2ddb5f3695cf4938979d645f31d7fba43ec8) + +* Move news item from section "Core and Builtins" to section "Security" +--- + ...-09-29-00-01-28.gh-issue-139400.X2T-jO.rst | 4 +++ + Modules/pyexpat.c | 25 +++++++++++++ + 3 files changed, 65 insertions(+) + create mode 100644 Misc/NEWS.d/next/Security/2025-09-29-00-01-28.gh-issue-139400.X2T-jO.rst + +diff --git a/Misc/NEWS.d/next/Security/2025-09-29-00-01-28.gh-issue-139400.X2T-jO.rst b/Misc/NEWS.d/next/Security/2025-09-29-00-01-28.gh-issue-139400.X2T-jO.rst +new file mode 100644 +index 00000000000000..a5dea3b5f8147a +--- /dev/null ++++ b/Misc/NEWS.d/next/Security/2025-09-29-00-01-28.gh-issue-139400.X2T-jO.rst +@@ -0,0 +1,4 @@ ++:mod:`xml.parsers.expat`: Make sure that parent Expat parsers are only ++garbage-collected once they are no longer referenced by subparsers created ++by :meth:`~xml.parsers.expat.xmlparser.ExternalEntityParserCreate`. ++Patch by Sebastian Pipping. +diff --git a/Modules/pyexpat.c b/Modules/pyexpat.c +index bc14a691318814..d25e4554e385d0 100644 +--- a/Modules/pyexpat.c ++++ b/Modules/pyexpat.c +@@ -69,6 +69,15 @@ typedef struct { + PyObject_HEAD + + XML_Parser itself; ++ /* ++ * Strong reference to a parent `xmlparseobject` if this parser ++ * is a child parser. Set to NULL if this parser is a root parser. ++ * This is needed to keep the parent parser alive as long as it has ++ * at least one child parser. ++ * ++ * See https://github.com/python/cpython/issues/139400 for details. ++ */ ++ PyObject *parent; + int ordered_attributes; /* Return attributes as a list. */ + int specified_attributes; /* Report only specified attributes. */ + int in_callback; /* Is a callback active? */ +@@ -990,6 +999,11 @@ pyexpat_xmlparser_ExternalEntityParserCreate_impl(xmlparseobject *self, + return NULL; + } + ++ // The new subparser will make use of the parent XML_Parser inside of Expat. ++ // So we need to take subparsers into account with the reference counting ++ // of their parent parser. ++ Py_INCREF(self); ++ + new_parser->buffer_size = self->buffer_size; + new_parser->buffer_used = 0; + new_parser->buffer = NULL; +@@ -999,6 +1013,7 @@ pyexpat_xmlparser_ExternalEntityParserCreate_impl(xmlparseobject *self, + new_parser->ns_prefixes = self->ns_prefixes; + new_parser->itself = XML_ExternalEntityParserCreate(self->itself, context, + encoding); ++ new_parser->parent = (PyObject *)self; + new_parser->handlers = 0; + new_parser->intern = self->intern; + Py_XINCREF(new_parser->intern); +@@ -1007,11 +1022,13 @@ pyexpat_xmlparser_ExternalEntityParserCreate_impl(xmlparseobject *self, + new_parser->buffer = PyMem_Malloc(new_parser->buffer_size); + if (new_parser->buffer == NULL) { + Py_DECREF(new_parser); ++ Py_DECREF(self); + return PyErr_NoMemory(); + } + } + if (!new_parser->itself) { + Py_DECREF(new_parser); ++ Py_DECREF(self); + return PyErr_NoMemory(); + } + +@@ -1024,6 +1041,7 @@ pyexpat_xmlparser_ExternalEntityParserCreate_impl(xmlparseobject *self, + new_parser->handlers = PyMem_New(PyObject *, i); + if (!new_parser->handlers) { + Py_DECREF(new_parser); ++ Py_DECREF(self); + return PyErr_NoMemory(); + } + clear_handlers(new_parser, 1); +@@ -1202,6 +1220,7 @@ newxmlparseobject(pyexpat_state *state, const char *encoding, + /* namespace_separator is either NULL or contains one char + \0 */ + self->itself = XML_ParserCreate_MM(encoding, &ExpatMemoryHandler, + namespace_separator); ++ self->parent = NULL; + if (self->itself == NULL) { + PyErr_SetString(PyExc_RuntimeError, + "XML_ParserCreate failed"); +@@ -1237,6 +1256,7 @@ xmlparse_traverse(xmlparseobject *op, visitproc visit, void *arg) + for (int i = 0; handler_info[i].name != NULL; i++) { + Py_VISIT(op->handlers[i]); + } ++ Py_VISIT(op->parent); + Py_VISIT(Py_TYPE(op)); + return 0; + } +@@ -1246,6 +1266,10 @@ xmlparse_clear(xmlparseobject *op) + { + clear_handlers(op, 0); + Py_CLEAR(op->intern); ++ // NOTE: We cannot call Py_CLEAR(op->parent) prior to calling ++ // XML_ParserFree(op->itself), or a subparser could lose its parent ++ // XML_Parser while still making use of it internally. ++ // https://github.com/python/cpython/issues/139400 + return 0; + } + +@@ -1257,6 +1281,7 @@ xmlparse_dealloc(xmlparseobject *self) + if (self->itself != NULL) + XML_ParserFree(self->itself); + self->itself = NULL; ++ Py_CLEAR(self->parent); + + if (self->handlers != NULL) { + PyMem_Free(self->handlers); diff --git a/22d5724fbbc0a3c55c51f63a14c10e0c618770d7.patch b/22d5724fbbc0a3c55c51f63a14c10e0c618770d7.patch new file mode 100644 index 0000000000000000000000000000000000000000..de34b40b36f9329b1932ec5843e23475367af505 --- /dev/null +++ b/22d5724fbbc0a3c55c51f63a14c10e0c618770d7.patch @@ -0,0 +1,231 @@ +From 22d5724fbbc0a3c55c51f63a14c10e0c618770d7 Mon Sep 17 00:00:00 2001 +From: "Miss Islington (bot)" + <31488909+miss-islington@users.noreply.github.com> +Date: Tue, 7 Oct 2025 14:05:06 +0200 +Subject: [PATCH] [3.11] gh-135661: Fix CDATA section parsing in HTMLParser + (GH-135665) (GH-137774) (GH-139659) + +"] ]>" and "]] >" no longer end the CDATA section. + +Make CDATA section parsing context depending. +Add private method HTMLParser._set_support_cdata() to change the context. +If called with True, "<[CDATA[" starts a CDATA section which ends with "]]>". +If called with False, "<[CDATA[" starts a bogus comments which ends with ">". +(cherry picked from commit 0cbbfc462119b9107b373c24d2bda5a1271bed36) +(cherry picked from commit dcf24768c918c41821cda6fe6a1aa20ce26545dd) + +Co-authored-by: Serhiy Storchaka +--- + Lib/html/parser.py | 33 ++++++++- + Lib/test/test_htmlparser.py | 74 +++++++++++++++++-- + ...-06-18-13-34-55.gh-issue-135661.NZlpWf.rst | 5 ++ + 3 files changed, 104 insertions(+), 8 deletions(-) + create mode 100644 Misc/NEWS.d/next/Security/2025-06-18-13-34-55.gh-issue-135661.NZlpWf.rst + +diff --git a/Lib/html/parser.py b/Lib/html/parser.py +index 500b4c40abc367..8eae9dc55e568c 100644 +--- a/Lib/html/parser.py ++++ b/Lib/html/parser.py +@@ -127,6 +127,7 @@ def reset(self): + self.lasttag = '???' + self.interesting = interesting_normal + self.cdata_elem = None ++ self._support_cdata = True + self._escapable = True + _markupbase.ParserBase.reset(self) + +@@ -164,6 +165,19 @@ def clear_cdata_mode(self): + self.cdata_elem = None + self._escapable = True + ++ def _set_support_cdata(self, flag=True): ++ """Enable or disable support of the CDATA sections. ++ If enabled, "<[CDATA[" starts a CDATA section which ends with "]]>". ++ If disabled, "<[CDATA[" starts a bogus comments which ends with ">". ++ ++ This method is not called by default. Its purpose is to be called ++ in custom handle_starttag() and handle_endtag() methods, with ++ value that depends on the adjusted current node. ++ See https://html.spec.whatwg.org/multipage/parsing.html#markup-declaration-open-state ++ for details. ++ """ ++ self._support_cdata = flag ++ + # Internal -- handle data as far as reasonable. May leave state + # and data to be processed by a subsequent call. If 'end' is + # true, force handling all data as if followed by EOF marker. +@@ -238,7 +252,7 @@ def goahead(self, end): + j -= len(suffix) + break + self.handle_comment(rawdata[i+4:j]) +- elif startswith("', i+9) ++ if j < 0: ++ return -1 ++ self.unknown_decl(rawdata[i+3: j]) ++ return j + 3 + elif rawdata[i:i+9].lower() == ' + gtpos = rawdata.find('>', i+9) +@@ -323,6 +341,15 @@ def parse_html_declaration(self, i): + return -1 + self.handle_decl(rawdata[i+2:gtpos]) + return gtpos+1 ++ elif rawdata[i:i+3] == '', i+3) ++ if j < 0: ++ return -1 ++ if rawdata[j-1] == ']': ++ self.unknown_decl(rawdata[i+3: j-1]) ++ else: ++ self.handle_comment(rawdata[i+2: j]) ++ return j + 1 + else: + return self.parse_bogus_comment(i) + +diff --git a/Lib/test/test_htmlparser.py b/Lib/test/test_htmlparser.py +index 4a67420ae14fe1..a7be7a6e20224a 100644 +--- a/Lib/test/test_htmlparser.py ++++ b/Lib/test/test_htmlparser.py +@@ -9,10 +9,13 @@ + + class EventCollector(html.parser.HTMLParser): + +- def __init__(self, *args, **kw): ++ def __init__(self, *args, autocdata=False, **kw): ++ self.autocdata = autocdata + self.events = [] + self.append = self.events.append + html.parser.HTMLParser.__init__(self, *args, **kw) ++ if autocdata: ++ self._set_support_cdata(False) + + def get_events(self): + # Normalize the list of events so that buffer artefacts don't +@@ -33,12 +36,16 @@ def get_events(self): + + def handle_starttag(self, tag, attrs): + self.append(("starttag", tag, attrs)) ++ if self.autocdata and tag == 'svg': ++ self._set_support_cdata(True) + + def handle_startendtag(self, tag, attrs): + self.append(("startendtag", tag, attrs)) + + def handle_endtag(self, tag): + self.append(("endtag", tag)) ++ if self.autocdata and tag == 'svg': ++ self._set_support_cdata(False) + + # all other markup + +@@ -739,10 +746,6 @@ def test_eof_in_declarations(self): + ('' + '' +@@ -804,8 +819,57 @@ def test_broken_condcoms(self): + ('startendtag', 'img', [('src', 'mammoth.bmp')]), + ('unknown decl', 'endif') + ] ++ + self._run_check(html, expected) + ++ @support.subTests('content', [ ++ 'just some plain text', ++ '', ++ '¬-an-entity-ref;', ++ "", ++ '', ++ '[[I have many brackets]]', ++ 'I have a > in the middle', ++ 'I have a ]] in the middle', ++ '] ]>', ++ ']] >', ++ ('\n' ++ ' if (a < b && a > b) {\n' ++ ' printf("[How?]");\n' ++ ' }\n'), ++ ]) ++ def test_cdata_section_content(self, content): ++ # See "13.2.5.42 Markup declaration open state", ++ # "13.2.5.69 CDATA section state", and issue bpo-32876. ++ html = f'{content}' ++ expected = [ ++ ('starttag', 'svg', []), ++ ('starttag', 'text', [('y', '100')]), ++ ('unknown decl', 'CDATA[' + content), ++ ('endtag', 'text'), ++ ('endtag', 'svg'), ++ ] ++ self._run_check(html, expected) ++ self._run_check(html, expected, collector=EventCollector(autocdata=True)) ++ ++ def test_cdata_section(self): ++ # See "13.2.5.42 Markup declaration open state". ++ html = ('bar]]>' ++ 'foo<br>bar' ++ 'bar]]>') ++ expected = [ ++ ('comment', '[CDATA[foo'), ++ ('starttag', 'svg', []), ++ ('starttag', 'text', [('y', '100')]), ++ ('unknown decl', 'CDATA[foo
bar'), ++ ('endtag', 'text'), ++ ('endtag', 'svg'), ++ ('comment', '[CDATA[foo'), ++ ] ++ self._run_check(html, expected, collector=EventCollector(autocdata=True)) ++ + def test_convert_charrefs_dropped_text(self): + # #23144: make sure that all the events are triggered when + # convert_charrefs is True, even if we don't call .close() +diff --git a/Misc/NEWS.d/next/Security/2025-06-18-13-34-55.gh-issue-135661.NZlpWf.rst b/Misc/NEWS.d/next/Security/2025-06-18-13-34-55.gh-issue-135661.NZlpWf.rst +new file mode 100644 +index 00000000000000..fe000d936aae9d +--- /dev/null ++++ b/Misc/NEWS.d/next/Security/2025-06-18-13-34-55.gh-issue-135661.NZlpWf.rst +@@ -0,0 +1,5 @@ ++Fix CDATA section parsing in :class:`html.parser.HTMLParser` according to ++the HTML5 standard: ``] ]>`` and ``]] >`` no longer end the CDATA section. ++Add private method ``_set_support_cdata()`` which can be used to specify ++how to parse ``<[CDATA[`` --- as a CDATA section in foreign content ++(SVG or MathML) or as a bogus comment in the HTML namespace. diff --git a/python3.11.spec b/python3.11.spec index 4f684bba1a4b8382276dbabd97a1096aa6264e25..07143f0b3f1e76a2f1ed8a0903a2acb4ae22f70c 100644 --- a/python3.11.spec +++ b/python3.11.spec @@ -64,7 +64,7 @@ Summary: Version %{pybasever} of the Python interpreter Name: python%{pybasever} Version: %{src_version} -Release: 24%{?dist} +Release: 25%{?dist} License: Python-2.0.1 URL: https://www.python.org/ @@ -115,7 +115,9 @@ Patch0036: https://github.com/python/cpython/commit/5f90abaa786f994db3907fc31e2e Patch0037: https://github.com/python/cpython/commit/c5655aa6ad120d2ed7f255bebd6e8b71a9c07dde.patch # https://github.com/python/cpython/commit/bc4a703a934a59657ecd018320ef990bc5542803 Patch0038: https://github.com/python/cpython/commit/bc4a703a934a59657ecd018320ef990bc5542803-mod.patch -Patch0039: CVE-2025-8291-3.11-gh-139700-Check-consistency-of-the-zip64-end-of.patch +Patch0039: https://github.com/python/cpython/commit/1459d1f1f1f00f36a25f616c0cea1b6d1609ff7d.patch +Patch0040: https://github.com/python/cpython/commit/22d5724fbbc0a3c55c51f63a14c10e0c618770d7.patch +Patch0041: CVE-2025-8291-3.11-gh-139700-Check-consistency-of-the-zip64-end-of.patch Patch3000: 00001-rpath.patch Patch3001: 00251-change-user-install-location.patch @@ -1148,6 +1150,13 @@ LD_LIBRARY_PATH=$(pwd)/normal $(pwd)/normal/python -m test.regrtest \ %endif %changelog +* Tue Oct 28 2025 Tracker Robot - 3.11.6-25 +- [Type] security +- [DESC] Apply patches from rpm-tracker +- [Bug Fix] 1459d1f1f1f00f36a25f616c0cea1b6d1609ff7d.patch: [3.11] gh-139400: Make sure that parent parsers outlive their subparsers in pyexpat (GH-139403) (#139612) +- [Bug Fix] 22d5724fbbc0a3c55c51f63a14c10e0c618770d7.patch: [3.11] gh-135661: Fix CDATA section parsing in HTMLParser (GH-135665) (GH-137774) (GH-139659) +- [CVE Fix] 1d29afb0d6218aa8fb5e1e4a6133a4778d89bb46.patch: [3.11] gh-139700: Check consistency of the zip64 end of central directory record (GH-139702) (GH-139708) (GH-139713) + * Wed Oct 22 2025 Shuo Wang - 3.11.6-24 - fix CVE-2025-8291 - gh-139700: Check consistency of the zip64 end of