From 77dc13a527c22f461ca53b3c4905e9c45df15abe Mon Sep 17 00:00:00 2001 From: Lumir Balhar Date: Tue, 3 Dec 2024 20:59:35 +0100 Subject: [PATCH 01/33] Update to 3.11.11 Fixes: rhbz#2321655 --- python3.11.spec | 6 +++++- sources | 4 ++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/python3.11.spec b/python3.11.spec index acebdec..fff1430 100644 --- a/python3.11.spec +++ b/python3.11.spec @@ -13,7 +13,7 @@ URL: https://www.python.org/ # WARNING When rebasing to a new Python version, # remember to update the python3-docs package as well -%global general_version %{pybasever}.10 +%global general_version %{pybasever}.11 #global prerel ... %global upstream_version %{general_version}%{?prerel} Version: %{general_version}%{?prerel:~%{prerel}} @@ -1645,6 +1645,10 @@ CheckPython optimized # ====================================================== %changelog +* Tue Dec 03 2024 Lumír Balhar - 3.11.11-1 +- Update to 3.11.11 +- Fixes: rhbz#2321655 + * Mon Sep 09 2024 Tomáš Hrnčiar - 3.11.10-1 - Update to 3.11.10 diff --git a/sources b/sources index 24b6016..cab6ce8 100644 --- a/sources +++ b/sources @@ -1,2 +1,2 @@ -SHA512 (Python-3.11.10.tar.xz) = 6ce77cced1ce90bb5eea38504dfc1bc19c872149a5a63fdd8353ac8c772c54ab7a42176e141c7f6f898d31761bf93e1739b238920fbeefbedd6016ad033c1de0 -SHA512 (Python-3.11.10.tar.xz.asc) = 3a9efe1dd39fd6883ae3fc8dd7f6e25af7e06c6e6049cf9a31a1a82e6d7c84f85ac838d2a71127977d93ce77233a8bbff86a10a80d24fcee85a4e70fcbd1db19 +SHA512 (Python-3.11.11.tar.xz) = 3ff90f15f725fa8d06686158aaddb887a247b03ca4dc1fdfd81a8efb53373db3e8673bd0b3de30bb7669f3f07d9854e9d8a2dbcd49b18d15b8172787a53a0a9e +SHA512 (Python-3.11.11.tar.xz.asc) = d71b0b42537fb636e8c469d62d13ff020149e4fb9d87eb17f8c999301195e418d134dbdb7e4ab49b06de16e96f8ef6bbcf2a749956fffca2ce03185f191c181d From 65fcf85d2e61dd2580aa9d42554fdbc79e7dc9d6 Mon Sep 17 00:00:00 2001 From: Fedora Release Engineering Date: Sat, 18 Jan 2025 21:08:16 +0000 Subject: [PATCH 02/33] Rebuilt for https://fedoraproject.org/wiki/Fedora_42_Mass_Rebuild --- python3.11.spec | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/python3.11.spec b/python3.11.spec index fff1430..754494d 100644 --- a/python3.11.spec +++ b/python3.11.spec @@ -17,7 +17,7 @@ URL: https://www.python.org/ #global prerel ... %global upstream_version %{general_version}%{?prerel} Version: %{general_version}%{?prerel:~%{prerel}} -Release: 1%{?dist} +Release: 2%{?dist} License: Python-2.0.1 @@ -1645,6 +1645,9 @@ CheckPython optimized # ====================================================== %changelog +* Sat Jan 18 2025 Fedora Release Engineering - 3.11.11-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_42_Mass_Rebuild + * Tue Dec 03 2024 Lumír Balhar - 3.11.11-1 - Update to 3.11.11 - Fixes: rhbz#2321655 From 9cf2fe58ab8f88a03e6e680f7f3c6a5b65ed596f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Esser?= Date: Sat, 1 Feb 2025 19:56:57 +0100 Subject: [PATCH 03/33] Add explicit BR: libxcrypt-devel MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Björn Esser --- python3.11.spec | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/python3.11.spec b/python3.11.spec index 754494d..c046dcf 100644 --- a/python3.11.spec +++ b/python3.11.spec @@ -17,7 +17,7 @@ URL: https://www.python.org/ #global prerel ... %global upstream_version %{general_version}%{?prerel} Version: %{general_version}%{?prerel:~%{prerel}} -Release: 2%{?dist} +Release: 3%{?dist} License: Python-2.0.1 @@ -214,6 +214,7 @@ BuildRequires: libnsl2-devel BuildRequires: libtirpc-devel BuildRequires: libGL-devel BuildRequires: libuuid-devel +BuildRequires: libxcrypt-devel BuildRequires: libX11-devel BuildRequires: make BuildRequires: mpdecimal-devel @@ -1645,6 +1646,9 @@ CheckPython optimized # ====================================================== %changelog +* Sat Feb 01 2025 Björn Esser - 3.11.11-3 +- Add explicit BR: libxcrypt-devel + * Sat Jan 18 2025 Fedora Release Engineering - 3.11.11-2 - Rebuilt for https://fedoraproject.org/wiki/Fedora_42_Mass_Rebuild From 976de1a01d96ed23c81877b5e53b2c8190cfc6f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Mon, 3 Feb 2025 11:13:44 +0000 Subject: [PATCH 04/33] Ensure this package is built with Tk 8 - Fixes: rhbz#2337758 --- python3.11.spec | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python3.11.spec b/python3.11.spec index c046dcf..e8f87c4 100644 --- a/python3.11.spec +++ b/python3.11.spec @@ -228,9 +228,9 @@ BuildRequires: sqlite-devel BuildRequires: gdb BuildRequires: tar -BuildRequires: tcl-devel +BuildRequires: tcl-devel < 1:9 BuildRequires: tix-devel -BuildRequires: tk-devel +BuildRequires: tk-devel < 1:9 BuildRequires: tzdata %if %{with valgrind} From 9406dc1ea3694ee62808f3f1fc11234430ce7353 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Thu, 6 Feb 2025 12:04:28 +0100 Subject: [PATCH 05/33] Rebuilt with mpdecimal 4.0.0 --- python3.11.spec | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/python3.11.spec b/python3.11.spec index e8f87c4..b8aeda2 100644 --- a/python3.11.spec +++ b/python3.11.spec @@ -17,7 +17,7 @@ URL: https://www.python.org/ #global prerel ... %global upstream_version %{general_version}%{?prerel} Version: %{general_version}%{?prerel:~%{prerel}} -Release: 3%{?dist} +Release: 4%{?dist} License: Python-2.0.1 @@ -1646,6 +1646,9 @@ CheckPython optimized # ====================================================== %changelog +* Thu Feb 06 2025 Miro Hrončok - 3.11.11-4 +- Rebuilt with mpdecimal 4.0.0 + * Sat Feb 01 2025 Björn Esser - 3.11.11-3 - Add explicit BR: libxcrypt-devel From 3fe7e179a078f68dd30a66b166cc9912f1f85961 Mon Sep 17 00:00:00 2001 From: Charalampos Stratakis Date: Mon, 10 Feb 2025 23:27:07 +0100 Subject: [PATCH 06/33] Security fix for CVE-2025-0938 Fixes: rhbz#2343272 --- ...-and-in-domain-names-for-parsed-urls.patch | 119 ++++++++++++++++++ python3.11.spec | 10 +- 2 files changed, 128 insertions(+), 1 deletion(-) create mode 100644 00450-cve-2025-0938-disallow-square-brackets-and-in-domain-names-for-parsed-urls.patch diff --git a/00450-cve-2025-0938-disallow-square-brackets-and-in-domain-names-for-parsed-urls.patch b/00450-cve-2025-0938-disallow-square-brackets-and-in-domain-names-for-parsed-urls.patch new file mode 100644 index 0000000..6ed829d --- /dev/null +++ b/00450-cve-2025-0938-disallow-square-brackets-and-in-domain-names-for-parsed-urls.patch @@ -0,0 +1,119 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Seth Michael Larson +Date: Fri, 31 Jan 2025 11:41:34 -0600 +Subject: [PATCH] 00450: CVE-2025-0938: Disallow square brackets ([ and ]) in + domain names for parsed URLs + +Co-authored-by: Peter Bierma +--- + Lib/test/test_urlparse.py | 37 ++++++++++++++++++- + Lib/urllib/parse.py | 20 +++++++++- + ...-01-28-14-08-03.gh-issue-105704.EnhHxu.rst | 4 ++ + 3 files changed, 58 insertions(+), 3 deletions(-) + create mode 100644 Misc/NEWS.d/next/Security/2025-01-28-14-08-03.gh-issue-105704.EnhHxu.rst + +diff --git a/Lib/test/test_urlparse.py b/Lib/test/test_urlparse.py +index 2376dad81b..a283063f24 100644 +--- a/Lib/test/test_urlparse.py ++++ b/Lib/test/test_urlparse.py +@@ -1224,16 +1224,51 @@ def test_invalid_bracketed_hosts(self): + self.assertRaises(ValueError, urllib.parse.urlsplit, 'Scheme://user@[0439:23af::2309::fae7:1234]/Path?Query') + self.assertRaises(ValueError, urllib.parse.urlsplit, 'Scheme://user@[0439:23af:2309::fae7:1234:2342:438e:192.0.2.146]/Path?Query') + self.assertRaises(ValueError, urllib.parse.urlsplit, 'Scheme://user@]v6a.ip[/Path') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://prefix.[v6a.ip]') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://[v6a.ip].suffix') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://prefix.[v6a.ip]/') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://[v6a.ip].suffix/') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://prefix.[v6a.ip]?') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://[v6a.ip].suffix?') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://prefix.[::1]') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://[::1].suffix') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://prefix.[::1]/') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://[::1].suffix/') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://prefix.[::1]?') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://[::1].suffix?') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://prefix.[::1]:a') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://[::1].suffix:a') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://prefix.[::1]:a1') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://[::1].suffix:a1') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://prefix.[::1]:1a') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://[::1].suffix:1a') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://prefix.[::1]:') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://[::1].suffix:/') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://prefix.[::1]:?') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://user@prefix.[v6a.ip]') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://user@[v6a.ip].suffix') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://[v6a.ip') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://v6a.ip]') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://]v6a.ip[') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://]v6a.ip') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://v6a.ip[') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://prefix.[v6a.ip') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://v6a.ip].suffix') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://prefix]v6a.ip[suffix') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://prefix]v6a.ip') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://v6a.ip[suffix') + + def test_splitting_bracketed_hosts(self): +- p1 = urllib.parse.urlsplit('scheme://user@[v6a.ip]/path?query') ++ p1 = urllib.parse.urlsplit('scheme://user@[v6a.ip]:1234/path?query') + self.assertEqual(p1.hostname, 'v6a.ip') + self.assertEqual(p1.username, 'user') + self.assertEqual(p1.path, '/path') ++ self.assertEqual(p1.port, 1234) + p2 = urllib.parse.urlsplit('scheme://user@[0439:23af:2309::fae7%test]/path?query') + self.assertEqual(p2.hostname, '0439:23af:2309::fae7%test') + self.assertEqual(p2.username, 'user') + self.assertEqual(p2.path, '/path') ++ self.assertIs(p2.port, None) + p3 = urllib.parse.urlsplit('scheme://user@[0439:23af:2309::fae7:1234:192.0.2.146%test]/path?query') + self.assertEqual(p3.hostname, '0439:23af:2309::fae7:1234:192.0.2.146%test') + self.assertEqual(p3.username, 'user') +diff --git a/Lib/urllib/parse.py b/Lib/urllib/parse.py +index abf1d1b546..724cce8d39 100644 +--- a/Lib/urllib/parse.py ++++ b/Lib/urllib/parse.py +@@ -436,6 +436,23 @@ def _checknetloc(netloc): + raise ValueError("netloc '" + netloc + "' contains invalid " + + "characters under NFKC normalization") + ++def _check_bracketed_netloc(netloc): ++ # Note that this function must mirror the splitting ++ # done in NetlocResultMixins._hostinfo(). ++ hostname_and_port = netloc.rpartition('@')[2] ++ before_bracket, have_open_br, bracketed = hostname_and_port.partition('[') ++ if have_open_br: ++ # No data is allowed before a bracket. ++ if before_bracket: ++ raise ValueError("Invalid IPv6 URL") ++ hostname, _, port = bracketed.partition(']') ++ # No data is allowed after the bracket but before the port delimiter. ++ if port and not port.startswith(":"): ++ raise ValueError("Invalid IPv6 URL") ++ else: ++ hostname, _, port = hostname_and_port.partition(':') ++ _check_bracketed_host(hostname) ++ + # Valid bracketed hosts are defined in + # https://www.rfc-editor.org/rfc/rfc3986#page-49 and https://url.spec.whatwg.org/ + def _check_bracketed_host(hostname): +@@ -496,8 +513,7 @@ def urlsplit(url, scheme='', allow_fragments=True): + (']' in netloc and '[' not in netloc)): + raise ValueError("Invalid IPv6 URL") + if '[' in netloc and ']' in netloc: +- bracketed_host = netloc.partition('[')[2].partition(']')[0] +- _check_bracketed_host(bracketed_host) ++ _check_bracketed_netloc(netloc) + if allow_fragments and '#' in url: + url, fragment = url.split('#', 1) + if '?' in url: +diff --git a/Misc/NEWS.d/next/Security/2025-01-28-14-08-03.gh-issue-105704.EnhHxu.rst b/Misc/NEWS.d/next/Security/2025-01-28-14-08-03.gh-issue-105704.EnhHxu.rst +new file mode 100644 +index 0000000000..bff1bc6b0d +--- /dev/null ++++ b/Misc/NEWS.d/next/Security/2025-01-28-14-08-03.gh-issue-105704.EnhHxu.rst +@@ -0,0 +1,4 @@ ++When using :func:`urllib.parse.urlsplit` and :func:`urllib.parse.urlparse` host ++parsing would not reject domain names containing square brackets (``[`` and ++``]``). Square brackets are only valid for IPv6 and IPvFuture hosts according to ++`RFC 3986 Section 3.2.2 `__. diff --git a/python3.11.spec b/python3.11.spec index b8aeda2..2877d9d 100644 --- a/python3.11.spec +++ b/python3.11.spec @@ -17,7 +17,7 @@ URL: https://www.python.org/ #global prerel ... %global upstream_version %{general_version}%{?prerel} Version: %{general_version}%{?prerel:~%{prerel}} -Release: 4%{?dist} +Release: 5%{?dist} License: Python-2.0.1 @@ -331,6 +331,10 @@ Patch371: 00371-revert-bpo-1596321-fix-threading-_shutdown-for-the-main-thread-g # get_cid() returns VMADDR_CID_ANY (-1). Patch438: 00438-fix-threadedvsocksocketstreamtest-gh-119465-gh-119479-119484.patch +# 00450 # 4ab8663661748eb994c09e4ae89f59eb84c5d3ea +# CVE-2025-0938: Disallow square brackets ([ and ]) in domain names for parsed URLs +Patch450: 00450-cve-2025-0938-disallow-square-brackets-and-in-domain-names-for-parsed-urls.patch + # (New patches go here ^^^) # # When adding new patches to "python" and "python3" in Fedora, EL, etc., @@ -1646,6 +1650,10 @@ CheckPython optimized # ====================================================== %changelog +* Mon Feb 10 2025 Charalampos Stratakis - 3.11.11-5 +- Security fix for CVE-2025-0938 +- Fixes: rhbz#2343272 + * Thu Feb 06 2025 Miro Hrončok - 3.11.11-4 - Rebuilt with mpdecimal 4.0.0 From d0bc099cf5b2410276f33c11587070c8a8d402e2 Mon Sep 17 00:00:00 2001 From: Charalampos Stratakis Date: Tue, 1 Apr 2025 01:22:06 +0200 Subject: [PATCH 07/33] Properly apply exported CFLAGS for dtrace/systemtap builds Fixes: rhbz#2356302 --- ...d-cflags-for-dtrace-systemtap-builds.patch | 52 +++++++++++++++++++ python3.11.spec | 18 ++++++- 2 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 00452-properly-apply-exported-cflags-for-dtrace-systemtap-builds.patch diff --git a/00452-properly-apply-exported-cflags-for-dtrace-systemtap-builds.patch b/00452-properly-apply-exported-cflags-for-dtrace-systemtap-builds.patch new file mode 100644 index 0000000..e36195b --- /dev/null +++ b/00452-properly-apply-exported-cflags-for-dtrace-systemtap-builds.patch @@ -0,0 +1,52 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: "Miss Islington (bot)" + <31488909+miss-islington@users.noreply.github.com> +Date: Mon, 31 Mar 2025 20:29:04 +0200 +Subject: [PATCH] 00452: Properly apply exported CFLAGS for dtrace/systemtap + builds + +When using --with-dtrace the resulting object file could be missing +specific CFLAGS exported by the build system due to the systemtap +script using specific defaults. + +Exporting the CC and CFLAGS variables before the dtrace invocation +allows us to properly apply CFLAGS exported by the build system +even when cross-compiling. + +Co-authored-by: stratakis +--- + Makefile.pre.in | 4 ++-- + .../next/Build/2025-03-31-19-22-41.gh-issue-131865.PIJy7X.rst | 2 ++ + 2 files changed, 4 insertions(+), 2 deletions(-) + create mode 100644 Misc/NEWS.d/next/Build/2025-03-31-19-22-41.gh-issue-131865.PIJy7X.rst + +diff --git a/Makefile.pre.in b/Makefile.pre.in +index 81d4d50f82..0bd3447638 100644 +--- a/Makefile.pre.in ++++ b/Makefile.pre.in +@@ -1453,7 +1453,7 @@ Python/frozen.o: $(FROZEN_FILES_OUT) + # an include guard, so we can't use a pipeline to transform its output. + Include/pydtrace_probes.h: $(srcdir)/Include/pydtrace.d + $(MKDIR_P) Include +- $(DTRACE) $(DFLAGS) -o $@ -h -s $< ++ CC="$(CC)" CFLAGS="$(CFLAGS)" $(DTRACE) $(DFLAGS) -o $@ -h -s $< + : sed in-place edit with POSIX-only tools + sed 's/PYTHON_/PyDTrace_/' $@ > $@.tmp + mv $@.tmp $@ +@@ -1463,7 +1463,7 @@ Python/import.o: $(srcdir)/Include/pydtrace.h + Modules/gcmodule.o: $(srcdir)/Include/pydtrace.h + + Python/pydtrace.o: $(srcdir)/Include/pydtrace.d $(DTRACE_DEPS) +- $(DTRACE) $(DFLAGS) -o $@ -G -s $< $(DTRACE_DEPS) ++ CC="$(CC)" CFLAGS="$(CFLAGS)" $(DTRACE) $(DFLAGS) -o $@ -G -s $< $(DTRACE_DEPS) + + Objects/typeobject.o: Objects/typeslots.inc + +diff --git a/Misc/NEWS.d/next/Build/2025-03-31-19-22-41.gh-issue-131865.PIJy7X.rst b/Misc/NEWS.d/next/Build/2025-03-31-19-22-41.gh-issue-131865.PIJy7X.rst +new file mode 100644 +index 0000000000..a287e0b228 +--- /dev/null ++++ b/Misc/NEWS.d/next/Build/2025-03-31-19-22-41.gh-issue-131865.PIJy7X.rst +@@ -0,0 +1,2 @@ ++The DTrace build now properly passes the ``CC`` and ``CFLAGS`` variables ++to the ``dtrace`` command when utilizing SystemTap on Linux. diff --git a/python3.11.spec b/python3.11.spec index 2877d9d..19fd162 100644 --- a/python3.11.spec +++ b/python3.11.spec @@ -17,7 +17,7 @@ URL: https://www.python.org/ #global prerel ... %global upstream_version %{general_version}%{?prerel} Version: %{general_version}%{?prerel:~%{prerel}} -Release: 5%{?dist} +Release: 6%{?dist} License: Python-2.0.1 @@ -335,6 +335,18 @@ Patch438: 00438-fix-threadedvsocksocketstreamtest-gh-119465-gh-119479-119484.pat # CVE-2025-0938: Disallow square brackets ([ and ]) in domain names for parsed URLs Patch450: 00450-cve-2025-0938-disallow-square-brackets-and-in-domain-names-for-parsed-urls.patch +# 00452 # eb11d070c5af7d1b5e47f4e02186152d08eaf793 +# Properly apply exported CFLAGS for dtrace/systemtap builds +# +# When using --with-dtrace the resulting object file could be missing +# specific CFLAGS exported by the build system due to the systemtap +# script using specific defaults. +# +# Exporting the CC and CFLAGS variables before the dtrace invocation +# allows us to properly apply CFLAGS exported by the build system +# even when cross-compiling. +Patch452: 00452-properly-apply-exported-cflags-for-dtrace-systemtap-builds.patch + # (New patches go here ^^^) # # When adding new patches to "python" and "python3" in Fedora, EL, etc., @@ -1650,6 +1662,10 @@ CheckPython optimized # ====================================================== %changelog +* Mon Mar 31 2025 Charalampos Stratakis - 3.11.11-6 +- Properly apply exported CFLAGS for dtrace/systemtap builds +- Fixes: rhbz#2356302 + * Mon Feb 10 2025 Charalampos Stratakis - 3.11.11-5 - Security fix for CVE-2025-0938 - Fixes: rhbz#2343272 From 6cfe05c332fad5e6c45916c9ed73b4b42531ea7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Wed, 9 Apr 2025 09:41:08 +0200 Subject: [PATCH 08/33] Update to 3.11.12 Patches 438 and 350 merged upstream. --- ...treamtest-gh-119465-gh-119479-119484.patch | 66 ---------- ...-and-in-domain-names-for-parsed-urls.patch | 119 ------------------ python3.11.spec | 22 +--- sources | 4 +- 4 files changed, 7 insertions(+), 204 deletions(-) delete mode 100644 00438-fix-threadedvsocksocketstreamtest-gh-119465-gh-119479-119484.patch delete mode 100644 00450-cve-2025-0938-disallow-square-brackets-and-in-domain-names-for-parsed-urls.patch diff --git a/00438-fix-threadedvsocksocketstreamtest-gh-119465-gh-119479-119484.patch b/00438-fix-threadedvsocksocketstreamtest-gh-119465-gh-119479-119484.patch deleted file mode 100644 index a4830ed..0000000 --- a/00438-fix-threadedvsocksocketstreamtest-gh-119465-gh-119479-119484.patch +++ /dev/null @@ -1,66 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: "Miss Islington (bot)" - <31488909+miss-islington@users.noreply.github.com> -Date: Fri, 24 May 2024 01:23:55 +0200 -Subject: [PATCH] 00438: Fix ThreadedVSOCKSocketStreamTest (GH-119465) - (GH-119479) (#119484) - -Fix ThreadedVSOCKSocketStreamTest: if get_cid() returns the host -address or the "any" address, use the local communication address -(loopback): VMADDR_CID_LOCAL. - -On Linux 6.9, apparently, the /dev/vsock device is now available but -get_cid() returns VMADDR_CID_ANY (-1). - -(cherry picked from commit c750061047ee520d8299334df4b112fd983d7e48) - -Co-authored-by: Victor Stinner -(cherry picked from commit e94dbe4ed83460f18bd72563c5f09f6cdc71f604) - -Co-authored-by: Victor Stinner ---- - Lib/test/test_socket.py | 10 ++++++---- - 1 file changed, 6 insertions(+), 4 deletions(-) - -diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py -index cc803d8753..f40364055e 100644 ---- a/Lib/test/test_socket.py -+++ b/Lib/test/test_socket.py -@@ -43,6 +43,7 @@ - # test unicode string and carriage return - MSG = 'Michael Gilfix was here\u1234\r\n'.encode('utf-8') - -+VMADDR_CID_LOCAL = 1 - VSOCKPORT = 1234 - AIX = platform.system() == "AIX" - WSL = "microsoft-standard-WSL" in platform.release() -@@ -127,8 +128,8 @@ def _have_socket_qipcrtr(): - - def _have_socket_vsock(): - """Check whether AF_VSOCK sockets are supported on this host.""" -- ret = get_cid() is not None -- return ret -+ cid = get_cid() -+ return (cid is not None) - - - def _have_socket_bluetooth(): -@@ -471,8 +472,6 @@ def clientTearDown(self): - @unittest.skipIf(WSL, 'VSOCK does not work on Microsoft WSL') - @unittest.skipUnless(HAVE_SOCKET_VSOCK, - 'VSOCK sockets required for this test.') --@unittest.skipUnless(get_cid() != 2, -- "This test can only be run on a virtual guest.") - class ThreadedVSOCKSocketStreamTest(unittest.TestCase, ThreadableTest): - - def __init__(self, methodName='runTest'): -@@ -494,6 +493,9 @@ def clientSetUp(self): - self.cli = socket.socket(socket.AF_VSOCK, socket.SOCK_STREAM) - self.addCleanup(self.cli.close) - cid = get_cid() -+ if cid in (socket.VMADDR_CID_HOST, socket.VMADDR_CID_ANY): -+ # gh-119461: Use the local communication address (loopback) -+ cid = VMADDR_CID_LOCAL - self.cli.connect((cid, VSOCKPORT)) - - def testStream(self): diff --git a/00450-cve-2025-0938-disallow-square-brackets-and-in-domain-names-for-parsed-urls.patch b/00450-cve-2025-0938-disallow-square-brackets-and-in-domain-names-for-parsed-urls.patch deleted file mode 100644 index 6ed829d..0000000 --- a/00450-cve-2025-0938-disallow-square-brackets-and-in-domain-names-for-parsed-urls.patch +++ /dev/null @@ -1,119 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Seth Michael Larson -Date: Fri, 31 Jan 2025 11:41:34 -0600 -Subject: [PATCH] 00450: CVE-2025-0938: Disallow square brackets ([ and ]) in - domain names for parsed URLs - -Co-authored-by: Peter Bierma ---- - Lib/test/test_urlparse.py | 37 ++++++++++++++++++- - Lib/urllib/parse.py | 20 +++++++++- - ...-01-28-14-08-03.gh-issue-105704.EnhHxu.rst | 4 ++ - 3 files changed, 58 insertions(+), 3 deletions(-) - create mode 100644 Misc/NEWS.d/next/Security/2025-01-28-14-08-03.gh-issue-105704.EnhHxu.rst - -diff --git a/Lib/test/test_urlparse.py b/Lib/test/test_urlparse.py -index 2376dad81b..a283063f24 100644 ---- a/Lib/test/test_urlparse.py -+++ b/Lib/test/test_urlparse.py -@@ -1224,16 +1224,51 @@ def test_invalid_bracketed_hosts(self): - self.assertRaises(ValueError, urllib.parse.urlsplit, 'Scheme://user@[0439:23af::2309::fae7:1234]/Path?Query') - self.assertRaises(ValueError, urllib.parse.urlsplit, 'Scheme://user@[0439:23af:2309::fae7:1234:2342:438e:192.0.2.146]/Path?Query') - self.assertRaises(ValueError, urllib.parse.urlsplit, 'Scheme://user@]v6a.ip[/Path') -+ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://prefix.[v6a.ip]') -+ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://[v6a.ip].suffix') -+ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://prefix.[v6a.ip]/') -+ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://[v6a.ip].suffix/') -+ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://prefix.[v6a.ip]?') -+ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://[v6a.ip].suffix?') -+ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://prefix.[::1]') -+ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://[::1].suffix') -+ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://prefix.[::1]/') -+ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://[::1].suffix/') -+ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://prefix.[::1]?') -+ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://[::1].suffix?') -+ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://prefix.[::1]:a') -+ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://[::1].suffix:a') -+ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://prefix.[::1]:a1') -+ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://[::1].suffix:a1') -+ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://prefix.[::1]:1a') -+ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://[::1].suffix:1a') -+ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://prefix.[::1]:') -+ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://[::1].suffix:/') -+ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://prefix.[::1]:?') -+ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://user@prefix.[v6a.ip]') -+ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://user@[v6a.ip].suffix') -+ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://[v6a.ip') -+ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://v6a.ip]') -+ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://]v6a.ip[') -+ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://]v6a.ip') -+ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://v6a.ip[') -+ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://prefix.[v6a.ip') -+ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://v6a.ip].suffix') -+ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://prefix]v6a.ip[suffix') -+ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://prefix]v6a.ip') -+ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://v6a.ip[suffix') - - def test_splitting_bracketed_hosts(self): -- p1 = urllib.parse.urlsplit('scheme://user@[v6a.ip]/path?query') -+ p1 = urllib.parse.urlsplit('scheme://user@[v6a.ip]:1234/path?query') - self.assertEqual(p1.hostname, 'v6a.ip') - self.assertEqual(p1.username, 'user') - self.assertEqual(p1.path, '/path') -+ self.assertEqual(p1.port, 1234) - p2 = urllib.parse.urlsplit('scheme://user@[0439:23af:2309::fae7%test]/path?query') - self.assertEqual(p2.hostname, '0439:23af:2309::fae7%test') - self.assertEqual(p2.username, 'user') - self.assertEqual(p2.path, '/path') -+ self.assertIs(p2.port, None) - p3 = urllib.parse.urlsplit('scheme://user@[0439:23af:2309::fae7:1234:192.0.2.146%test]/path?query') - self.assertEqual(p3.hostname, '0439:23af:2309::fae7:1234:192.0.2.146%test') - self.assertEqual(p3.username, 'user') -diff --git a/Lib/urllib/parse.py b/Lib/urllib/parse.py -index abf1d1b546..724cce8d39 100644 ---- a/Lib/urllib/parse.py -+++ b/Lib/urllib/parse.py -@@ -436,6 +436,23 @@ def _checknetloc(netloc): - raise ValueError("netloc '" + netloc + "' contains invalid " + - "characters under NFKC normalization") - -+def _check_bracketed_netloc(netloc): -+ # Note that this function must mirror the splitting -+ # done in NetlocResultMixins._hostinfo(). -+ hostname_and_port = netloc.rpartition('@')[2] -+ before_bracket, have_open_br, bracketed = hostname_and_port.partition('[') -+ if have_open_br: -+ # No data is allowed before a bracket. -+ if before_bracket: -+ raise ValueError("Invalid IPv6 URL") -+ hostname, _, port = bracketed.partition(']') -+ # No data is allowed after the bracket but before the port delimiter. -+ if port and not port.startswith(":"): -+ raise ValueError("Invalid IPv6 URL") -+ else: -+ hostname, _, port = hostname_and_port.partition(':') -+ _check_bracketed_host(hostname) -+ - # Valid bracketed hosts are defined in - # https://www.rfc-editor.org/rfc/rfc3986#page-49 and https://url.spec.whatwg.org/ - def _check_bracketed_host(hostname): -@@ -496,8 +513,7 @@ def urlsplit(url, scheme='', allow_fragments=True): - (']' in netloc and '[' not in netloc)): - raise ValueError("Invalid IPv6 URL") - if '[' in netloc and ']' in netloc: -- bracketed_host = netloc.partition('[')[2].partition(']')[0] -- _check_bracketed_host(bracketed_host) -+ _check_bracketed_netloc(netloc) - if allow_fragments and '#' in url: - url, fragment = url.split('#', 1) - if '?' in url: -diff --git a/Misc/NEWS.d/next/Security/2025-01-28-14-08-03.gh-issue-105704.EnhHxu.rst b/Misc/NEWS.d/next/Security/2025-01-28-14-08-03.gh-issue-105704.EnhHxu.rst -new file mode 100644 -index 0000000000..bff1bc6b0d ---- /dev/null -+++ b/Misc/NEWS.d/next/Security/2025-01-28-14-08-03.gh-issue-105704.EnhHxu.rst -@@ -0,0 +1,4 @@ -+When using :func:`urllib.parse.urlsplit` and :func:`urllib.parse.urlparse` host -+parsing would not reject domain names containing square brackets (``[`` and -+``]``). Square brackets are only valid for IPv6 and IPvFuture hosts according to -+`RFC 3986 Section 3.2.2 `__. diff --git a/python3.11.spec b/python3.11.spec index 19fd162..c963d83 100644 --- a/python3.11.spec +++ b/python3.11.spec @@ -13,11 +13,11 @@ URL: https://www.python.org/ # WARNING When rebasing to a new Python version, # remember to update the python3-docs package as well -%global general_version %{pybasever}.11 +%global general_version %{pybasever}.12 #global prerel ... %global upstream_version %{general_version}%{?prerel} Version: %{general_version}%{?prerel:~%{prerel}} -Release: 6%{?dist} +Release: 1%{?dist} License: Python-2.0.1 @@ -320,21 +320,6 @@ Patch251: 00251-change-user-install-location.patch # https://github.com/GrahamDumpleton/mod_wsgi/issues/730 Patch371: 00371-revert-bpo-1596321-fix-threading-_shutdown-for-the-main-thread-gh-28549-gh-28589.patch -# 00438 # be066d7a5aa1a8982dc0f38b6e90319ee8cf2bc2 -# Fix ThreadedVSOCKSocketStreamTest (GH-119465) (GH-119479) (#119484) -# -# Fix ThreadedVSOCKSocketStreamTest: if get_cid() returns the host -# address or the "any" address, use the local communication address -# (loopback): VMADDR_CID_LOCAL. -# -# On Linux 6.9, apparently, the /dev/vsock device is now available but -# get_cid() returns VMADDR_CID_ANY (-1). -Patch438: 00438-fix-threadedvsocksocketstreamtest-gh-119465-gh-119479-119484.patch - -# 00450 # 4ab8663661748eb994c09e4ae89f59eb84c5d3ea -# CVE-2025-0938: Disallow square brackets ([ and ]) in domain names for parsed URLs -Patch450: 00450-cve-2025-0938-disallow-square-brackets-and-in-domain-names-for-parsed-urls.patch - # 00452 # eb11d070c5af7d1b5e47f4e02186152d08eaf793 # Properly apply exported CFLAGS for dtrace/systemtap builds # @@ -1662,6 +1647,9 @@ CheckPython optimized # ====================================================== %changelog +* Wed Apr 09 2025 Miro Hrončok - 3.11.12-1 +- Update to 3.11.12 + * Mon Mar 31 2025 Charalampos Stratakis - 3.11.11-6 - Properly apply exported CFLAGS for dtrace/systemtap builds - Fixes: rhbz#2356302 diff --git a/sources b/sources index cab6ce8..d109a58 100644 --- a/sources +++ b/sources @@ -1,2 +1,2 @@ -SHA512 (Python-3.11.11.tar.xz) = 3ff90f15f725fa8d06686158aaddb887a247b03ca4dc1fdfd81a8efb53373db3e8673bd0b3de30bb7669f3f07d9854e9d8a2dbcd49b18d15b8172787a53a0a9e -SHA512 (Python-3.11.11.tar.xz.asc) = d71b0b42537fb636e8c469d62d13ff020149e4fb9d87eb17f8c999301195e418d134dbdb7e4ab49b06de16e96f8ef6bbcf2a749956fffca2ce03185f191c181d +SHA512 (Python-3.11.12.tar.xz) = 5c95900de73cd187f5d7a89a05314ef85f4d680308d0d5fff5e6ada81f8ecf030018bef0f1a819d007e8b6d01b52e50395572c2d1a56d2c164492e13a69a9926 +SHA512 (Python-3.11.12.tar.xz.asc) = cb1f82d44be6de67182747f8ad1054e85cca22753c0c86ff12b95ec7044c5c6c37f40a876e5707a6c422d58f483257b8ddbb3ea87893679f81b9299c48373f20 From 2902fe1d79a3005044ea5ca9869c0614b7b84345 Mon Sep 17 00:00:00 2001 From: Charalampos Stratakis Date: Wed, 16 Apr 2025 05:18:41 +0200 Subject: [PATCH 09/33] test_ssl: Don't stop ThreadedEchoServer on OSError in ConnectionHandler Fixes: rhbz#2355052 --- ...rver-on-oserror-in-connectionhandler.patch | 80 +++++++++++++++++++ python3.11.spec | 21 ++++- 2 files changed, 100 insertions(+), 1 deletion(-) create mode 100644 00458-test_ssl-don-t-stop-threadedechoserver-on-oserror-in-connectionhandler.patch diff --git a/00458-test_ssl-don-t-stop-threadedechoserver-on-oserror-in-connectionhandler.patch b/00458-test_ssl-don-t-stop-threadedechoserver-on-oserror-in-connectionhandler.patch new file mode 100644 index 0000000..92d47b3 --- /dev/null +++ b/00458-test_ssl-don-t-stop-threadedechoserver-on-oserror-in-connectionhandler.patch @@ -0,0 +1,80 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: "Miss Islington (bot)" + <31488909+miss-islington@users.noreply.github.com> +Date: Mon, 11 Nov 2024 15:26:10 +0100 +Subject: [PATCH] 00458: test_ssl: Don't stop ThreadedEchoServer on OSError in + ConnectionHandler + +If `read()` in the ConnectionHandler thread raises `OSError` (except `ConnectionError`), +the ConnectionHandler shuts down the entire ThreadedEchoServer, +preventing further connections. +It also does that for `EPROTOTYPE` in `wrap_conn`. + +Make sure that the context manager *is* used, and remove the `server.stop()` +calls from ConnectionHandler. + +Backported from 3.12+: +https://github.com/python/cpython/pull/126503 + +Co-authored-by: Petr Viktorin +--- + Lib/test/test_ssl.py | 17 ++++++++++++----- + 1 file changed, 12 insertions(+), 5 deletions(-) + +diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py +index 203351bd60..0b169c37d5 100644 +--- a/Lib/test/test_ssl.py ++++ b/Lib/test/test_ssl.py +@@ -2516,7 +2516,6 @@ def wrap_conn(self): + # See also http://erickt.github.io/blog/2014/11/19/adventures-in-debugging-a-potential-osx-kernel-bug/ + if e.errno != errno.EPROTOTYPE and sys.platform != "darwin": + self.running = False +- self.server.stop() + self.close() + return False + else: +@@ -2651,10 +2650,6 @@ def run(self): + self.close() + self.running = False + +- # normally, we'd just stop here, but for the test +- # harness, we want to stop the server +- self.server.stop() +- + def __init__(self, certificate=None, ssl_version=None, + certreqs=None, cacerts=None, + chatty=True, connectionchatty=False, starttls_server=False, +@@ -2688,21 +2683,33 @@ def __init__(self, certificate=None, ssl_version=None, + self.conn_errors = [] + threading.Thread.__init__(self) + self.daemon = True ++ self._in_context = False + + def __enter__(self): ++ if self._in_context: ++ raise ValueError('Re-entering ThreadedEchoServer context') ++ self._in_context = True + self.start(threading.Event()) + self.flag.wait() + return self + + def __exit__(self, *args): ++ assert self._in_context ++ self._in_context = False + self.stop() + self.join() + + def start(self, flag=None): ++ if not self._in_context: ++ raise ValueError( ++ 'ThreadedEchoServer must be used as a context manager') + self.flag = flag + threading.Thread.start(self) + + def run(self): ++ if not self._in_context: ++ raise ValueError( ++ 'ThreadedEchoServer must be used as a context manager') + self.sock.settimeout(1.0) + self.sock.listen(5) + self.active = True diff --git a/python3.11.spec b/python3.11.spec index c963d83..190d82e 100644 --- a/python3.11.spec +++ b/python3.11.spec @@ -17,7 +17,7 @@ URL: https://www.python.org/ #global prerel ... %global upstream_version %{general_version}%{?prerel} Version: %{general_version}%{?prerel:~%{prerel}} -Release: 1%{?dist} +Release: 2%{?dist} License: Python-2.0.1 @@ -332,6 +332,21 @@ Patch371: 00371-revert-bpo-1596321-fix-threading-_shutdown-for-the-main-thread-g # even when cross-compiling. Patch452: 00452-properly-apply-exported-cflags-for-dtrace-systemtap-builds.patch +# 00458 # ee47b2530c18d1e0b414f5a0738ddce28e7510f4 +# test_ssl: Don't stop ThreadedEchoServer on OSError in ConnectionHandler +# +# If `read()` in the ConnectionHandler thread raises `OSError` (except `ConnectionError`), +# the ConnectionHandler shuts down the entire ThreadedEchoServer, +# preventing further connections. +# It also does that for `EPROTOTYPE` in `wrap_conn`. +# +# Make sure that the context manager *is* used, and remove the `server.stop()` +# calls from ConnectionHandler. +# +# Backported from 3.12+: +# https://github.com/python/cpython/pull/126503 +Patch458: 00458-test_ssl-don-t-stop-threadedechoserver-on-oserror-in-connectionhandler.patch + # (New patches go here ^^^) # # When adding new patches to "python" and "python3" in Fedora, EL, etc., @@ -1647,6 +1662,10 @@ CheckPython optimized # ====================================================== %changelog +* Wed Apr 16 2025 Charalampos Stratakis - 3.11.12-2 +- test_ssl: Don't stop ThreadedEchoServer on OSError in ConnectionHandler +- Fixes: rhbz#2355052 + * Wed Apr 09 2025 Miro Hrončok - 3.11.12-1 - Update to 3.11.12 From f1bceb07301748cd2010b4151d0bae0959c9bc43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Hrn=C4=8Diar?= Date: Thu, 17 Apr 2025 11:56:07 +0200 Subject: [PATCH 10/33] Regenerate patches with updated importpatches script --- 00001-rpath.patch | 5 +++-- 00251-change-user-install-location.patch | 2 +- ...ing-_shutdown-for-the-main-thread-gh-28549-gh-28589.patch | 4 ++-- ...y-apply-exported-cflags-for-dtrace-systemtap-builds.patch | 3 +-- ...-threadedechoserver-on-oserror-in-connectionhandler.patch | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/00001-rpath.patch b/00001-rpath.patch index 778c077..58e0d8f 100644 --- a/00001-rpath.patch +++ b/00001-rpath.patch @@ -1,8 +1,9 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: David Malcolm Date: Wed, 13 Jan 2010 21:25:18 +0000 -Subject: [PATCH] 00001: Fixup distutils/unixccompiler.py to remove standard - library path from rpath Was Patch0 in ivazquez' python3000 specfile +Subject: =?UTF-8?q?00001:=20Fixup=20distutils/unixccompiler.py=20to=20remo?= + =?UTF-8?q?ve=20standard=20library=20path=20from=20rpath=0AWas=20Patch0=20?= + =?UTF-8?q?in=20ivazquez'=20python3000=20specfile?= --- Lib/distutils/unixccompiler.py | 9 +++++++++ diff --git a/00251-change-user-install-location.patch b/00251-change-user-install-location.patch index 549d139..7c079b0 100644 --- a/00251-change-user-install-location.patch +++ b/00251-change-user-install-location.patch @@ -1,7 +1,7 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Mon, 15 Feb 2021 12:19:27 +0100 -Subject: [PATCH] 00251: Change user install location +Subject: 00251: Change user install location MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit diff --git a/00371-revert-bpo-1596321-fix-threading-_shutdown-for-the-main-thread-gh-28549-gh-28589.patch b/00371-revert-bpo-1596321-fix-threading-_shutdown-for-the-main-thread-gh-28549-gh-28589.patch index 28ac750..598f434 100644 --- a/00371-revert-bpo-1596321-fix-threading-_shutdown-for-the-main-thread-gh-28549-gh-28589.patch +++ b/00371-revert-bpo-1596321-fix-threading-_shutdown-for-the-main-thread-gh-28549-gh-28589.patch @@ -1,8 +1,8 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Hrn=C4=8Diar?= Date: Tue, 7 Dec 2021 14:41:59 +0100 -Subject: [PATCH] 00371: Revert "bpo-1596321: Fix threading._shutdown() for the - main thread (GH-28549) (GH-28589)" +Subject: 00371: Revert "bpo-1596321: Fix threading._shutdown() for the main + thread (GH-28549) (GH-28589)" This reverts commit 38c67738c64304928c68d5c2bd78bbb01d979b94. It introduced regression causing FreeIPA's tests to fail. diff --git a/00452-properly-apply-exported-cflags-for-dtrace-systemtap-builds.patch b/00452-properly-apply-exported-cflags-for-dtrace-systemtap-builds.patch index e36195b..1417bdb 100644 --- a/00452-properly-apply-exported-cflags-for-dtrace-systemtap-builds.patch +++ b/00452-properly-apply-exported-cflags-for-dtrace-systemtap-builds.patch @@ -2,8 +2,7 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 31 Mar 2025 20:29:04 +0200 -Subject: [PATCH] 00452: Properly apply exported CFLAGS for dtrace/systemtap - builds +Subject: 00452: Properly apply exported CFLAGS for dtrace/systemtap builds When using --with-dtrace the resulting object file could be missing specific CFLAGS exported by the build system due to the systemtap diff --git a/00458-test_ssl-don-t-stop-threadedechoserver-on-oserror-in-connectionhandler.patch b/00458-test_ssl-don-t-stop-threadedechoserver-on-oserror-in-connectionhandler.patch index 92d47b3..e22c0e6 100644 --- a/00458-test_ssl-don-t-stop-threadedechoserver-on-oserror-in-connectionhandler.patch +++ b/00458-test_ssl-don-t-stop-threadedechoserver-on-oserror-in-connectionhandler.patch @@ -2,7 +2,7 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 11 Nov 2024 15:26:10 +0100 -Subject: [PATCH] 00458: test_ssl: Don't stop ThreadedEchoServer on OSError in +Subject: 00458: test_ssl: Don't stop ThreadedEchoServer on OSError in ConnectionHandler If `read()` in the ConnectionHandler thread raises `OSError` (except `ConnectionError`), From 2b6b498d7775c90af01cf01a3fb1665e607af22b Mon Sep 17 00:00:00 2001 From: Charalampos Stratakis Date: Tue, 13 May 2025 02:20:25 +0200 Subject: [PATCH 11/33] Fix PySSL_SetError handling SSL_ERROR_SYSCALL This fixes random flakiness of test_ssl on stressed machines --- 00001-rpath.patch | 5 +- ..._seterror-handling-ssl_error_syscall.patch | 196 ++++++++++++++++++ python3.11.spec | 22 +- 3 files changed, 217 insertions(+), 6 deletions(-) create mode 100644 00462-fix-pyssl_seterror-handling-ssl_error_syscall.patch diff --git a/00001-rpath.patch b/00001-rpath.patch index 58e0d8f..9498516 100644 --- a/00001-rpath.patch +++ b/00001-rpath.patch @@ -1,9 +1,8 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: David Malcolm Date: Wed, 13 Jan 2010 21:25:18 +0000 -Subject: =?UTF-8?q?00001:=20Fixup=20distutils/unixccompiler.py=20to=20remo?= - =?UTF-8?q?ve=20standard=20library=20path=20from=20rpath=0AWas=20Patch0=20?= - =?UTF-8?q?in=20ivazquez'=20python3000=20specfile?= +Subject: 00001: Fixup distutils/unixccompiler.py to remove standard library + path from rpath Was Patch0 in ivazquez' python3000 specfile --- Lib/distutils/unixccompiler.py | 9 +++++++++ diff --git a/00462-fix-pyssl_seterror-handling-ssl_error_syscall.patch b/00462-fix-pyssl_seterror-handling-ssl_error_syscall.patch new file mode 100644 index 0000000..43182ad --- /dev/null +++ b/00462-fix-pyssl_seterror-handling-ssl_error_syscall.patch @@ -0,0 +1,196 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: yevgeny hong +Date: Tue, 26 Mar 2024 16:45:43 +0900 +Subject: 00462: Fix PySSL_SetError handling SSL_ERROR_SYSCALL + +Python 3.10 changed from using SSL_write() and SSL_read() to SSL_write_ex() and +SSL_read_ex(), but did not update handling of the return value. + +Change error handling so that the return value is not examined. +OSError (not EOF) is now returned when retval is 0. + +This resolves the issue of failing tests when a system is +stressed on OpenSSL 3.5. + +Co-authored-by: Serhiy Storchaka +Co-authored-by: Petr Viktorin +--- + Lib/test/test_ssl.py | 28 ++++++----- + ...-02-18-09-50-31.gh-issue-115627.HGchj0.rst | 2 + + Modules/_ssl.c | 48 +++++++------------ + 3 files changed, 35 insertions(+), 43 deletions(-) + create mode 100644 Misc/NEWS.d/next/Library/2024-02-18-09-50-31.gh-issue-115627.HGchj0.rst + +diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py +index 0b169c37d5..921c41bd0d 100644 +--- a/Lib/test/test_ssl.py ++++ b/Lib/test/test_ssl.py +@@ -2633,16 +2633,18 @@ def run(self): + self.write(msg.lower()) + except OSError as e: + # handles SSLError and socket errors ++ if isinstance(e, ConnectionError): ++ # OpenSSL 1.1.1 sometimes raises ++ # ConnectionResetError when connection is not ++ # shut down gracefully. ++ if self.server.chatty and support.verbose: ++ print(f" Connection reset by peer: {self.addr}") ++ ++ self.close() ++ self.running = False ++ return + if self.server.chatty and support.verbose: +- if isinstance(e, ConnectionError): +- # OpenSSL 1.1.1 sometimes raises +- # ConnectionResetError when connection is not +- # shut down gracefully. +- print( +- f" Connection reset by peer: {self.addr}" +- ) +- else: +- handle_error("Test server failure:\n") ++ handle_error("Test server failure:\n") + try: + self.write(b"ERROR\n") + except OSError: +@@ -3337,8 +3339,8 @@ def test_wrong_cert_tls13(self): + suppress_ragged_eofs=False) as s: + s.connect((HOST, server.port)) + with self.assertRaisesRegex( +- ssl.SSLError, +- 'alert unknown ca|EOF occurred' ++ OSError, ++ 'alert unknown ca|EOF occurred|TLSV1_ALERT_UNKNOWN_CA|closed by the remote host|Connection reset by peer' + ): + # TLS 1.3 perform client cert exchange after handshake + s.write(b'data') +@@ -4610,8 +4612,8 @@ def msg_cb(conn, direction, version, content_type, msg_type, data): + # test sometimes fails with EOF error. Test passes as long as + # server aborts connection with an error. + with self.assertRaisesRegex( +- ssl.SSLError, +- '(certificate required|EOF occurred)' ++ OSError, ++ 'certificate required|EOF occurred|closed by the remote host|Connection reset by peer' + ): + # receive CertificateRequest + data = s.recv(1024) +diff --git a/Misc/NEWS.d/next/Library/2024-02-18-09-50-31.gh-issue-115627.HGchj0.rst b/Misc/NEWS.d/next/Library/2024-02-18-09-50-31.gh-issue-115627.HGchj0.rst +new file mode 100644 +index 0000000000..75d926ab59 +--- /dev/null ++++ b/Misc/NEWS.d/next/Library/2024-02-18-09-50-31.gh-issue-115627.HGchj0.rst +@@ -0,0 +1,2 @@ ++Fix the :mod:`ssl` module error handling of connection terminate by peer. ++It now throws an OSError with the appropriate error code instead of an EOFError. +diff --git a/Modules/_ssl.c b/Modules/_ssl.c +index 09207abde1..787c241133 100644 +--- a/Modules/_ssl.c ++++ b/Modules/_ssl.c +@@ -576,7 +576,7 @@ PySSL_ChainExceptions(PySSLSocket *sslsock) { + } + + static PyObject * +-PySSL_SetError(PySSLSocket *sslsock, int ret, const char *filename, int lineno) ++PySSL_SetError(PySSLSocket *sslsock, const char *filename, int lineno) + { + PyObject *type; + char *errstr = NULL; +@@ -589,7 +589,6 @@ PySSL_SetError(PySSLSocket *sslsock, int ret, const char *filename, int lineno) + _sslmodulestate *state = get_state_sock(sslsock); + type = state->PySSLErrorObject; + +- assert(ret <= 0); + e = ERR_peek_last_error(); + + if (sslsock->ssl != NULL) { +@@ -622,32 +621,21 @@ PySSL_SetError(PySSLSocket *sslsock, int ret, const char *filename, int lineno) + case SSL_ERROR_SYSCALL: + { + if (e == 0) { +- PySocketSockObject *s = GET_SOCKET(sslsock); +- if (ret == 0 || (((PyObject *)s) == Py_None)) { ++ /* underlying BIO reported an I/O error */ ++ ERR_clear_error(); ++#ifdef MS_WINDOWS ++ if (err.ws) { ++ return PyErr_SetFromWindowsErr(err.ws); ++ } ++#endif ++ if (err.c) { ++ errno = err.c; ++ return PyErr_SetFromErrno(PyExc_OSError); ++ } ++ else { + p = PY_SSL_ERROR_EOF; + type = state->PySSLEOFErrorObject; + errstr = "EOF occurred in violation of protocol"; +- } else if (s && ret == -1) { +- /* underlying BIO reported an I/O error */ +- ERR_clear_error(); +-#ifdef MS_WINDOWS +- if (err.ws) { +- return PyErr_SetFromWindowsErr(err.ws); +- } +-#endif +- if (err.c) { +- errno = err.c; +- return PyErr_SetFromErrno(PyExc_OSError); +- } +- else { +- p = PY_SSL_ERROR_EOF; +- type = state->PySSLEOFErrorObject; +- errstr = "EOF occurred in violation of protocol"; +- } +- } else { /* possible? */ +- p = PY_SSL_ERROR_SYSCALL; +- type = state->PySSLSyscallErrorObject; +- errstr = "Some I/O error occurred"; + } + } else { + if (ERR_GET_LIB(e) == ERR_LIB_SSL && +@@ -1013,7 +1001,7 @@ _ssl__SSLSocket_do_handshake_impl(PySSLSocket *self) + err.ssl == SSL_ERROR_WANT_WRITE); + Py_XDECREF(sock); + if (ret < 1) +- return PySSL_SetError(self, ret, __FILE__, __LINE__); ++ return PySSL_SetError(self, __FILE__, __LINE__); + if (PySSL_ChainExceptions(self) < 0) + return NULL; + Py_RETURN_NONE; +@@ -2434,7 +2422,7 @@ _ssl__SSLSocket_write_impl(PySSLSocket *self, Py_buffer *b) + + Py_XDECREF(sock); + if (retval == 0) +- return PySSL_SetError(self, retval, __FILE__, __LINE__); ++ return PySSL_SetError(self, __FILE__, __LINE__); + if (PySSL_ChainExceptions(self) < 0) + return NULL; + return PyLong_FromSize_t(count); +@@ -2464,7 +2452,7 @@ _ssl__SSLSocket_pending_impl(PySSLSocket *self) + self->err = err; + + if (count < 0) +- return PySSL_SetError(self, count, __FILE__, __LINE__); ++ return PySSL_SetError(self, __FILE__, __LINE__); + else + return PyLong_FromLong(count); + } +@@ -2587,7 +2575,7 @@ _ssl__SSLSocket_read_impl(PySSLSocket *self, Py_ssize_t len, + err.ssl == SSL_ERROR_WANT_WRITE); + + if (retval == 0) { +- PySSL_SetError(self, retval, __FILE__, __LINE__); ++ PySSL_SetError(self, __FILE__, __LINE__); + goto error; + } + if (self->exc_type != NULL) +@@ -2713,7 +2701,7 @@ _ssl__SSLSocket_shutdown_impl(PySSLSocket *self) + } + if (ret < 0) { + Py_XDECREF(sock); +- PySSL_SetError(self, ret, __FILE__, __LINE__); ++ PySSL_SetError(self, __FILE__, __LINE__); + return NULL; + } + if (self->exc_type != NULL) diff --git a/python3.11.spec b/python3.11.spec index 190d82e..47c60d9 100644 --- a/python3.11.spec +++ b/python3.11.spec @@ -17,7 +17,7 @@ URL: https://www.python.org/ #global prerel ... %global upstream_version %{general_version}%{?prerel} Version: %{general_version}%{?prerel:~%{prerel}} -Release: 2%{?dist} +Release: 3%{?dist} License: Python-2.0.1 @@ -284,8 +284,7 @@ Source11: idle3.appdata.xml # (Patches taken from github.com/fedora-python/cpython) # 00001 # d06a8853cf4bae9e115f45e1d531d2dc152c5cc8 -# Fixup distutils/unixccompiler.py to remove standard library path from rpath -# Was Patch0 in ivazquez' python3000 specfile +# Fixup distutils/unixccompiler.py to remove standard library path from rpath Was Patch0 in ivazquez' python3000 specfile Patch1: 00001-rpath.patch # 00251 # af0f1ba72e01cb93371ff21fb7ca889daa43fa7a @@ -347,6 +346,19 @@ Patch452: 00452-properly-apply-exported-cflags-for-dtrace-systemtap-builds.patch # https://github.com/python/cpython/pull/126503 Patch458: 00458-test_ssl-don-t-stop-threadedechoserver-on-oserror-in-connectionhandler.patch +# 00462 # c9db492d8924b2d1a0991e36f3c2b4f9c2ec8942 +# Fix PySSL_SetError handling SSL_ERROR_SYSCALL +# +# Python 3.10 changed from using SSL_write() and SSL_read() to SSL_write_ex() and +# SSL_read_ex(), but did not update handling of the return value. +# +# Change error handling so that the return value is not examined. +# OSError (not EOF) is now returned when retval is 0. +# +# This resolves the issue of failing tests when a system is +# stressed on OpenSSL 3.5. +Patch462: 00462-fix-pyssl_seterror-handling-ssl_error_syscall.patch + # (New patches go here ^^^) # # When adding new patches to "python" and "python3" in Fedora, EL, etc., @@ -1662,6 +1674,10 @@ CheckPython optimized # ====================================================== %changelog +* Tue May 13 2025 Charalampos Stratakis - 3.11.12-3 +- Fix PySSL_SetError handling SSL_ERROR_SYSCALL +- This fixes random flakiness of test_ssl on stressed machines + * Wed Apr 16 2025 Charalampos Stratakis - 3.11.12-2 - test_ssl: Don't stop ThreadedEchoServer on OSError in ConnectionHandler - Fixes: rhbz#2355052 From 4553d57adf6c37473da87dbd729db677332b3738 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Hrn=C4=8Diar?= Date: Wed, 4 Jun 2025 09:21:18 +0200 Subject: [PATCH 12/33] Update to 3.11.13 --- ...rver-on-oserror-in-connectionhandler.patch | 80 ------------------- python3.11.spec | 22 ++--- sources | 4 +- 3 files changed, 7 insertions(+), 99 deletions(-) delete mode 100644 00458-test_ssl-don-t-stop-threadedechoserver-on-oserror-in-connectionhandler.patch diff --git a/00458-test_ssl-don-t-stop-threadedechoserver-on-oserror-in-connectionhandler.patch b/00458-test_ssl-don-t-stop-threadedechoserver-on-oserror-in-connectionhandler.patch deleted file mode 100644 index e22c0e6..0000000 --- a/00458-test_ssl-don-t-stop-threadedechoserver-on-oserror-in-connectionhandler.patch +++ /dev/null @@ -1,80 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: "Miss Islington (bot)" - <31488909+miss-islington@users.noreply.github.com> -Date: Mon, 11 Nov 2024 15:26:10 +0100 -Subject: 00458: test_ssl: Don't stop ThreadedEchoServer on OSError in - ConnectionHandler - -If `read()` in the ConnectionHandler thread raises `OSError` (except `ConnectionError`), -the ConnectionHandler shuts down the entire ThreadedEchoServer, -preventing further connections. -It also does that for `EPROTOTYPE` in `wrap_conn`. - -Make sure that the context manager *is* used, and remove the `server.stop()` -calls from ConnectionHandler. - -Backported from 3.12+: -https://github.com/python/cpython/pull/126503 - -Co-authored-by: Petr Viktorin ---- - Lib/test/test_ssl.py | 17 ++++++++++++----- - 1 file changed, 12 insertions(+), 5 deletions(-) - -diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py -index 203351bd60..0b169c37d5 100644 ---- a/Lib/test/test_ssl.py -+++ b/Lib/test/test_ssl.py -@@ -2516,7 +2516,6 @@ def wrap_conn(self): - # See also http://erickt.github.io/blog/2014/11/19/adventures-in-debugging-a-potential-osx-kernel-bug/ - if e.errno != errno.EPROTOTYPE and sys.platform != "darwin": - self.running = False -- self.server.stop() - self.close() - return False - else: -@@ -2651,10 +2650,6 @@ def run(self): - self.close() - self.running = False - -- # normally, we'd just stop here, but for the test -- # harness, we want to stop the server -- self.server.stop() -- - def __init__(self, certificate=None, ssl_version=None, - certreqs=None, cacerts=None, - chatty=True, connectionchatty=False, starttls_server=False, -@@ -2688,21 +2683,33 @@ def __init__(self, certificate=None, ssl_version=None, - self.conn_errors = [] - threading.Thread.__init__(self) - self.daemon = True -+ self._in_context = False - - def __enter__(self): -+ if self._in_context: -+ raise ValueError('Re-entering ThreadedEchoServer context') -+ self._in_context = True - self.start(threading.Event()) - self.flag.wait() - return self - - def __exit__(self, *args): -+ assert self._in_context -+ self._in_context = False - self.stop() - self.join() - - def start(self, flag=None): -+ if not self._in_context: -+ raise ValueError( -+ 'ThreadedEchoServer must be used as a context manager') - self.flag = flag - threading.Thread.start(self) - - def run(self): -+ if not self._in_context: -+ raise ValueError( -+ 'ThreadedEchoServer must be used as a context manager') - self.sock.settimeout(1.0) - self.sock.listen(5) - self.active = True diff --git a/python3.11.spec b/python3.11.spec index 47c60d9..43aa488 100644 --- a/python3.11.spec +++ b/python3.11.spec @@ -13,11 +13,11 @@ URL: https://www.python.org/ # WARNING When rebasing to a new Python version, # remember to update the python3-docs package as well -%global general_version %{pybasever}.12 +%global general_version %{pybasever}.13 #global prerel ... %global upstream_version %{general_version}%{?prerel} Version: %{general_version}%{?prerel:~%{prerel}} -Release: 3%{?dist} +Release: 1%{?dist} License: Python-2.0.1 @@ -331,21 +331,6 @@ Patch371: 00371-revert-bpo-1596321-fix-threading-_shutdown-for-the-main-thread-g # even when cross-compiling. Patch452: 00452-properly-apply-exported-cflags-for-dtrace-systemtap-builds.patch -# 00458 # ee47b2530c18d1e0b414f5a0738ddce28e7510f4 -# test_ssl: Don't stop ThreadedEchoServer on OSError in ConnectionHandler -# -# If `read()` in the ConnectionHandler thread raises `OSError` (except `ConnectionError`), -# the ConnectionHandler shuts down the entire ThreadedEchoServer, -# preventing further connections. -# It also does that for `EPROTOTYPE` in `wrap_conn`. -# -# Make sure that the context manager *is* used, and remove the `server.stop()` -# calls from ConnectionHandler. -# -# Backported from 3.12+: -# https://github.com/python/cpython/pull/126503 -Patch458: 00458-test_ssl-don-t-stop-threadedechoserver-on-oserror-in-connectionhandler.patch - # 00462 # c9db492d8924b2d1a0991e36f3c2b4f9c2ec8942 # Fix PySSL_SetError handling SSL_ERROR_SYSCALL # @@ -1674,6 +1659,9 @@ CheckPython optimized # ====================================================== %changelog +* Wed Jun 04 2025 Tomáš Hrnčiar - 3.11.13-1 +- Update to 3.11.13 + * Tue May 13 2025 Charalampos Stratakis - 3.11.12-3 - Fix PySSL_SetError handling SSL_ERROR_SYSCALL - This fixes random flakiness of test_ssl on stressed machines diff --git a/sources b/sources index d109a58..4cc1725 100644 --- a/sources +++ b/sources @@ -1,2 +1,2 @@ -SHA512 (Python-3.11.12.tar.xz) = 5c95900de73cd187f5d7a89a05314ef85f4d680308d0d5fff5e6ada81f8ecf030018bef0f1a819d007e8b6d01b52e50395572c2d1a56d2c164492e13a69a9926 -SHA512 (Python-3.11.12.tar.xz.asc) = cb1f82d44be6de67182747f8ad1054e85cca22753c0c86ff12b95ec7044c5c6c37f40a876e5707a6c422d58f483257b8ddbb3ea87893679f81b9299c48373f20 +SHA512 (Python-3.11.13.tar.xz) = 70f57464d548eac4fe0d0c7f85a14b0e549a4e25ef66de4fc36b06ce72a3efe87dadfcd56ee275c10483cf802fbc9d73b61f9fb2941a46e2f92f075aeb1afe85 +SHA512 (Python-3.11.13.tar.xz.asc) = 6e261490bc7777f0bcebd0464867df98b7955b32f13a445aab3cb6a1a1d3fb804817638f67a8586910fb97291a805b64f130909c06257903f431f8634c691c3b From 9d2c8873e9fc60a0077b7a419c85db046bde52b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Thu, 26 Jun 2025 13:08:59 +0200 Subject: [PATCH 13/33] Fixup the patch 1 commit message after the importpatches/exportpatches change This fixes up f1bceb07301748cd2010b4151d0bae0959c9bc43 + 2b6b498d7775c90af01cf01a3fb1665e607af22b. --- 00001-rpath.patch | 3 ++- python3.11.spec | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/00001-rpath.patch b/00001-rpath.patch index 9498516..cd063e5 100644 --- a/00001-rpath.patch +++ b/00001-rpath.patch @@ -2,8 +2,9 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: David Malcolm Date: Wed, 13 Jan 2010 21:25:18 +0000 Subject: 00001: Fixup distutils/unixccompiler.py to remove standard library - path from rpath Was Patch0 in ivazquez' python3000 specfile + path from rpath +Was Patch0 in ivazquez' python3000 specfile --- Lib/distutils/unixccompiler.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/python3.11.spec b/python3.11.spec index 43aa488..35cfed2 100644 --- a/python3.11.spec +++ b/python3.11.spec @@ -284,7 +284,9 @@ Source11: idle3.appdata.xml # (Patches taken from github.com/fedora-python/cpython) # 00001 # d06a8853cf4bae9e115f45e1d531d2dc152c5cc8 -# Fixup distutils/unixccompiler.py to remove standard library path from rpath Was Patch0 in ivazquez' python3000 specfile +# Fixup distutils/unixccompiler.py to remove standard library path from rpath +# +# Was Patch0 in ivazquez' python3000 specfile Patch1: 00001-rpath.patch # 00251 # af0f1ba72e01cb93371ff21fb7ca889daa43fa7a From d53a9edf137a12e4bf5f1d87ddc5bc19abf861b1 Mon Sep 17 00:00:00 2001 From: Fedora Release Engineering Date: Fri, 25 Jul 2025 11:19:02 +0000 Subject: [PATCH 14/33] Rebuilt for https://fedoraproject.org/wiki/Fedora_43_Mass_Rebuild --- python3.11.spec | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/python3.11.spec b/python3.11.spec index 35cfed2..56e5b17 100644 --- a/python3.11.spec +++ b/python3.11.spec @@ -17,7 +17,7 @@ URL: https://www.python.org/ #global prerel ... %global upstream_version %{general_version}%{?prerel} Version: %{general_version}%{?prerel:~%{prerel}} -Release: 1%{?dist} +Release: 2%{?dist} License: Python-2.0.1 @@ -1661,6 +1661,9 @@ CheckPython optimized # ====================================================== %changelog +* Fri Jul 25 2025 Fedora Release Engineering - 3.11.13-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_43_Mass_Rebuild + * Wed Jun 04 2025 Tomáš Hrnčiar - 3.11.13-1 - Update to 3.11.13 From 7de99f0f7e7575f8536eb48aeb6d9ea9d75b18a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Zachar?= Date: Mon, 28 Jul 2025 09:44:37 +0200 Subject: [PATCH 15/33] Drop STI and use tmt instead Resolves: rhbz#2383057 --- {tests/.fmf => .fmf}/version | 0 plan.fmf | 62 ++++++++++++++++++++++++++++++++++++ tests/provision.fmf | 4 --- tests/tests.yml | 56 -------------------------------- 4 files changed, 62 insertions(+), 60 deletions(-) rename {tests/.fmf => .fmf}/version (100%) create mode 100644 plan.fmf delete mode 100644 tests/provision.fmf delete mode 100644 tests/tests.yml diff --git a/tests/.fmf/version b/.fmf/version similarity index 100% rename from tests/.fmf/version rename to .fmf/version diff --git a/plan.fmf b/plan.fmf new file mode 100644 index 0000000..028bf63 --- /dev/null +++ b/plan.fmf @@ -0,0 +1,62 @@ +execute: + how: tmt + +provision: + hardware: + memory: '>= 3 GB' + +environment: + pybasever: '3.11' + +discover: + - name: tests_python + how: shell + url: https://src.fedoraproject.org/tests/python.git + tests: + - name: smoke + path: /smoke + test: "VERSION=${pybasever} ./venv.sh" + - name: smoke_virtualenv + path: /smoke + test: "VERSION=${pybasever} METHOD=virtualenv ./venv.sh" + - name: debugsmoke + path: /smoke + test: "PYTHON=python${pybasever}d TOX=false VERSION=${pybasever} ./venv.sh" + - name: selftest + path: /selftest + test: "VERSION=${pybasever} X='-i test_check_probes' ./parallel.sh" + - name: debugtest + path: /selftest + test: "VERSION=${pybasever} PYTHON=python${pybasever}d X='-i test_check_probes' ./parallel.sh" + - name: debugflags + path: /flags + test: "python${pybasever}d ./assertflags.py -O0" + - name: marshalparser + path: /marshalparser + test: "VERSION=${pybasever} SAMPLE=10 ./test_marshalparser_compatibility.sh" + +prepare: + - name: Install dependencies + how: install + package: + - gcc # for extension building in venv and selftest + - gdb # for test_gdb + - gcc-c++ # for test_cppext + - "python${pybasever}" # the test subject + - "python${pybasever}-debug" # for leak testing + - "python${pybasever}-devel" # for extension building in venv and selftest + - "python${pybasever}-tkinter" # for selftest + - "python${pybasever}-test" # for selftest + - tox # for venv tests + - virtualenv # for virtualenv tests + - glibc-all-langpacks # for locale tests + - marshalparser # for testing compatibility (magic numbers) with marshalparser + - rpm # for debugging + - dnf # for upgrade + - name: Update packages + how: shell + script: dnf upgrade -y + - name: rpm_qa + order: 100 + how: shell + script: rpm -qa | sort | tee $TMT_PLAN_DATA/rpmqa.txt diff --git a/tests/provision.fmf b/tests/provision.fmf deleted file mode 100644 index 1a4f0f0..0000000 --- a/tests/provision.fmf +++ /dev/null @@ -1,4 +0,0 @@ ---- -standard-inventory-qcow2: - qemu: - m: 3G # Amount of VM memory diff --git a/tests/tests.yml b/tests/tests.yml deleted file mode 100644 index 07e31cb..0000000 --- a/tests/tests.yml +++ /dev/null @@ -1,56 +0,0 @@ ---- -- hosts: localhost - tags: - - classic - tasks: - - dnf: - name: "*" - state: latest - -- hosts: localhost - roles: - - role: standard-test-basic - tags: - - classic - repositories: - - repo: "https://src.fedoraproject.org/tests/python.git" - dest: "python" - pybasever: "3.11" - tests: - - rpm_qa: - run: rpm -qa - - smoke: - dir: python/smoke - run: "VERSION={{ pybasever }} ./venv.sh" - - smoke_virtualenv: - dir: python/smoke - run: "VERSION={{ pybasever }} METHOD=virtualenv ./venv.sh" - - debugsmoke: - dir: python/smoke - run: "PYTHON=python{{ pybasever }}d TOX=false VERSION={{ pybasever }} ./venv.sh" - - selftest: - dir: python/selftest - run: "VERSION={{ pybasever }} X='-i test_check_probes' ./parallel.sh" - - debugtest: - dir: python/selftest - run: "VERSION={{ pybasever }} PYTHON=python{{ pybasever }}d X='-i test_check_probes' ./parallel.sh" - - debugflags: - dir: python/flags - run: "python{{ pybasever }}d ./assertflags.py -O0" - - marshalparser: - dir: python/marshalparser - run: "VERSION={{ pybasever }} SAMPLE=10 test_marshalparser_compatibility.sh" - required_packages: - - gcc # for extension building in venv and selftest - - gcc-c++ # for test_cppext - - gdb # for test_gdb - - "python{{ pybasever }}" # the test subject - - "python{{ pybasever }}-debug" # for leak testing - - "python{{ pybasever }}-devel" # for extension building in venv and selftest - - "python{{ pybasever }}-tkinter" # for selftest - - "python{{ pybasever }}-test" # for selftest - - tox # for venv tests - - virtualenv # for virtualenv tests - - glibc-all-langpacks # for locale tests - - marshalparser # for testing compatibility (magic numbers) with marshalparser - - rpm # for debugging From 5a283b533c5cdf484ae84ca26e2c4f838f1ca3ab Mon Sep 17 00:00:00 2001 From: Lumir Balhar Date: Tue, 26 Aug 2025 10:01:22 +0200 Subject: [PATCH 16/33] rpminspect: Wrap strings with globs with single quotes It seems to be required since rpminspect 2.0: https://github.com/rpminspect/rpminspect/commit/1593c38ce46980e0279150706d1f7c7bdd82de28 --- rpminspect.yaml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/rpminspect.yaml b/rpminspect.yaml index 83dfb5e..8cc18cb 100644 --- a/rpminspect.yaml +++ b/rpminspect.yaml @@ -1,22 +1,22 @@ # exclude test XML data (not always valid) from XML validity check: xml: ignore: - - /usr/lib*/python*/test/xmltestdata/* - - /usr/lib*/python*/test/xmltestdata/*/* + - '/usr/lib*/python*/test/xmltestdata/*' + - '/usr/lib*/python*/test/xmltestdata/*/*' # exclude _socket from ipv4 only functions check, it has both ipv4 and ipv6 only badfuncs: allowed: - /usr/lib*/python*/lib-dynload/_socket.*: + '/usr/lib*/python*/lib-dynload/_socket.*': - inet_aton - inet_ntoa # exclude the debug build from annocheck entirely annocheck: ignore: - - /usr/bin/python*d - - /usr/lib*/libpython*d.so.1.0 - - /usr/lib*/python*/lib-dynload/*.cpython-*d-*-*-*.so + - '/usr/bin/python*d' + - '/usr/lib*/libpython*d.so.1.0' + - '/usr/lib*/python*/lib-dynload/*.cpython-*d-*-*-*.so' # don't report changed content of compiled files # that is expected with every toolchain update and not reproducible yet From 20fedd32614ea087fa2e135fe5bb3e20806a1d5e Mon Sep 17 00:00:00 2001 From: Karolina Surma Date: Fri, 10 Oct 2025 13:54:32 +0200 Subject: [PATCH 17/33] Update to Python 3.11.14 --- python3.11.spec | 9 ++++++--- sources | 4 ++-- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/python3.11.spec b/python3.11.spec index 56e5b17..838231b 100644 --- a/python3.11.spec +++ b/python3.11.spec @@ -13,11 +13,11 @@ URL: https://www.python.org/ # WARNING When rebasing to a new Python version, # remember to update the python3-docs package as well -%global general_version %{pybasever}.13 +%global general_version %{pybasever}.14 #global prerel ... %global upstream_version %{general_version}%{?prerel} Version: %{general_version}%{?prerel:~%{prerel}} -Release: 2%{?dist} +Release: 1%{?dist} License: Python-2.0.1 @@ -68,7 +68,7 @@ License: Python-2.0.1 # from Python with the versions below. # This needs to be manually updated when we update Python. %global pip_version 24.0 -%global setuptools_version 65.5.0 +%global setuptools_version 79.0.1 # Expensive optimizations (mainly, profile-guided optimizations) %bcond_without optimizations @@ -1661,6 +1661,9 @@ CheckPython optimized # ====================================================== %changelog +* Fri Oct 10 2025 Karolina Surma - 3.11.14-1 +- Update to 3.11.14 + * Fri Jul 25 2025 Fedora Release Engineering - 3.11.13-2 - Rebuilt for https://fedoraproject.org/wiki/Fedora_43_Mass_Rebuild diff --git a/sources b/sources index 4cc1725..d418a33 100644 --- a/sources +++ b/sources @@ -1,2 +1,2 @@ -SHA512 (Python-3.11.13.tar.xz) = 70f57464d548eac4fe0d0c7f85a14b0e549a4e25ef66de4fc36b06ce72a3efe87dadfcd56ee275c10483cf802fbc9d73b61f9fb2941a46e2f92f075aeb1afe85 -SHA512 (Python-3.11.13.tar.xz.asc) = 6e261490bc7777f0bcebd0464867df98b7955b32f13a445aab3cb6a1a1d3fb804817638f67a8586910fb97291a805b64f130909c06257903f431f8634c691c3b +SHA512 (Python-3.11.14.tar.xz) = 8b5aa917fe67dbaa3c306239ed56c16cd7a3b4b701fab0b3dc0d342d60176c75440713bcab0c59a3289ac4a0f06103bd31140c492556e1937fcdbd990675f9e5 +SHA512 (Python-3.11.14.tar.xz.asc) = d0049fd6f6d06ae5d86b3587080be060d522dd52e7e56270125541d5617582ea3977b75c7e585da005694665cfc5657e39033a730187c506edc252965f4df769 From c10d237b28d52fe5f17177e035a98a054407ce83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Fri, 5 Sep 2025 13:23:10 +0000 Subject: [PATCH 18/33] Inject SBOM into the installed wheels (when using the bundled ones) --- python3.11.spec | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/python3.11.spec b/python3.11.spec index 838231b..0f5f334 100644 --- a/python3.11.spec +++ b/python3.11.spec @@ -249,6 +249,9 @@ BuildRequires: /usr/sbin/ifconfig %if %{with rpmwheels} BuildRequires: %{python_wheel_pkg_prefix}-setuptools-wheel BuildRequires: %{python_wheel_pkg_prefix}-pip-wheel +%else +# For %%python_wheel_inject_sbom +BuildRequires: python-rpm-macros %endif %if %{without bootstrap} @@ -1063,6 +1066,11 @@ for file in %{buildroot}%{pylibdir}/pydoc_data/topics.py $(grep --include='*.py' rm ${directory}/{__pycache__/${module}.cpython-%{pyshortver}.opt-?.pyc,${module}.py} done +%if %{without rpmwheels} +# Inject SBOM into the installed wheels (if the macro is available) +%{?python_wheel_inject_sbom:%python_wheel_inject_sbom %{buildroot}%{pylibdir}/ensurepip/_bundled/*.whl} +%endif + # ====================================================== # Checks for packaging issues # ====================================================== From 2bbb4fe674258219e08a50ad964572eb550a3fb1 Mon Sep 17 00:00:00 2001 From: Karolina Surma Date: Tue, 6 Jan 2026 17:48:59 +0100 Subject: [PATCH 19/33] Require at least the same expat version as used during the build The versioned requirement is no longer valid - this happens again now with expat 2.7.2 introducing new symbols. Make the versioned requirement future-proof - the generate version will always match at least the one present in the buildroot during the Python build. --- python3.11.spec | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/python3.11.spec b/python3.11.spec index 0f5f334..bb078d6 100644 --- a/python3.11.spec +++ b/python3.11.spec @@ -17,7 +17,7 @@ URL: https://www.python.org/ #global prerel ... %global upstream_version %{general_version}%{?prerel} Version: %{general_version}%{?prerel:~%{prerel}} -Release: 1%{?dist} +Release: 2%{?dist} License: Python-2.0.1 @@ -192,8 +192,7 @@ BuildRequires: bluez-libs-devel BuildRequires: bzip2 BuildRequires: bzip2-devel BuildRequires: desktop-file-utils -# See the runtime requirement in the -libs subpackage -BuildRequires: expat-devel >= 2.6 +BuildRequires: expat-devel BuildRequires: findutils BuildRequires: gcc-c++ @@ -500,12 +499,20 @@ Recommends: (%{pkgname}-tkinter%{?_isa} = %{version}-%{release} if tk%{?_isa}) Requires: tzdata # The requirement on libexpat is generated, but we need to version it. -# When built with expat >= 2.6, but installed with older expat, we get: +# When built with a specific expat version, but installed with an older one, +# we sometimes get: # ImportError: /usr/lib64/python3.X/lib-dynload/pyexpat.cpython-....so: -# undefined symbol: XML_SetReparseDeferralEnabled +# undefined symbol: XML_... +# The pyexpat module has build-time checks for expat version to only use the +# available symbols. However, there is no runtime protection, so when the module +# is later installed with an older expat, it may error due to undefined symbols. # This breaks many things, including python -m venv. +# We avoid this problem by requiring at least the same version of expat that +# was used during the build time. # Other subpackages (like -debug) also need this, but they all depend on -libs. -Requires: expat >= 2.6 +%global expat_version %(LANG=C rpm -q --qf '%%{version}' expat.%{_target_cpu} | sed 's/.*not installed/0/') +Requires: expat >= %{expat_version} + %description -n %{pkgname}-libs This package contains runtime libraries for use by Python: @@ -1669,6 +1676,9 @@ CheckPython optimized # ====================================================== %changelog +* Tue Jan 06 2026 Karolina Surma - 3.11.14-2 +- Require at least the same expat version as used during the build time + * Fri Oct 10 2025 Karolina Surma - 3.11.14-1 - Update to 3.11.14 From 6bb200e1be0403b0555c483bff58eec6d3531216 Mon Sep 17 00:00:00 2001 From: Lumir Balhar Date: Thu, 8 Jan 2026 07:47:43 +0100 Subject: [PATCH 20/33] Security fix for CVE-2025-12084 --- 00471-cve-2025-12084.patch | 140 +++++++++++++++++++++++++++++++++++++ python3.11.spec | 12 +++- 2 files changed, 151 insertions(+), 1 deletion(-) create mode 100644 00471-cve-2025-12084.patch diff --git a/00471-cve-2025-12084.patch b/00471-cve-2025-12084.patch new file mode 100644 index 0000000..0796167 --- /dev/null +++ b/00471-cve-2025-12084.patch @@ -0,0 +1,140 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: "Miss Islington (bot)" + <31488909+miss-islington@users.noreply.github.com> +Date: Mon, 22 Dec 2025 14:48:49 +0100 +Subject: 00471: CVE-2025-12084 + +* gh-142145: Remove quadratic behavior in node ID cache clearing (GH-142146) +* gh-142754: Ensure that Element & Attr instances have the ownerDocument attribute (GH-142794) +(cherry picked from commit 1cc7551b3f9f71efbc88d96dce90f82de98b2454) +(cherry picked from commit 08d8e18ad81cd45bc4a27d6da478b51ea49486e4) +(cherry picked from commit 8d2d7bb2e754f8649a68ce4116271a4932f76907) + +Co-authored-by: Jacob Walls <38668450+jacobtylerwalls@users.noreply.github.com> +Co-authored-by: Seth Michael Larson +Co-authored-by: Petr Viktorin +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: 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 +--- + 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 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 @@ def testAppendChild(self): + 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. diff --git a/python3.11.spec b/python3.11.spec index bb078d6..df7e7cf 100644 --- a/python3.11.spec +++ b/python3.11.spec @@ -17,7 +17,7 @@ URL: https://www.python.org/ #global prerel ... %global upstream_version %{general_version}%{?prerel} Version: %{general_version}%{?prerel:~%{prerel}} -Release: 2%{?dist} +Release: 3%{?dist} License: Python-2.0.1 @@ -348,6 +348,13 @@ Patch452: 00452-properly-apply-exported-cflags-for-dtrace-systemtap-builds.patch # stressed on OpenSSL 3.5. Patch462: 00462-fix-pyssl_seterror-handling-ssl_error_syscall.patch +# 00471 # f7ffc7e947b58a4d33c7f5bb69674af20fe4875d +# CVE-2025-12084 +# +# * gh-142145: Remove quadratic behavior in node ID cache clearing (GH-142146) +# * gh-142754: Ensure that Element & Attr instances have the ownerDocument attribute (GH-142794) +Patch471: 00471-cve-2025-12084.patch + # (New patches go here ^^^) # # When adding new patches to "python" and "python3" in Fedora, EL, etc., @@ -1676,6 +1683,9 @@ CheckPython optimized # ====================================================== %changelog +* Thu Jan 08 2026 Lumír Balhar - 3.11.14-3 +- Security fix for CVE-2025-12084 + * Tue Jan 06 2026 Karolina Surma - 3.11.14-2 - Require at least the same expat version as used during the build time From 16eea4e6c0d921dd412ff637cfaa624a0ddbf016 Mon Sep 17 00:00:00 2001 From: Karolina Surma Date: Mon, 12 Jan 2026 11:55:39 +0100 Subject: [PATCH 21/33] Extend the expat requirement to differentiate between 32 and 64 arches (cherry picked from python3.15 commit a5ca170d3f1e6e19f5df66f21482c2b10593af42) --- python3.11.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python3.11.spec b/python3.11.spec index df7e7cf..3fa0684 100644 --- a/python3.11.spec +++ b/python3.11.spec @@ -518,7 +518,7 @@ Requires: tzdata # was used during the build time. # Other subpackages (like -debug) also need this, but they all depend on -libs. %global expat_version %(LANG=C rpm -q --qf '%%{version}' expat.%{_target_cpu} | sed 's/.*not installed/0/') -Requires: expat >= %{expat_version} +Requires: expat%{?_isa} >= %{expat_version} %description -n %{pkgname}-libs From ebabf83a2d592a969c891aa1c3f4e14d9c81cb4e Mon Sep 17 00:00:00 2001 From: Lumir Balhar Date: Fri, 16 Jan 2026 09:25:54 +0100 Subject: [PATCH 22/33] Security fix for CVE-2025-13836 --- 00472-cve-2025-13836.patch | 156 +++++++++++++++++++++++++++++++++++++ python3.11.spec | 17 +++- 2 files changed, 172 insertions(+), 1 deletion(-) create mode 100644 00472-cve-2025-13836.patch diff --git a/00472-cve-2025-13836.patch b/00472-cve-2025-13836.patch new file mode 100644 index 0000000..d6e937d --- /dev/null +++ b/00472-cve-2025-13836.patch @@ -0,0 +1,156 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Serhiy Storchaka +Date: Mon, 1 Dec 2025 17:26:07 +0200 +Subject: 00472: CVE-2025-13836 + +gh-119451: Fix a potential denial of service in http.client (GH-119454) + +Reading the whole body of the HTTP response could cause OOM if +the Content-Length value is too large even if the server does not send +a large amount of data. Now the HTTP client reads large data by chunks, +therefore the amount of consumed memory is proportional to the amount +of sent data. +(cherry picked from commit 5a4c4a033a4a54481be6870aa1896fad732555b5) + +Co-authored-by: Serhiy Storchaka +--- + Lib/http/client.py | 28 ++++++-- + Lib/test/test_httplib.py | 66 +++++++++++++++++++ + ...-05-23-11-47-48.gh-issue-119451.qkJe9-.rst | 5 ++ + 3 files changed, 95 insertions(+), 4 deletions(-) + create mode 100644 Misc/NEWS.d/next/Security/2024-05-23-11-47-48.gh-issue-119451.qkJe9-.rst + +diff --git a/Lib/http/client.py b/Lib/http/client.py +index 91ee1b470c..c977612732 100644 +--- a/Lib/http/client.py ++++ b/Lib/http/client.py +@@ -111,6 +111,11 @@ + _MAXLINE = 65536 + _MAXHEADERS = 100 + ++# Data larger than this will be read in chunks, to prevent extreme ++# overallocation. ++_MIN_READ_BUF_SIZE = 1 << 20 ++ ++ + # Header name/value ABNF (http://tools.ietf.org/html/rfc7230#section-3.2) + # + # VCHAR = %x21-7E +@@ -635,10 +640,25 @@ def _safe_read(self, amt): + reading. If the bytes are truly not available (due to EOF), then the + IncompleteRead exception can be used to detect the problem. + """ +- data = self.fp.read(amt) +- if len(data) < amt: +- raise IncompleteRead(data, amt-len(data)) +- return data ++ cursize = min(amt, _MIN_READ_BUF_SIZE) ++ data = self.fp.read(cursize) ++ if len(data) >= amt: ++ return data ++ if len(data) < cursize: ++ raise IncompleteRead(data, amt - len(data)) ++ ++ data = io.BytesIO(data) ++ data.seek(0, 2) ++ while True: ++ # This is a geometric increase in read size (never more than ++ # doubling out the current length of data per loop iteration). ++ delta = min(cursize, amt - cursize) ++ data.write(self.fp.read(delta)) ++ if data.tell() >= amt: ++ return data.getvalue() ++ cursize += delta ++ if data.tell() < cursize: ++ raise IncompleteRead(data.getvalue(), amt - data.tell()) + + def _safe_readinto(self, b): + """Same as _safe_read, but for reading into a buffer.""" +diff --git a/Lib/test/test_httplib.py b/Lib/test/test_httplib.py +index 8b9d49ec09..55363413b3 100644 +--- a/Lib/test/test_httplib.py ++++ b/Lib/test/test_httplib.py +@@ -1390,6 +1390,72 @@ def run_server(): + thread.join() + self.assertEqual(result, b"proxied data\n") + ++ def test_large_content_length(self): ++ serv = socket.create_server((HOST, 0)) ++ self.addCleanup(serv.close) ++ ++ def run_server(): ++ [conn, address] = serv.accept() ++ with conn: ++ while conn.recv(1024): ++ conn.sendall( ++ b"HTTP/1.1 200 Ok\r\n" ++ b"Content-Length: %d\r\n" ++ b"\r\n" % size) ++ conn.sendall(b'A' * (size//3)) ++ conn.sendall(b'B' * (size - size//3)) ++ ++ thread = threading.Thread(target=run_server) ++ thread.start() ++ self.addCleanup(thread.join, 1.0) ++ ++ conn = client.HTTPConnection(*serv.getsockname()) ++ try: ++ for w in range(15, 27): ++ size = 1 << w ++ conn.request("GET", "/") ++ with conn.getresponse() as response: ++ self.assertEqual(len(response.read()), size) ++ finally: ++ conn.close() ++ thread.join(1.0) ++ ++ def test_large_content_length_truncated(self): ++ serv = socket.create_server((HOST, 0)) ++ self.addCleanup(serv.close) ++ ++ def run_server(): ++ while True: ++ [conn, address] = serv.accept() ++ with conn: ++ conn.recv(1024) ++ if not size: ++ break ++ conn.sendall( ++ b"HTTP/1.1 200 Ok\r\n" ++ b"Content-Length: %d\r\n" ++ b"\r\n" ++ b"Text" % size) ++ ++ thread = threading.Thread(target=run_server) ++ thread.start() ++ self.addCleanup(thread.join, 1.0) ++ ++ conn = client.HTTPConnection(*serv.getsockname()) ++ try: ++ for w in range(18, 65): ++ size = 1 << w ++ conn.request("GET", "/") ++ with conn.getresponse() as response: ++ self.assertRaises(client.IncompleteRead, response.read) ++ conn.close() ++ finally: ++ conn.close() ++ size = 0 ++ conn.request("GET", "/") ++ conn.close() ++ thread.join(1.0) ++ + def test_putrequest_override_domain_validation(self): + """ + It should be possible to override the default validation +diff --git a/Misc/NEWS.d/next/Security/2024-05-23-11-47-48.gh-issue-119451.qkJe9-.rst b/Misc/NEWS.d/next/Security/2024-05-23-11-47-48.gh-issue-119451.qkJe9-.rst +new file mode 100644 +index 0000000000..6d6f25cd2f +--- /dev/null ++++ b/Misc/NEWS.d/next/Security/2024-05-23-11-47-48.gh-issue-119451.qkJe9-.rst +@@ -0,0 +1,5 @@ ++Fix a potential memory denial of service in the :mod:`http.client` module. ++When connecting to a malicious server, it could cause ++an arbitrary amount of memory to be allocated. ++This could have led to symptoms including a :exc:`MemoryError`, swapping, out ++of memory (OOM) killed processes or containers, or even system crashes. diff --git a/python3.11.spec b/python3.11.spec index 3fa0684..4693ab4 100644 --- a/python3.11.spec +++ b/python3.11.spec @@ -17,7 +17,7 @@ URL: https://www.python.org/ #global prerel ... %global upstream_version %{general_version}%{?prerel} Version: %{general_version}%{?prerel:~%{prerel}} -Release: 3%{?dist} +Release: 4%{?dist} License: Python-2.0.1 @@ -355,6 +355,18 @@ Patch462: 00462-fix-pyssl_seterror-handling-ssl_error_syscall.patch # * gh-142754: Ensure that Element & Attr instances have the ownerDocument attribute (GH-142794) Patch471: 00471-cve-2025-12084.patch +# 00472 # 2ba215eaba508b2cdd7c3acfdf3b9a6e32872274 +# CVE-2025-13836 +# +# gh-119451: Fix a potential denial of service in http.client (GH-119454) +# +# Reading the whole body of the HTTP response could cause OOM if +# the Content-Length value is too large even if the server does not send +# a large amount of data. Now the HTTP client reads large data by chunks, +# therefore the amount of consumed memory is proportional to the amount +# of sent data. +Patch472: 00472-cve-2025-13836.patch + # (New patches go here ^^^) # # When adding new patches to "python" and "python3" in Fedora, EL, etc., @@ -1683,6 +1695,9 @@ CheckPython optimized # ====================================================== %changelog +* Fri Jan 16 2026 Lumír Balhar - 3.11.14-4 +- Security fix for CVE-2025-13836 + * Thu Jan 08 2026 Lumír Balhar - 3.11.14-3 - Security fix for CVE-2025-12084 From 4c7421cb3c40814f20aa764be6fc07ab7c66e783 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Hrn=C4=8Diar?= Date: Mon, 9 Feb 2026 09:55:14 +0100 Subject: [PATCH 23/33] Security fixes for CVE-2026-0865, CVE-2025-15366 and CVE-2025-15367 --- 00473-cve-2026-0865.patch | 90 ++++++++++++++++++++++++++++++++++++++ 00474-cve-2025-15366.patch | 61 ++++++++++++++++++++++++++ 00475-cve-2025-15367.patch | 61 ++++++++++++++++++++++++++ python3.11.spec | 30 ++++++++++++- 4 files changed, 241 insertions(+), 1 deletion(-) create mode 100644 00473-cve-2026-0865.patch create mode 100644 00474-cve-2025-15366.patch create mode 100644 00475-cve-2025-15367.patch diff --git a/00473-cve-2026-0865.patch b/00473-cve-2026-0865.patch new file mode 100644 index 0000000..f7bec8e --- /dev/null +++ b/00473-cve-2026-0865.patch @@ -0,0 +1,90 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Seth Michael Larson +Date: Sat, 17 Jan 2026 11:46:21 -0600 +Subject: 00473: CVE-2026-0865 + + 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 +--- + 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 79e3d1c642..9270f3f8d6 100644 +--- a/Lib/test/support/__init__.py ++++ b/Lib/test/support/__init__.py +@@ -2282,3 +2282,10 @@ def copy_python_src_ignore(path, names): + #Windows doesn't have os.uname() but it doesn't support s390x. + skip_on_s390x = unittest.skipIf(hasattr(os, 'uname') and os.uname().machine == 's390x', + 'skipped on s390x') ++ ++ ++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 9316d0ecbc..28e3656632 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 +@@ -503,6 +503,16 @@ def testExtras(self): + '\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 fab851c5a4..fd98e85d75 100644 +--- a/Lib/wsgiref/headers.py ++++ b/Lib/wsgiref/headers.py +@@ -9,6 +9,7 @@ + # 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 @@ def __init__(self, headers=None): + 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 0000000000..44bd0b2705 +--- /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. diff --git a/00474-cve-2025-15366.patch b/00474-cve-2025-15366.patch new file mode 100644 index 0000000..0e474a4 --- /dev/null +++ b/00474-cve-2025-15366.patch @@ -0,0 +1,61 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Seth Michael Larson +Date: Tue, 20 Jan 2026 14:45:42 -0600 +Subject: 00474: CVE-2025-15366 + +gh-143921: Reject control characters in IMAP commands + +(cherry-picked from commit 6262704b134db2a4ba12e85ecfbd968534f28b45) +--- + Lib/imaplib.py | 4 +++- + Lib/test/test_imaplib.py | 6 ++++++ + .../Security/2026-01-16-11-41-06.gh-issue-143921.AeCOor.rst | 1 + + 3 files changed, 10 insertions(+), 1 deletion(-) + create mode 100644 Misc/NEWS.d/next/Security/2026-01-16-11-41-06.gh-issue-143921.AeCOor.rst + +diff --git a/Lib/imaplib.py b/Lib/imaplib.py +index 20b86c35d3..bc7628d17a 100644 +--- a/Lib/imaplib.py ++++ b/Lib/imaplib.py +@@ -132,7 +132,7 @@ + # We compile these in _mode_xxx. + _Literal = br'.*{(?P\d+)}$' + _Untagged_status = br'\* (?P\d+) (?P[A-Z-]+)( (?P.*))?' +- ++_control_chars = re.compile(b'[\x00-\x1F\x7F]') + + + class IMAP4: +@@ -994,6 +994,8 @@ def _command(self, name, *args): + if arg is None: continue + if isinstance(arg, str): + arg = bytes(arg, self._encoding) ++ if _control_chars.search(arg): ++ raise ValueError("Control characters not allowed in commands") + data = data + b' ' + arg + + literal = self.literal +diff --git a/Lib/test/test_imaplib.py b/Lib/test/test_imaplib.py +index 7665532d01..caf0884719 100644 +--- a/Lib/test/test_imaplib.py ++++ b/Lib/test/test_imaplib.py +@@ -510,6 +510,12 @@ def test_login(self): + self.assertEqual(data[0], b'LOGIN completed') + self.assertEqual(client.state, 'AUTH') + ++ def test_control_characters(self): ++ client, _ = self._setup(SimpleIMAPHandler) ++ for c0 in support.control_characters_c0(): ++ with self.assertRaises(ValueError): ++ client.login(f'user{c0}', 'pass') ++ + def test_logout(self): + client, _ = self._setup(SimpleIMAPHandler) + typ, data = client.login('user', 'pass') +diff --git a/Misc/NEWS.d/next/Security/2026-01-16-11-41-06.gh-issue-143921.AeCOor.rst b/Misc/NEWS.d/next/Security/2026-01-16-11-41-06.gh-issue-143921.AeCOor.rst +new file mode 100644 +index 0000000000..4e13fe92bc +--- /dev/null ++++ b/Misc/NEWS.d/next/Security/2026-01-16-11-41-06.gh-issue-143921.AeCOor.rst +@@ -0,0 +1 @@ ++Reject control characters in IMAP commands. diff --git a/00475-cve-2025-15367.patch b/00475-cve-2025-15367.patch new file mode 100644 index 0000000..eab4dec --- /dev/null +++ b/00475-cve-2025-15367.patch @@ -0,0 +1,61 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Seth Michael Larson +Date: Tue, 20 Jan 2026 14:46:32 -0600 +Subject: 00475: CVE-2025-15367 + +gh-143923: Reject control characters in POP3 commands + +(cherry-picked from commit b234a2b67539f787e191d2ef19a7cbdce32874e7) +--- + Lib/poplib.py | 2 ++ + Lib/test/test_poplib.py | 8 ++++++++ + .../2026-01-16-11-43-47.gh-issue-143923.DuytMe.rst | 1 + + 3 files changed, 11 insertions(+) + create mode 100644 Misc/NEWS.d/next/Security/2026-01-16-11-43-47.gh-issue-143923.DuytMe.rst + +diff --git a/Lib/poplib.py b/Lib/poplib.py +index 0f8587317c..f563030f7f 100644 +--- a/Lib/poplib.py ++++ b/Lib/poplib.py +@@ -122,6 +122,8 @@ def _putline(self, line): + def _putcmd(self, line): + if self._debugging: print('*cmd*', repr(line)) + line = bytes(line, self.encoding) ++ if re.search(b'[\x00-\x1F\x7F]', line): ++ raise ValueError('Control characters not allowed in commands') + self._putline(line) + + +diff --git a/Lib/test/test_poplib.py b/Lib/test/test_poplib.py +index 49ba993197..b56bc3535e 100644 +--- a/Lib/test/test_poplib.py ++++ b/Lib/test/test_poplib.py +@@ -12,6 +12,7 @@ + import unittest + from unittest import TestCase, skipUnless + from test import support as test_support ++from test.support import control_characters_c0 + from test.support import hashlib_helper + from test.support import socket_helper + from test.support import threading_helper +@@ -367,6 +368,13 @@ def test_quit(self): + self.assertIsNone(self.client.sock) + self.assertIsNone(self.client.file) + ++ def test_control_characters(self): ++ for c0 in control_characters_c0(): ++ with self.assertRaises(ValueError): ++ self.client.user(f'user{c0}') ++ with self.assertRaises(ValueError): ++ self.client.pass_(f'{c0}pass') ++ + @requires_ssl + def test_stls_capa(self): + capa = self.client.capa() +diff --git a/Misc/NEWS.d/next/Security/2026-01-16-11-43-47.gh-issue-143923.DuytMe.rst b/Misc/NEWS.d/next/Security/2026-01-16-11-43-47.gh-issue-143923.DuytMe.rst +new file mode 100644 +index 0000000000..3cde4df3e0 +--- /dev/null ++++ b/Misc/NEWS.d/next/Security/2026-01-16-11-43-47.gh-issue-143923.DuytMe.rst +@@ -0,0 +1 @@ ++Reject control characters in POP3 commands. diff --git a/python3.11.spec b/python3.11.spec index 4693ab4..f93ffc4 100644 --- a/python3.11.spec +++ b/python3.11.spec @@ -17,7 +17,7 @@ URL: https://www.python.org/ #global prerel ... %global upstream_version %{general_version}%{?prerel} Version: %{general_version}%{?prerel:~%{prerel}} -Release: 4%{?dist} +Release: 5%{?dist} License: Python-2.0.1 @@ -367,6 +367,31 @@ Patch471: 00471-cve-2025-12084.patch # of sent data. Patch472: 00472-cve-2025-13836.patch +# 00473 # 3c13163c5c0be4d073b081f19ad52c007c126d53 +# CVE-2026-0865 +# +# 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 +Patch473: 00473-cve-2026-0865.patch + +# 00474 # 837ddca0372fa87ff9cee47142200caa21e77def +# CVE-2025-15366 +# +# gh-143921: Reject control characters in IMAP commands +# +# (cherry-picked from commit 6262704b134db2a4ba12e85ecfbd968534f28b45) +Patch474: 00474-cve-2025-15366.patch + +# 00475 # 3748209a316662d4e85981ca1a7418547a1d25c6 +# CVE-2025-15367 +# +# gh-143923: Reject control characters in POP3 commands +# +# (cherry-picked from commit b234a2b67539f787e191d2ef19a7cbdce32874e7) +Patch475: 00475-cve-2025-15367.patch + # (New patches go here ^^^) # # When adding new patches to "python" and "python3" in Fedora, EL, etc., @@ -1695,6 +1720,9 @@ CheckPython optimized # ====================================================== %changelog +* Mon Feb 09 2026 Tomáš Hrnčiar - 3.11.14-5 +- Security fixes for CVE-2026-0865, CVE-2025-15366 and CVE-2025-15367 + * Fri Jan 16 2026 Lumír Balhar - 3.11.14-4 - Security fix for CVE-2025-13836 From 46ace4ef14d7b4723ce491b146b089735f574129 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Hrn=C4=8Diar?= Date: Tue, 3 Mar 2026 14:32:28 +0100 Subject: [PATCH 24/33] Update to 3.11.15 --- ..._seterror-handling-ssl_error_syscall.patch | 2 +- 00471-cve-2025-12084.patch | 140 ---------------- 00472-cve-2025-13836.patch | 156 ------------------ 00473-cve-2026-0865.patch | 90 ---------- python3.11.spec | 35 +--- sources | 4 +- 6 files changed, 8 insertions(+), 419 deletions(-) delete mode 100644 00471-cve-2025-12084.patch delete mode 100644 00472-cve-2025-13836.patch delete mode 100644 00473-cve-2026-0865.patch diff --git a/00462-fix-pyssl_seterror-handling-ssl_error_syscall.patch b/00462-fix-pyssl_seterror-handling-ssl_error_syscall.patch index 43182ad..0016e57 100644 --- a/00462-fix-pyssl_seterror-handling-ssl_error_syscall.patch +++ b/00462-fix-pyssl_seterror-handling-ssl_error_syscall.patch @@ -84,7 +84,7 @@ index 0000000000..75d926ab59 +Fix the :mod:`ssl` module error handling of connection terminate by peer. +It now throws an OSError with the appropriate error code instead of an EOFError. diff --git a/Modules/_ssl.c b/Modules/_ssl.c -index 09207abde1..787c241133 100644 +index 6275d94d64..ee7b131920 100644 --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -576,7 +576,7 @@ PySSL_ChainExceptions(PySSLSocket *sslsock) { diff --git a/00471-cve-2025-12084.patch b/00471-cve-2025-12084.patch deleted file mode 100644 index 0796167..0000000 --- a/00471-cve-2025-12084.patch +++ /dev/null @@ -1,140 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: "Miss Islington (bot)" - <31488909+miss-islington@users.noreply.github.com> -Date: Mon, 22 Dec 2025 14:48:49 +0100 -Subject: 00471: CVE-2025-12084 - -* gh-142145: Remove quadratic behavior in node ID cache clearing (GH-142146) -* gh-142754: Ensure that Element & Attr instances have the ownerDocument attribute (GH-142794) -(cherry picked from commit 1cc7551b3f9f71efbc88d96dce90f82de98b2454) -(cherry picked from commit 08d8e18ad81cd45bc4a27d6da478b51ea49486e4) -(cherry picked from commit 8d2d7bb2e754f8649a68ce4116271a4932f76907) - -Co-authored-by: Jacob Walls <38668450+jacobtylerwalls@users.noreply.github.com> -Co-authored-by: Seth Michael Larson -Co-authored-by: Petr Viktorin -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: 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 ---- - 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 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 @@ def testAppendChild(self): - 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. diff --git a/00472-cve-2025-13836.patch b/00472-cve-2025-13836.patch deleted file mode 100644 index d6e937d..0000000 --- a/00472-cve-2025-13836.patch +++ /dev/null @@ -1,156 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Serhiy Storchaka -Date: Mon, 1 Dec 2025 17:26:07 +0200 -Subject: 00472: CVE-2025-13836 - -gh-119451: Fix a potential denial of service in http.client (GH-119454) - -Reading the whole body of the HTTP response could cause OOM if -the Content-Length value is too large even if the server does not send -a large amount of data. Now the HTTP client reads large data by chunks, -therefore the amount of consumed memory is proportional to the amount -of sent data. -(cherry picked from commit 5a4c4a033a4a54481be6870aa1896fad732555b5) - -Co-authored-by: Serhiy Storchaka ---- - Lib/http/client.py | 28 ++++++-- - Lib/test/test_httplib.py | 66 +++++++++++++++++++ - ...-05-23-11-47-48.gh-issue-119451.qkJe9-.rst | 5 ++ - 3 files changed, 95 insertions(+), 4 deletions(-) - create mode 100644 Misc/NEWS.d/next/Security/2024-05-23-11-47-48.gh-issue-119451.qkJe9-.rst - -diff --git a/Lib/http/client.py b/Lib/http/client.py -index 91ee1b470c..c977612732 100644 ---- a/Lib/http/client.py -+++ b/Lib/http/client.py -@@ -111,6 +111,11 @@ - _MAXLINE = 65536 - _MAXHEADERS = 100 - -+# Data larger than this will be read in chunks, to prevent extreme -+# overallocation. -+_MIN_READ_BUF_SIZE = 1 << 20 -+ -+ - # Header name/value ABNF (http://tools.ietf.org/html/rfc7230#section-3.2) - # - # VCHAR = %x21-7E -@@ -635,10 +640,25 @@ def _safe_read(self, amt): - reading. If the bytes are truly not available (due to EOF), then the - IncompleteRead exception can be used to detect the problem. - """ -- data = self.fp.read(amt) -- if len(data) < amt: -- raise IncompleteRead(data, amt-len(data)) -- return data -+ cursize = min(amt, _MIN_READ_BUF_SIZE) -+ data = self.fp.read(cursize) -+ if len(data) >= amt: -+ return data -+ if len(data) < cursize: -+ raise IncompleteRead(data, amt - len(data)) -+ -+ data = io.BytesIO(data) -+ data.seek(0, 2) -+ while True: -+ # This is a geometric increase in read size (never more than -+ # doubling out the current length of data per loop iteration). -+ delta = min(cursize, amt - cursize) -+ data.write(self.fp.read(delta)) -+ if data.tell() >= amt: -+ return data.getvalue() -+ cursize += delta -+ if data.tell() < cursize: -+ raise IncompleteRead(data.getvalue(), amt - data.tell()) - - def _safe_readinto(self, b): - """Same as _safe_read, but for reading into a buffer.""" -diff --git a/Lib/test/test_httplib.py b/Lib/test/test_httplib.py -index 8b9d49ec09..55363413b3 100644 ---- a/Lib/test/test_httplib.py -+++ b/Lib/test/test_httplib.py -@@ -1390,6 +1390,72 @@ def run_server(): - thread.join() - self.assertEqual(result, b"proxied data\n") - -+ def test_large_content_length(self): -+ serv = socket.create_server((HOST, 0)) -+ self.addCleanup(serv.close) -+ -+ def run_server(): -+ [conn, address] = serv.accept() -+ with conn: -+ while conn.recv(1024): -+ conn.sendall( -+ b"HTTP/1.1 200 Ok\r\n" -+ b"Content-Length: %d\r\n" -+ b"\r\n" % size) -+ conn.sendall(b'A' * (size//3)) -+ conn.sendall(b'B' * (size - size//3)) -+ -+ thread = threading.Thread(target=run_server) -+ thread.start() -+ self.addCleanup(thread.join, 1.0) -+ -+ conn = client.HTTPConnection(*serv.getsockname()) -+ try: -+ for w in range(15, 27): -+ size = 1 << w -+ conn.request("GET", "/") -+ with conn.getresponse() as response: -+ self.assertEqual(len(response.read()), size) -+ finally: -+ conn.close() -+ thread.join(1.0) -+ -+ def test_large_content_length_truncated(self): -+ serv = socket.create_server((HOST, 0)) -+ self.addCleanup(serv.close) -+ -+ def run_server(): -+ while True: -+ [conn, address] = serv.accept() -+ with conn: -+ conn.recv(1024) -+ if not size: -+ break -+ conn.sendall( -+ b"HTTP/1.1 200 Ok\r\n" -+ b"Content-Length: %d\r\n" -+ b"\r\n" -+ b"Text" % size) -+ -+ thread = threading.Thread(target=run_server) -+ thread.start() -+ self.addCleanup(thread.join, 1.0) -+ -+ conn = client.HTTPConnection(*serv.getsockname()) -+ try: -+ for w in range(18, 65): -+ size = 1 << w -+ conn.request("GET", "/") -+ with conn.getresponse() as response: -+ self.assertRaises(client.IncompleteRead, response.read) -+ conn.close() -+ finally: -+ conn.close() -+ size = 0 -+ conn.request("GET", "/") -+ conn.close() -+ thread.join(1.0) -+ - def test_putrequest_override_domain_validation(self): - """ - It should be possible to override the default validation -diff --git a/Misc/NEWS.d/next/Security/2024-05-23-11-47-48.gh-issue-119451.qkJe9-.rst b/Misc/NEWS.d/next/Security/2024-05-23-11-47-48.gh-issue-119451.qkJe9-.rst -new file mode 100644 -index 0000000000..6d6f25cd2f ---- /dev/null -+++ b/Misc/NEWS.d/next/Security/2024-05-23-11-47-48.gh-issue-119451.qkJe9-.rst -@@ -0,0 +1,5 @@ -+Fix a potential memory denial of service in the :mod:`http.client` module. -+When connecting to a malicious server, it could cause -+an arbitrary amount of memory to be allocated. -+This could have led to symptoms including a :exc:`MemoryError`, swapping, out -+of memory (OOM) killed processes or containers, or even system crashes. diff --git a/00473-cve-2026-0865.patch b/00473-cve-2026-0865.patch deleted file mode 100644 index f7bec8e..0000000 --- a/00473-cve-2026-0865.patch +++ /dev/null @@ -1,90 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Seth Michael Larson -Date: Sat, 17 Jan 2026 11:46:21 -0600 -Subject: 00473: CVE-2026-0865 - - 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 ---- - 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 79e3d1c642..9270f3f8d6 100644 ---- a/Lib/test/support/__init__.py -+++ b/Lib/test/support/__init__.py -@@ -2282,3 +2282,10 @@ def copy_python_src_ignore(path, names): - #Windows doesn't have os.uname() but it doesn't support s390x. - skip_on_s390x = unittest.skipIf(hasattr(os, 'uname') and os.uname().machine == 's390x', - 'skipped on s390x') -+ -+ -+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 9316d0ecbc..28e3656632 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 -@@ -503,6 +503,16 @@ def testExtras(self): - '\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 fab851c5a4..fd98e85d75 100644 ---- a/Lib/wsgiref/headers.py -+++ b/Lib/wsgiref/headers.py -@@ -9,6 +9,7 @@ - # 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 @@ def __init__(self, headers=None): - 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 0000000000..44bd0b2705 ---- /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. diff --git a/python3.11.spec b/python3.11.spec index f93ffc4..57468d4 100644 --- a/python3.11.spec +++ b/python3.11.spec @@ -13,11 +13,11 @@ URL: https://www.python.org/ # WARNING When rebasing to a new Python version, # remember to update the python3-docs package as well -%global general_version %{pybasever}.14 +%global general_version %{pybasever}.15 #global prerel ... %global upstream_version %{general_version}%{?prerel} Version: %{general_version}%{?prerel:~%{prerel}} -Release: 5%{?dist} +Release: 1%{?dist} License: Python-2.0.1 @@ -348,34 +348,6 @@ Patch452: 00452-properly-apply-exported-cflags-for-dtrace-systemtap-builds.patch # stressed on OpenSSL 3.5. Patch462: 00462-fix-pyssl_seterror-handling-ssl_error_syscall.patch -# 00471 # f7ffc7e947b58a4d33c7f5bb69674af20fe4875d -# CVE-2025-12084 -# -# * gh-142145: Remove quadratic behavior in node ID cache clearing (GH-142146) -# * gh-142754: Ensure that Element & Attr instances have the ownerDocument attribute (GH-142794) -Patch471: 00471-cve-2025-12084.patch - -# 00472 # 2ba215eaba508b2cdd7c3acfdf3b9a6e32872274 -# CVE-2025-13836 -# -# gh-119451: Fix a potential denial of service in http.client (GH-119454) -# -# Reading the whole body of the HTTP response could cause OOM if -# the Content-Length value is too large even if the server does not send -# a large amount of data. Now the HTTP client reads large data by chunks, -# therefore the amount of consumed memory is proportional to the amount -# of sent data. -Patch472: 00472-cve-2025-13836.patch - -# 00473 # 3c13163c5c0be4d073b081f19ad52c007c126d53 -# CVE-2026-0865 -# -# 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 -Patch473: 00473-cve-2026-0865.patch - # 00474 # 837ddca0372fa87ff9cee47142200caa21e77def # CVE-2025-15366 # @@ -1720,6 +1692,9 @@ CheckPython optimized # ====================================================== %changelog +* Tue Mar 03 2026 Tomáš Hrnčiar - 3.11.15-1 +- Update to 3.11.15 + * Mon Feb 09 2026 Tomáš Hrnčiar - 3.11.14-5 - Security fixes for CVE-2026-0865, CVE-2025-15366 and CVE-2025-15367 diff --git a/sources b/sources index d418a33..c0c09ac 100644 --- a/sources +++ b/sources @@ -1,2 +1,2 @@ -SHA512 (Python-3.11.14.tar.xz) = 8b5aa917fe67dbaa3c306239ed56c16cd7a3b4b701fab0b3dc0d342d60176c75440713bcab0c59a3289ac4a0f06103bd31140c492556e1937fcdbd990675f9e5 -SHA512 (Python-3.11.14.tar.xz.asc) = d0049fd6f6d06ae5d86b3587080be060d522dd52e7e56270125541d5617582ea3977b75c7e585da005694665cfc5657e39033a730187c506edc252965f4df769 +SHA512 (Python-3.11.15.tar.xz) = 1667f4839acfd23d05917a12993983b7dc3ab4438a37c72496fd040ac6981f4dea9dc95461ca701a6862beedb56c423fb83398b8b18e39e1efe12f539fced1c1 +SHA512 (Python-3.11.15.tar.xz.asc) = 673822ca037acb521bf7d3e7433f83cc2d60c8d102cfbf6695234e2a50ce12a7003040ad4017438510ebbb1ff0ba6727253fae250b07bc0e3d24b5578e80be52 From 067265083c5be1c35962b6a43dd0d68a0feeb810 Mon Sep 17 00:00:00 2001 From: Lumir Balhar Date: Thu, 26 Mar 2026 11:48:28 +0100 Subject: [PATCH 25/33] Security fix for CVE-2026-4519 (rhbz#2449727) --- 00478-cve-2026-4519.patch | 121 ++++++++++++++++++++++++++++++++++++++ python3.11.spec | 11 +++- 2 files changed, 131 insertions(+), 1 deletion(-) create mode 100644 00478-cve-2026-4519.patch diff --git a/00478-cve-2026-4519.patch b/00478-cve-2026-4519.patch new file mode 100644 index 0000000..eb9d2ef --- /dev/null +++ b/00478-cve-2026-4519.patch @@ -0,0 +1,121 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: tomcruiseqi +Date: Wed, 25 Mar 2026 02:23:28 +0800 +Subject: 00478: CVE-2026-4519 + +Reject leading dashes in webbrowser URLs (GH-143931) (GH-146364) + +(cherry picked from commit 82a24a4442312bdcfc4c799885e8b3e00990f02b) + +Co-authored-by: Seth Michael Larson +--- + Lib/test/test_webbrowser.py | 5 +++++ + Lib/webbrowser.py | 14 ++++++++++++++ + .../2026-01-16-12-04-49.gh-issue-143930.zYC5x3.rst | 1 + + 3 files changed, 20 insertions(+) + create mode 100644 Misc/NEWS.d/next/Security/2026-01-16-12-04-49.gh-issue-143930.zYC5x3.rst + +diff --git a/Lib/test/test_webbrowser.py b/Lib/test/test_webbrowser.py +index 9d608d63a0..0ac985f56c 100644 +--- a/Lib/test/test_webbrowser.py ++++ b/Lib/test/test_webbrowser.py +@@ -59,6 +59,11 @@ def test_open(self): + options=[], + arguments=[URL]) + ++ def test_reject_dash_prefixes(self): ++ browser = self.browser_class(name=CMD_NAME) ++ with self.assertRaises(ValueError): ++ browser.open(f"--key=val {URL}") ++ + + class BackgroundBrowserCommandTest(CommandTestMixin, unittest.TestCase): + +diff --git a/Lib/webbrowser.py b/Lib/webbrowser.py +index 5d72524c08..0fd0aeb3c1 100755 +--- a/Lib/webbrowser.py ++++ b/Lib/webbrowser.py +@@ -155,6 +155,12 @@ def open_new(self, url): + def open_new_tab(self, url): + return self.open(url, 2) + ++ @staticmethod ++ def _check_url(url): ++ """Ensures that the URL is safe to pass to subprocesses as a parameter""" ++ if url and url.lstrip().startswith("-"): ++ raise ValueError(f"Invalid URL: {url}") ++ + + class GenericBrowser(BaseBrowser): + """Class for all browsers started with a command +@@ -172,6 +178,7 @@ def __init__(self, name): + + def open(self, url, new=0, autoraise=True): + sys.audit("webbrowser.open", url) ++ self._check_url(url) + cmdline = [self.name] + [arg.replace("%s", url) + for arg in self.args] + try: +@@ -192,6 +199,7 @@ def open(self, url, new=0, autoraise=True): + cmdline = [self.name] + [arg.replace("%s", url) + for arg in self.args] + sys.audit("webbrowser.open", url) ++ self._check_url(url) + try: + if sys.platform[:3] == 'win': + p = subprocess.Popen(cmdline) +@@ -257,6 +265,7 @@ def _invoke(self, args, remote, autoraise, url=None): + + def open(self, url, new=0, autoraise=True): + sys.audit("webbrowser.open", url) ++ self._check_url(url) + if new == 0: + action = self.remote_action + elif new == 1: +@@ -358,6 +367,7 @@ class Konqueror(BaseBrowser): + + def open(self, url, new=0, autoraise=True): + sys.audit("webbrowser.open", url) ++ self._check_url(url) + # XXX Currently I know no way to prevent KFM from opening a new win. + if new == 2: + action = "newTab" +@@ -442,6 +452,7 @@ def _remote(self, action): + + def open(self, url, new=0, autoraise=True): + sys.audit("webbrowser.open", url) ++ self._check_url(url) + if new: + ok = self._remote("LOADNEW " + url) + else: +@@ -605,6 +616,7 @@ def register_standard_browsers(): + class WindowsDefault(BaseBrowser): + def open(self, url, new=0, autoraise=True): + sys.audit("webbrowser.open", url) ++ self._check_url(url) + try: + os.startfile(url) + except OSError: +@@ -637,6 +649,7 @@ def __init__(self, name): + + def open(self, url, new=0, autoraise=True): + sys.audit("webbrowser.open", url) ++ self._check_url(url) + assert "'" not in url + # hack for local urls + if not ':' in url: +@@ -689,6 +702,7 @@ def _name(self, val): + + def open(self, url, new=0, autoraise=True): + sys.audit("webbrowser.open", url) ++ self._check_url(url) + if self.name == 'default': + script = 'open location "%s"' % url.replace('"', '%22') # opens in default browser + else: +diff --git a/Misc/NEWS.d/next/Security/2026-01-16-12-04-49.gh-issue-143930.zYC5x3.rst b/Misc/NEWS.d/next/Security/2026-01-16-12-04-49.gh-issue-143930.zYC5x3.rst +new file mode 100644 +index 0000000000..0f27eae99a +--- /dev/null ++++ b/Misc/NEWS.d/next/Security/2026-01-16-12-04-49.gh-issue-143930.zYC5x3.rst +@@ -0,0 +1 @@ ++Reject leading dashes in URLs passed to :func:`webbrowser.open` diff --git a/python3.11.spec b/python3.11.spec index 57468d4..76fcaf6 100644 --- a/python3.11.spec +++ b/python3.11.spec @@ -17,7 +17,7 @@ URL: https://www.python.org/ #global prerel ... %global upstream_version %{general_version}%{?prerel} Version: %{general_version}%{?prerel:~%{prerel}} -Release: 1%{?dist} +Release: 2%{?dist} License: Python-2.0.1 @@ -364,6 +364,12 @@ Patch474: 00474-cve-2025-15366.patch # (cherry-picked from commit b234a2b67539f787e191d2ef19a7cbdce32874e7) Patch475: 00475-cve-2025-15367.patch +# 00478 # 40c5c88950b10eaf1c10c5afcc39887b8e23c997 +# CVE-2026-4519 +# +# Reject leading dashes in webbrowser URLs (GH-143931) (GH-146364) +Patch478: 00478-cve-2026-4519.patch + # (New patches go here ^^^) # # When adding new patches to "python" and "python3" in Fedora, EL, etc., @@ -1692,6 +1698,9 @@ CheckPython optimized # ====================================================== %changelog +* Thu Mar 26 2026 Lumír Balhar - 3.11.15-2 +- Security fix for CVE-2026-4519 (rhbz#2449727) + * Tue Mar 03 2026 Tomáš Hrnčiar - 3.11.15-1 - Update to 3.11.15 From b6a32dca60faf21771b2e8b45fcb11e5fbaaeb15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Wed, 11 Mar 2026 19:39:18 +0100 Subject: [PATCH 26/33] Only explicitly require expat >= installed version when expat < 2.7.4 See https://src.fedoraproject.org/rpms/expat/c/4da0543472 (cherry picked from python3.15 commit ce1bde3e67443b7cf5df33bf58cb2ec75cc2c8e2) --- python3.11.spec | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/python3.11.spec b/python3.11.spec index 76fcaf6..c2c22c5 100644 --- a/python3.11.spec +++ b/python3.11.spec @@ -532,8 +532,12 @@ Requires: tzdata # We avoid this problem by requiring at least the same version of expat that # was used during the build time. # Other subpackages (like -debug) also need this, but they all depend on -libs. +# Since expat 2.7.4, the library has versioned symbols and this is no longer needed, +# as the generated requirement will be in the form of libexpat.so.1(LIBEXPAT_2.7.2) etc. %global expat_version %(LANG=C rpm -q --qf '%%{version}' expat.%{_target_cpu} | sed 's/.*not installed/0/') +%if v"%{expat_version}" < v"2.7.4" Requires: expat%{?_isa} >= %{expat_version} +%endif %description -n %{pkgname}-libs From 9be9ebcf5faa7cba7f19241fccd128160dd13164 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Thu, 9 Apr 2026 13:16:25 +0200 Subject: [PATCH 27/33] Explicitly build with OpenSSL 3 for now https://fedoraproject.org/wiki/Changes/OpenSSL40 --- python3.11.spec | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/python3.11.spec b/python3.11.spec index c2c22c5..4bd9ce7 100644 --- a/python3.11.spec +++ b/python3.11.spec @@ -17,7 +17,7 @@ URL: https://www.python.org/ #global prerel ... %global upstream_version %{general_version}%{?prerel} Version: %{general_version}%{?prerel:~%{prerel}} -Release: 2%{?dist} +Release: 3%{?dist} License: Python-2.0.1 @@ -219,7 +219,6 @@ BuildRequires: make BuildRequires: mpdecimal-devel BuildRequires: ncurses-devel -BuildRequires: openssl-devel BuildRequires: pkgconfig BuildRequires: readline-devel BuildRequires: redhat-rpm-config >= 127 @@ -232,6 +231,10 @@ BuildRequires: tix-devel BuildRequires: tk-devel < 1:9 BuildRequires: tzdata +# Support for OpenSSL 4 only landed in Python 3.15 for now +# https://github.com/python/cpython/issues/146207 +BuildRequires: (openssl-devel < 1:4 or openssl3-devel) + %if %{with valgrind} BuildRequires: valgrind-devel %endif @@ -1702,6 +1705,9 @@ CheckPython optimized # ====================================================== %changelog +* Sat Apr 11 2026 Miro Hrončok - 3.11.15-3 +- Explicitly build with OpenSSL 3 + * Thu Mar 26 2026 Lumír Balhar - 3.11.15-2 - Security fix for CVE-2026-4519 (rhbz#2449727) From f51f0ca45b8bd9ab9f9079650f3542c0678e3a56 Mon Sep 17 00:00:00 2001 From: Charalampos Stratakis Date: Fri, 17 Apr 2026 03:41:06 +0200 Subject: [PATCH 28/33] Security fixes for CVE-2026-1502, CVE-2026-4786, CVE-2026-6100, CVE-2026-2297, CVE 2026-3644, CVE-2026-4224 Resolves: rhbz#2457941, rhbz#2458221, rhbz#2458013, rhbz#2444704, rhbz#2448188, rhbz#2448204 --- 00479-cve-2026-1502.patch | 106 +++++++++++++++++++++++++++ 00480-cve-2026-4786.patch | 63 ++++++++++++++++ 00482-cve-2026-6100.patch | 48 +++++++++++++ 00483-cve-2026-2297.patch | 33 +++++++++ 00484-cve-2026-3644.patch | 146 ++++++++++++++++++++++++++++++++++++++ 00485-cve-2026-4224.patch | 98 +++++++++++++++++++++++++ python3.11.spec | 42 ++++++++++- 7 files changed, 535 insertions(+), 1 deletion(-) create mode 100644 00479-cve-2026-1502.patch create mode 100644 00480-cve-2026-4786.patch create mode 100644 00482-cve-2026-6100.patch create mode 100644 00483-cve-2026-2297.patch create mode 100644 00484-cve-2026-3644.patch create mode 100644 00485-cve-2026-4224.patch diff --git a/00479-cve-2026-1502.patch b/00479-cve-2026-1502.patch new file mode 100644 index 0000000..b6ce808 --- /dev/null +++ b/00479-cve-2026-1502.patch @@ -0,0 +1,106 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Seth Larson +Date: Fri, 10 Apr 2026 10:21:42 -0500 +Subject: 00479: CVE-2026-1502 + +Reject CR/LF in HTTP tunnel request headers + +Co-authored-by: Illia Volochii +--- + Lib/http/client.py | 11 ++++- + Lib/test/test_httplib.py | 45 +++++++++++++++++++ + ...-03-20-09-29-42.gh-issue-146211.PQVbs7.rst | 2 + + 3 files changed, 57 insertions(+), 1 deletion(-) + create mode 100644 Misc/NEWS.d/next/Security/2026-03-20-09-29-42.gh-issue-146211.PQVbs7.rst + +diff --git a/Lib/http/client.py b/Lib/http/client.py +index c977612732..8cf783ab30 100644 +--- a/Lib/http/client.py ++++ b/Lib/http/client.py +@@ -941,12 +941,21 @@ def _wrap_ipv6(self, ip): + return ip + + def _tunnel(self): ++ if _contains_disallowed_url_pchar_re.search(self._tunnel_host): ++ raise ValueError('Tunnel host can\'t contain control characters %r' ++ % (self._tunnel_host,)) + connect = b"CONNECT %s:%d HTTP/1.0\r\n" % ( + self._wrap_ipv6(self._tunnel_host.encode("ascii")), + self._tunnel_port) + headers = [connect] + for header, value in self._tunnel_headers.items(): +- headers.append(f"{header}: {value}\r\n".encode("latin-1")) ++ header_bytes = header.encode("latin-1") ++ value_bytes = value.encode("latin-1") ++ if not _is_legal_header_name(header_bytes): ++ raise ValueError('Invalid header name %r' % (header_bytes,)) ++ if _is_illegal_header_value(value_bytes): ++ raise ValueError('Invalid header value %r' % (value_bytes,)) ++ headers.append(b"%s: %s\r\n" % (header_bytes, value_bytes)) + headers.append(b"\r\n") + # Making a single send() call instead of one per line encourages + # the host OS to use a more optimal packet size instead of +diff --git a/Lib/test/test_httplib.py b/Lib/test/test_httplib.py +index 55363413b3..a4ab909ca9 100644 +--- a/Lib/test/test_httplib.py ++++ b/Lib/test/test_httplib.py +@@ -371,6 +371,51 @@ def test_invalid_headers(self): + with self.assertRaisesRegex(ValueError, 'Invalid header'): + conn.putheader(name, value) + ++ def test_invalid_tunnel_headers(self): ++ cases = ( ++ ('Invalid\r\nName', 'ValidValue'), ++ ('Invalid\rName', 'ValidValue'), ++ ('Invalid\nName', 'ValidValue'), ++ ('\r\nInvalidName', 'ValidValue'), ++ ('\rInvalidName', 'ValidValue'), ++ ('\nInvalidName', 'ValidValue'), ++ (' InvalidName', 'ValidValue'), ++ ('\tInvalidName', 'ValidValue'), ++ ('Invalid:Name', 'ValidValue'), ++ (':InvalidName', 'ValidValue'), ++ ('ValidName', 'Invalid\r\nValue'), ++ ('ValidName', 'Invalid\rValue'), ++ ('ValidName', 'Invalid\nValue'), ++ ('ValidName', 'InvalidValue\r\n'), ++ ('ValidName', 'InvalidValue\r'), ++ ('ValidName', 'InvalidValue\n'), ++ ) ++ for name, value in cases: ++ with self.subTest((name, value)): ++ conn = client.HTTPConnection('example.com') ++ conn.set_tunnel('tunnel', headers={ ++ name: value ++ }) ++ conn.sock = FakeSocket('') ++ with self.assertRaisesRegex(ValueError, 'Invalid header'): ++ conn._tunnel() # Called in .connect() ++ ++ def test_invalid_tunnel_host(self): ++ cases = ( ++ 'invalid\r.host', ++ '\ninvalid.host', ++ 'invalid.host\r\n', ++ 'invalid.host\x00', ++ 'invalid host', ++ ) ++ for tunnel_host in cases: ++ with self.subTest(tunnel_host): ++ conn = client.HTTPConnection('example.com') ++ conn.set_tunnel(tunnel_host) ++ conn.sock = FakeSocket('') ++ with self.assertRaisesRegex(ValueError, 'Tunnel host can\'t contain control characters'): ++ conn._tunnel() # Called in .connect() ++ + def test_headers_debuglevel(self): + body = ( + b'HTTP/1.1 200 OK\r\n' +diff --git a/Misc/NEWS.d/next/Security/2026-03-20-09-29-42.gh-issue-146211.PQVbs7.rst b/Misc/NEWS.d/next/Security/2026-03-20-09-29-42.gh-issue-146211.PQVbs7.rst +new file mode 100644 +index 0000000000..4993633b8e +--- /dev/null ++++ b/Misc/NEWS.d/next/Security/2026-03-20-09-29-42.gh-issue-146211.PQVbs7.rst +@@ -0,0 +1,2 @@ ++Reject CR/LF characters in tunnel request headers for the ++HTTPConnection.set_tunnel() method. diff --git a/00480-cve-2026-4786.patch b/00480-cve-2026-4786.patch new file mode 100644 index 0000000..a0fcb66 --- /dev/null +++ b/00480-cve-2026-4786.patch @@ -0,0 +1,63 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Stan Ulbrych +Date: Mon, 13 Apr 2026 22:41:51 +0100 +Subject: 00480: CVE-2026-4786 + +Fix webbrowser `%action` substitution bypass of dash-prefix check +--- + Lib/test/test_webbrowser.py | 8 ++++++++ + Lib/webbrowser.py | 5 +++-- + .../2026-03-31-09-15-51.gh-issue-148169.EZJzz2.rst | 2 ++ + 3 files changed, 13 insertions(+), 2 deletions(-) + create mode 100644 Misc/NEWS.d/next/Security/2026-03-31-09-15-51.gh-issue-148169.EZJzz2.rst + +diff --git a/Lib/test/test_webbrowser.py b/Lib/test/test_webbrowser.py +index 0ac985f56c..d629f889db 100644 +--- a/Lib/test/test_webbrowser.py ++++ b/Lib/test/test_webbrowser.py +@@ -99,6 +99,14 @@ def test_open_new_tab(self): + options=[], + arguments=[URL]) + ++ def test_reject_action_dash_prefixes(self): ++ browser = self.browser_class(name=CMD_NAME) ++ with self.assertRaises(ValueError): ++ browser.open('%action--incognito') ++ # new=1: action is "--new-window", so "%action" itself expands to ++ # a dash-prefixed flag even with no dash in the original URL. ++ with self.assertRaises(ValueError): ++ browser.open('%action', new=1) + + class MozillaCommandTest(CommandTestMixin, unittest.TestCase): + +diff --git a/Lib/webbrowser.py b/Lib/webbrowser.py +index 0fd0aeb3c1..026bdfbd7b 100755 +--- a/Lib/webbrowser.py ++++ b/Lib/webbrowser.py +@@ -265,7 +265,6 @@ def _invoke(self, args, remote, autoraise, url=None): + + def open(self, url, new=0, autoraise=True): + sys.audit("webbrowser.open", url) +- self._check_url(url) + if new == 0: + action = self.remote_action + elif new == 1: +@@ -279,7 +278,9 @@ def open(self, url, new=0, autoraise=True): + raise Error("Bad 'new' parameter to open(); " + + "expected 0, 1, or 2, got %s" % new) + +- args = [arg.replace("%s", url).replace("%action", action) ++ self._check_url(url.replace("%action", action)) ++ ++ args = [arg.replace("%action", action).replace("%s", url) + for arg in self.remote_args] + args = [arg for arg in args if arg] + success = self._invoke(args, True, autoraise, url) +diff --git a/Misc/NEWS.d/next/Security/2026-03-31-09-15-51.gh-issue-148169.EZJzz2.rst b/Misc/NEWS.d/next/Security/2026-03-31-09-15-51.gh-issue-148169.EZJzz2.rst +new file mode 100644 +index 0000000000..45cdeebe1b +--- /dev/null ++++ b/Misc/NEWS.d/next/Security/2026-03-31-09-15-51.gh-issue-148169.EZJzz2.rst +@@ -0,0 +1,2 @@ ++A bypass in :mod:`webbrowser` allowed URLs prefixed with ``%action`` to pass ++the dash-prefix safety check. diff --git a/00482-cve-2026-6100.patch b/00482-cve-2026-6100.patch new file mode 100644 index 0000000..ad4c39b --- /dev/null +++ b/00482-cve-2026-6100.patch @@ -0,0 +1,48 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Stan Ulbrych +Date: Mon, 13 Apr 2026 22:42:36 +0100 +Subject: 00482: CVE-2026-6100 + +Fix a possible UAF in {LZMA,BZ2,_Zlib}Decompressor +--- + .../Security/2026-04-10-16-28-21.gh-issue-148395.kfzm0G.rst | 5 +++++ + Modules/_bz2module.c | 1 + + Modules/_lzmamodule.c | 1 + + 3 files changed, 7 insertions(+) + create mode 100644 Misc/NEWS.d/next/Security/2026-04-10-16-28-21.gh-issue-148395.kfzm0G.rst + +diff --git a/Misc/NEWS.d/next/Security/2026-04-10-16-28-21.gh-issue-148395.kfzm0G.rst b/Misc/NEWS.d/next/Security/2026-04-10-16-28-21.gh-issue-148395.kfzm0G.rst +new file mode 100644 +index 0000000000..349d1cf3ca +--- /dev/null ++++ b/Misc/NEWS.d/next/Security/2026-04-10-16-28-21.gh-issue-148395.kfzm0G.rst +@@ -0,0 +1,5 @@ ++Fix a dangling input pointer in :class:`lzma.LZMADecompressor`, ++and :class:`bz2.BZ2Decompressor` ++when memory allocation fails with :exc:`MemoryError`, which could let a ++subsequent :meth:`!decompress` call read or write through a stale pointer to ++the already-released caller buffer. +diff --git a/Modules/_bz2module.c b/Modules/_bz2module.c +index 798e9efc62..b08ac5e44e 100644 +--- a/Modules/_bz2module.c ++++ b/Modules/_bz2module.c +@@ -595,6 +595,7 @@ decompress(BZ2Decompressor *d, char *data, size_t len, Py_ssize_t max_length) + return result; + + error: ++ bzs->next_in = NULL; + Py_XDECREF(result); + return NULL; + } +diff --git a/Modules/_lzmamodule.c b/Modules/_lzmamodule.c +index 97453a2808..51106a6a07 100644 +--- a/Modules/_lzmamodule.c ++++ b/Modules/_lzmamodule.c +@@ -1105,6 +1105,7 @@ decompress(Decompressor *d, uint8_t *data, size_t len, Py_ssize_t max_length) + return result; + + error: ++ lzs->next_in = NULL; + Py_XDECREF(result); + return NULL; + } diff --git a/00483-cve-2026-2297.patch b/00483-cve-2026-2297.patch new file mode 100644 index 0000000..b71b19f --- /dev/null +++ b/00483-cve-2026-2297.patch @@ -0,0 +1,33 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Steve Dower +Date: Wed, 4 Mar 2026 19:55:52 +0000 +Subject: 00483: CVE-2026-2297 + +Logging Bypass in Legacy .pyc File Handling +--- + Lib/importlib/_bootstrap_external.py | 2 +- + .../Security/2026-03-04-18-59-17.gh-issue-145506.6hwvEh.rst | 2 ++ + 2 files changed, 3 insertions(+), 1 deletion(-) + create mode 100644 Misc/NEWS.d/next/Security/2026-03-04-18-59-17.gh-issue-145506.6hwvEh.rst + +diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py +index e53f6acf38..588da3c7ad 100644 +--- a/Lib/importlib/_bootstrap_external.py ++++ b/Lib/importlib/_bootstrap_external.py +@@ -1126,7 +1126,7 @@ def get_filename(self, fullname): + + def get_data(self, path): + """Return the data from path as raw bytes.""" +- if isinstance(self, (SourceLoader, ExtensionFileLoader)): ++ if isinstance(self, (SourceLoader, SourcelessFileLoader, ExtensionFileLoader)): + with _io.open_code(str(path)) as file: + return file.read() + else: +diff --git a/Misc/NEWS.d/next/Security/2026-03-04-18-59-17.gh-issue-145506.6hwvEh.rst b/Misc/NEWS.d/next/Security/2026-03-04-18-59-17.gh-issue-145506.6hwvEh.rst +new file mode 100644 +index 0000000000..edeb9e640c +--- /dev/null ++++ b/Misc/NEWS.d/next/Security/2026-03-04-18-59-17.gh-issue-145506.6hwvEh.rst +@@ -0,0 +1,2 @@ ++Fixes CVE-2026-2297 by ensuring that ``SourcelessFileLoader`` uses ++:func:`io.open_code` when opening ``.pyc`` files. diff --git a/00484-cve-2026-3644.patch b/00484-cve-2026-3644.patch new file mode 100644 index 0000000..b01be87 --- /dev/null +++ b/00484-cve-2026-3644.patch @@ -0,0 +1,146 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Stan Ulbrych <89152624+StanFromIreland@users.noreply.github.com> +Date: Mon, 16 Mar 2026 13:43:43 +0000 +Subject: 00484: CVE-2026-3644 + +Incomplete control character validation in http.cookies + +Co-authored-by: Victor Stinner +--- + Lib/http/cookies.py | 24 ++++++++++-- + Lib/test/test_http_cookies.py | 38 +++++++++++++++++++ + ...-03-06-17-03-38.gh-issue-145599.kchwZV.rst | 4 ++ + 3 files changed, 62 insertions(+), 4 deletions(-) + create mode 100644 Misc/NEWS.d/next/Security/2026-03-06-17-03-38.gh-issue-145599.kchwZV.rst + +diff --git a/Lib/http/cookies.py b/Lib/http/cookies.py +index 5cfa7a8072..6b36ffa9f8 100644 +--- a/Lib/http/cookies.py ++++ b/Lib/http/cookies.py +@@ -335,9 +335,16 @@ def update(self, values): + key = key.lower() + if key not in self._reserved: + raise CookieError("Invalid attribute %r" % (key,)) ++ if _has_control_character(key, val): ++ raise CookieError("Control characters are not allowed in " ++ f"cookies {key!r} {val!r}") + data[key] = val + dict.update(self, data) + ++ def __ior__(self, values): ++ self.update(values) ++ return self ++ + def isReservedKey(self, K): + return K.lower() in self._reserved + +@@ -363,9 +370,15 @@ def __getstate__(self): + } + + def __setstate__(self, state): +- self._key = state['key'] +- self._value = state['value'] +- self._coded_value = state['coded_value'] ++ key = state['key'] ++ value = state['value'] ++ coded_value = state['coded_value'] ++ if _has_control_character(key, value, coded_value): ++ raise CookieError("Control characters are not allowed in cookies " ++ f"{key!r} {value!r} {coded_value!r}") ++ self._key = key ++ self._value = value ++ self._coded_value = coded_value + + def output(self, attrs=None, header="Set-Cookie:"): + return "%s %s" % (header, self.OutputString(attrs)) +@@ -377,13 +390,16 @@ def __repr__(self): + + def js_output(self, attrs=None): + # Print javascript ++ output_string = self.OutputString(attrs) ++ if _has_control_character(output_string): ++ raise CookieError("Control characters are not allowed in cookies") + return """ + +- """ % (self.OutputString(attrs).replace('"', r'\"')) ++ """ % (output_string.replace('"', r'\"')) + + def OutputString(self, attrs=None): + # Build up our result +diff --git a/Lib/test/test_http_cookies.py b/Lib/test/test_http_cookies.py +index 2438c57ef4..f9a846f8fa 100644 +--- a/Lib/test/test_http_cookies.py ++++ b/Lib/test/test_http_cookies.py +@@ -527,6 +527,14 @@ def test_control_characters(self): + with self.assertRaises(cookies.CookieError): + morsel["path"] = c0 + ++ # .__setstate__() ++ with self.assertRaises(cookies.CookieError): ++ morsel.__setstate__({'key': c0, 'value': 'val', 'coded_value': 'coded'}) ++ with self.assertRaises(cookies.CookieError): ++ morsel.__setstate__({'key': 'key', 'value': c0, 'coded_value': 'coded'}) ++ with self.assertRaises(cookies.CookieError): ++ morsel.__setstate__({'key': 'key', 'value': 'val', 'coded_value': c0}) ++ + # .setdefault() + with self.assertRaises(cookies.CookieError): + morsel.setdefault("path", c0) +@@ -541,6 +549,18 @@ def test_control_characters(self): + with self.assertRaises(cookies.CookieError): + morsel.set("path", "val", c0) + ++ # .update() ++ with self.assertRaises(cookies.CookieError): ++ morsel.update({"path": c0}) ++ with self.assertRaises(cookies.CookieError): ++ morsel.update({c0: "val"}) ++ ++ # .__ior__() ++ with self.assertRaises(cookies.CookieError): ++ morsel |= {"path": c0} ++ with self.assertRaises(cookies.CookieError): ++ morsel |= {c0: "val"} ++ + def test_control_characters_output(self): + # Tests that even if the internals of Morsel are modified + # that a call to .output() has control character safeguards. +@@ -561,6 +581,24 @@ def test_control_characters_output(self): + with self.assertRaises(cookies.CookieError): + cookie.output() + ++ # Tests that .js_output() also has control character safeguards. ++ for c0 in support.control_characters_c0(): ++ morsel = cookies.Morsel() ++ morsel.set("key", "value", "coded-value") ++ morsel._key = c0 # Override private variable. ++ cookie = cookies.SimpleCookie() ++ cookie["cookie"] = morsel ++ with self.assertRaises(cookies.CookieError): ++ cookie.js_output() ++ ++ morsel = cookies.Morsel() ++ morsel.set("key", "value", "coded-value") ++ morsel._coded_value = c0 # Override private variable. ++ cookie = cookies.SimpleCookie() ++ cookie["cookie"] = morsel ++ with self.assertRaises(cookies.CookieError): ++ cookie.js_output() ++ + + def load_tests(loader, tests, pattern): + tests.addTest(doctest.DocTestSuite(cookies)) +diff --git a/Misc/NEWS.d/next/Security/2026-03-06-17-03-38.gh-issue-145599.kchwZV.rst b/Misc/NEWS.d/next/Security/2026-03-06-17-03-38.gh-issue-145599.kchwZV.rst +new file mode 100644 +index 0000000000..fc2e503779 +--- /dev/null ++++ b/Misc/NEWS.d/next/Security/2026-03-06-17-03-38.gh-issue-145599.kchwZV.rst +@@ -0,0 +1,4 @@ ++Reject control characters in :class:`http.cookies.Morsel` ++:meth:`~http.cookies.Morsel.update` and ++:meth:`~http.cookies.BaseCookie.js_output`. ++This addresses `CVE-2026-3644 `_. diff --git a/00485-cve-2026-4224.patch b/00485-cve-2026-4224.patch new file mode 100644 index 0000000..cb5a8b5 --- /dev/null +++ b/00485-cve-2026-4224.patch @@ -0,0 +1,98 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Stan Ulbrych +Date: Wed, 8 Apr 2026 11:27:39 +0100 +Subject: 00485: CVE-2026-4224 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Stack overflow parsing XML with deeply nested DTD content models + +Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com> +--- + Lib/test/test_pyexpat.py | 18 ++++++++++++++++++ + ...6-03-14-17-31-39.gh-issue-145986.ifSSr8.rst | 4 ++++ + Modules/pyexpat.c | 9 ++++++++- + 3 files changed, 30 insertions(+), 1 deletion(-) + create mode 100644 Misc/NEWS.d/next/Security/2026-03-14-17-31-39.gh-issue-145986.ifSSr8.rst + +diff --git a/Lib/test/test_pyexpat.py b/Lib/test/test_pyexpat.py +index 9aa2fcedad..8afce3ffe1 100644 +--- a/Lib/test/test_pyexpat.py ++++ b/Lib/test/test_pyexpat.py +@@ -675,6 +675,24 @@ def test_change_size_2(self): + parser.Parse(xml2, True) + self.assertEqual(self.n, 4) + ++class ElementDeclHandlerTest(unittest.TestCase): ++ def test_deeply_nested_content_model(self): ++ # This should raise a RecursionError and not crash. ++ # See https://github.com/python/cpython/issues/145986. ++ N = 500_000 ++ data = ( ++ b'\n]>\n\n' ++ ) ++ ++ parser = expat.ParserCreate() ++ parser.ElementDeclHandler = lambda _1, _2: None ++ with support.infinite_recursion(): ++ with self.assertRaises(RecursionError): ++ parser.Parse(data) ++ ++ + class MalformedInputTest(unittest.TestCase): + def test1(self): + xml = b"\0\r\n" +diff --git a/Misc/NEWS.d/next/Security/2026-03-14-17-31-39.gh-issue-145986.ifSSr8.rst b/Misc/NEWS.d/next/Security/2026-03-14-17-31-39.gh-issue-145986.ifSSr8.rst +new file mode 100644 +index 0000000000..cb9dbadb72 +--- /dev/null ++++ b/Misc/NEWS.d/next/Security/2026-03-14-17-31-39.gh-issue-145986.ifSSr8.rst +@@ -0,0 +1,4 @@ ++:mod:`xml.parsers.expat`: Fixed a crash caused by unbounded C recursion when ++converting deeply nested XML content models with ++:meth:`~xml.parsers.expat.xmlparser.ElementDeclHandler`. ++This addresses `CVE-2026-4224 `_. +diff --git a/Modules/pyexpat.c b/Modules/pyexpat.c +index 7b76ddfabd..13c4e8e0ad 100644 +--- a/Modules/pyexpat.c ++++ b/Modules/pyexpat.c +@@ -3,6 +3,7 @@ + #endif + + #include "Python.h" ++#include "pycore_ceval.h" // _Py_EnterRecursiveCall() + #include "pycore_runtime.h" // _Py_ID() + #include + +@@ -578,6 +579,10 @@ static PyObject * + conv_content_model(XML_Content * const model, + PyObject *(*conv_string)(const XML_Char *)) + { ++ if (_Py_EnterRecursiveCall(" in conv_content_model")) { ++ return NULL; ++ } ++ + PyObject *result = NULL; + PyObject *children = PyTuple_New(model->numchildren); + int i; +@@ -589,7 +594,7 @@ conv_content_model(XML_Content * const model, + conv_string); + if (child == NULL) { + Py_XDECREF(children); +- return NULL; ++ goto done; + } + PyTuple_SET_ITEM(children, i, child); + } +@@ -597,6 +602,8 @@ conv_content_model(XML_Content * const model, + model->type, model->quant, + conv_string,model->name, children); + } ++done: ++ _Py_LeaveRecursiveCall(); + return result; + } + diff --git a/python3.11.spec b/python3.11.spec index 4bd9ce7..a9b6bcd 100644 --- a/python3.11.spec +++ b/python3.11.spec @@ -17,7 +17,7 @@ URL: https://www.python.org/ #global prerel ... %global upstream_version %{general_version}%{?prerel} Version: %{general_version}%{?prerel:~%{prerel}} -Release: 3%{?dist} +Release: 4%{?dist} License: Python-2.0.1 @@ -373,6 +373,42 @@ Patch475: 00475-cve-2025-15367.patch # Reject leading dashes in webbrowser URLs (GH-143931) (GH-146364) Patch478: 00478-cve-2026-4519.patch +# 00479 # 6fe61dd71dec5b7c9de2b1994172981667d034a1 +# CVE-2026-1502 +# +# Reject CR/LF in HTTP tunnel request headers +Patch479: 00479-cve-2026-1502.patch + +# 00480 # 9f4b1483ecfbc8c08117133c239fba544fcb42e7 +# CVE-2026-4786 +# +# Fix webbrowser `%%action` substitution bypass of dash-prefix check +Patch480: 00480-cve-2026-4786.patch + +# 00482 # 2a21454e658935990766df8c3c48af9363e8422a +# CVE-2026-6100 +# +# Fix a possible UAF in {LZMA,BZ2,_Zlib}Decompressor +Patch482: 00482-cve-2026-6100.patch + +# 00483 # cdb097a23eac5a09fb063a0e91001f69ff324205 +# CVE-2026-2297 +# +# Logging Bypass in Legacy .pyc File Handling +Patch483: 00483-cve-2026-2297.patch + +# 00484 # cf0bd2f2cce15cb35558aa08de34e9d18a8089f7 +# CVE-2026-3644 +# +# Incomplete control character validation in http.cookies +Patch484: 00484-cve-2026-3644.patch + +# 00485 # 54d821ba2f5a03ccced037978fcdb0a7c4d6878f +# CVE-2026-4224 +# +# Stack overflow parsing XML with deeply nested DTD content models +Patch485: 00485-cve-2026-4224.patch + # (New patches go here ^^^) # # When adding new patches to "python" and "python3" in Fedora, EL, etc., @@ -1705,6 +1741,10 @@ CheckPython optimized # ====================================================== %changelog +* Fri Apr 17 2026 Charalampos Stratakis - 3.11.15-4 +- Security fixes for CVE-2026-1502, CVE-2026-4786, CVE-2026-6100, CVE-2026-2297, CVE 2026-3644, CVE-2026-4224 +Resolves: rhbz#2457941, rhbz#2458221, rhbz#2458013, rhbz#2444704, rhbz#2448188, rhbz#2448204 + * Sat Apr 11 2026 Miro Hrončok - 3.11.15-3 - Explicitly build with OpenSSL 3 From fc0070dafaf1808177871ad44712aa711cd6cd62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Thu, 2 Jul 2026 10:54:53 +0200 Subject: [PATCH 29/33] Fix ssl.SSLError: [ASN1: NOT_ENOUGH_DATA] not enough data with OpenSSL 3.5.7+ --- 00489-openssl-3.5.7.patch | 75 +++++++++++++++++++++++++++++++++++++++ python3.11.spec | 17 ++++++++- 2 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 00489-openssl-3.5.7.patch diff --git a/00489-openssl-3.5.7.patch b/00489-openssl-3.5.7.patch new file mode 100644 index 0000000..5ba5e8b --- /dev/null +++ b/00489-openssl-3.5.7.patch @@ -0,0 +1,75 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: David Benjamin +Date: Fri, 24 Mar 2023 09:04:30 -0400 +Subject: 00489: Use BIO_eof to detect EOF for SSL_FILETYPE_ASN1 + +In PEM, we need to parse until error and then suppress `PEM_R_NO_START_LINE`, because PEM allows arbitrary leading and trailing data. DER, however, does not. Parsing until error and suppressing `ASN1_R_HEADER_TOO_LONG` doesn't quite work because that error also covers some cases that should be rejected. + +Instead, check `BIO_eof` early and stop the loop that way. + +This fixes https://github.com/python/cpython/issues/151504 and adds compatibility with OpenSSL 3.5.7+ + +(cherry-picked from commit acfe02f3b05436658d92add6b168538b30f357f0) +--- + Lib/test/test_ssl.py | 2 ++ + .../2022-12-20-10-55-14.gh-issue-100372.utfP65.rst | 2 ++ + Modules/_ssl.c | 10 ++++++---- + 3 files changed, 10 insertions(+), 4 deletions(-) + create mode 100644 Misc/NEWS.d/next/Library/2022-12-20-10-55-14.gh-issue-100372.utfP65.rst + +diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py +index 921c41bd0d..61cde99753 100644 +--- a/Lib/test/test_ssl.py ++++ b/Lib/test/test_ssl.py +@@ -1559,6 +1559,8 @@ def test_load_verify_cadata(self): + "not enough data: cadata does not contain a certificate" + ): + ctx.load_verify_locations(cadata=b"broken") ++ with self.assertRaises(ssl.SSLError): ++ ctx.load_verify_locations(cadata=cacert_der + b"A") + + @unittest.skipIf(Py_DEBUG_WIN32, "Avoid mixing debug/release CRT on Windows") + def test_load_dh_params(self): +diff --git a/Misc/NEWS.d/next/Library/2022-12-20-10-55-14.gh-issue-100372.utfP65.rst b/Misc/NEWS.d/next/Library/2022-12-20-10-55-14.gh-issue-100372.utfP65.rst +new file mode 100644 +index 0000000000..ec37aff509 +--- /dev/null ++++ b/Misc/NEWS.d/next/Library/2022-12-20-10-55-14.gh-issue-100372.utfP65.rst +@@ -0,0 +1,2 @@ ++:meth:`ssl.SSLContext.load_verify_locations` no longer incorrectly accepts ++some cases of trailing data when parsing DER. +diff --git a/Modules/_ssl.c b/Modules/_ssl.c +index ee7b131920..174e5dfce5 100644 +--- a/Modules/_ssl.c ++++ b/Modules/_ssl.c +@@ -3966,7 +3966,7 @@ _add_ca_certs(PySSLContext *self, const void *data, Py_ssize_t len, + { + BIO *biobuf = NULL; + X509_STORE *store; +- int retval = -1, err, loaded = 0; ++ int retval = -1, err, loaded = 0, was_bio_eof = 0; + + assert(filetype == SSL_FILETYPE_ASN1 || filetype == SSL_FILETYPE_PEM); + +@@ -3994,6 +3994,10 @@ _add_ca_certs(PySSLContext *self, const void *data, Py_ssize_t len, + int r; + + if (filetype == SSL_FILETYPE_ASN1) { ++ if (BIO_eof(biobuf)) { ++ was_bio_eof = 1; ++ break; ++ } + cert = d2i_X509_bio(biobuf, NULL); + } else { + cert = PEM_read_bio_X509(biobuf, NULL, +@@ -4029,9 +4033,7 @@ _add_ca_certs(PySSLContext *self, const void *data, Py_ssize_t len, + } + _setSSLError(get_state_ctx(self), msg, 0, __FILE__, __LINE__); + retval = -1; +- } else if ((filetype == SSL_FILETYPE_ASN1) && +- (ERR_GET_LIB(err) == ERR_LIB_ASN1) && +- (ERR_GET_REASON(err) == ASN1_R_HEADER_TOO_LONG)) { ++ } else if ((filetype == SSL_FILETYPE_ASN1) && was_bio_eof) { + /* EOF ASN1 file, not an error */ + ERR_clear_error(); + retval = 0; diff --git a/python3.11.spec b/python3.11.spec index a9b6bcd..08ed8b2 100644 --- a/python3.11.spec +++ b/python3.11.spec @@ -17,7 +17,7 @@ URL: https://www.python.org/ #global prerel ... %global upstream_version %{general_version}%{?prerel} Version: %{general_version}%{?prerel:~%{prerel}} -Release: 4%{?dist} +Release: 5%{?dist} License: Python-2.0.1 @@ -409,6 +409,18 @@ Patch484: 00484-cve-2026-3644.patch # Stack overflow parsing XML with deeply nested DTD content models Patch485: 00485-cve-2026-4224.patch +# 00489 # 008af720a5f6f98ed3feb8ebdbf88ab9dea4db22 +# Use BIO_eof to detect EOF for SSL_FILETYPE_ASN1 +# +# In PEM, we need to parse until error and then suppress `PEM_R_NO_START_LINE`, because PEM allows arbitrary leading and trailing data. DER, however, does not. Parsing until error and suppressing `ASN1_R_HEADER_TOO_LONG` doesn't quite work because that error also covers some cases that should be rejected. +# +# Instead, check `BIO_eof` early and stop the loop that way. +# +# This fixes https://github.com/python/cpython/issues/151504 and adds compatibility with OpenSSL 3.5.7+ +# +# (cherry-picked from commit acfe02f3b05436658d92add6b168538b30f357f0) +Patch489: 00489-openssl-3.5.7.patch + # (New patches go here ^^^) # # When adding new patches to "python" and "python3" in Fedora, EL, etc., @@ -1741,6 +1753,9 @@ CheckPython optimized # ====================================================== %changelog +* Thu Jul 02 2026 Miro Hrončok - 3.11.15-5 +- Fix ssl.SSLError: [ASN1: NOT_ENOUGH_DATA] not enough data with OpenSSL 3.5.7+ + * Fri Apr 17 2026 Charalampos Stratakis - 3.11.15-4 - Security fixes for CVE-2026-1502, CVE-2026-4786, CVE-2026-6100, CVE-2026-2297, CVE 2026-3644, CVE-2026-4224 Resolves: rhbz#2457941, rhbz#2458221, rhbz#2458013, rhbz#2444704, rhbz#2448188, rhbz#2448204 From 55cc855c79d4a45421dca6aa52b434058fe22eb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lum=C3=ADr=20Balhar?= Date: Wed, 1 Jul 2026 10:55:21 +0000 Subject: [PATCH 30/33] Run a new test to monitor changes in required symbols Co-Authored-By: Claude Sonnet 4.6 (1M context) --- plan.fmf | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/plan.fmf b/plan.fmf index 028bf63..c4ea482 100644 --- a/plan.fmf +++ b/plan.fmf @@ -34,6 +34,9 @@ discover: - name: marshalparser path: /marshalparser test: "VERSION=${pybasever} SAMPLE=10 ./test_marshalparser_compatibility.sh" + - name: required_symbols + path: /required-symbols + test: "VERSION=${pybasever} ./check.sh" prepare: - name: Install dependencies @@ -51,8 +54,9 @@ prepare: - virtualenv # for virtualenv tests - glibc-all-langpacks # for locale tests - marshalparser # for testing compatibility (magic numbers) with marshalparser + - binutils # for nm (symbol inspection) - rpm # for debugging - - dnf # for upgrade + - dnf # for upgrade and downgrade - name: Update packages how: shell script: dnf upgrade -y From 79c55d4ad7b9948b5bf44f62e9f6a869680b40e6 Mon Sep 17 00:00:00 2001 From: Fedora Release Engineering Date: Thu, 16 Jul 2026 22:47:27 +0000 Subject: [PATCH 31/33] Rebuilt for https://fedoraproject.org/wiki/Fedora_45_Mass_Rebuild --- python3.11.spec | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/python3.11.spec b/python3.11.spec index 08ed8b2..f033534 100644 --- a/python3.11.spec +++ b/python3.11.spec @@ -17,7 +17,7 @@ URL: https://www.python.org/ #global prerel ... %global upstream_version %{general_version}%{?prerel} Version: %{general_version}%{?prerel:~%{prerel}} -Release: 5%{?dist} +Release: 6%{?dist} License: Python-2.0.1 @@ -1753,6 +1753,9 @@ CheckPython optimized # ====================================================== %changelog +* Thu Jul 16 2026 Fedora Release Engineering - 3.11.15-6 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_45_Mass_Rebuild + * Thu Jul 02 2026 Miro Hrončok - 3.11.15-5 - Fix ssl.SSLError: [ASN1: NOT_ENOUGH_DATA] not enough data with OpenSSL 3.5.7+ From dadebe1c22becf14fc722ccf2b3aa6bd6af16782 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Thu, 30 Jul 2026 17:24:31 +0200 Subject: [PATCH 32/33] Skip UDP Lite tests if it's not supported - Fixes FTBFS on Linux kernel 7.1 and newer --- ...udp-lite-tests-if-it-s-not-supported.patch | 64 +++++++++++++++++++ python3.11.spec | 13 +++- 2 files changed, 76 insertions(+), 1 deletion(-) create mode 100644 00491-gh-149776-skip-udp-lite-tests-if-it-s-not-supported.patch diff --git a/00491-gh-149776-skip-udp-lite-tests-if-it-s-not-supported.patch b/00491-gh-149776-skip-udp-lite-tests-if-it-s-not-supported.patch new file mode 100644 index 0000000..5dc9a0f --- /dev/null +++ b/00491-gh-149776-skip-udp-lite-tests-if-it-s-not-supported.patch @@ -0,0 +1,64 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Victor Stinner +Date: Wed, 13 May 2026 17:27:56 +0200 +Subject: 00491: gh-149776: Skip UDP Lite tests if it's not supported + +Fix test_socket on Linux kernel 7.1 and newer: skip UDP Lite tests if +it's not supported. + +(cherry picked from commit 3cfc249e11a132dc69624150843779aa96c72b2b) +(cherry picked from commit 49d08674d8dba50dc29539e3c7bce21d66066b06) +--- + Lib/test/test_socket.py | 22 ++++++++++++++++++- + ...-05-13-14-53-23.gh-issue-149776.orqgsn.rst | 2 ++ + 2 files changed, 23 insertions(+), 1 deletion(-) + create mode 100644 Misc/NEWS.d/next/Tests/2026-05-13-14-53-23.gh-issue-149776.orqgsn.rst + +diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py +index 5ea8c8e62c..c96185b2e5 100644 +--- a/Lib/test/test_socket.py ++++ b/Lib/test/test_socket.py +@@ -145,6 +145,26 @@ def _have_socket_bluetooth(): + return True + + ++def _have_udp_lite(): ++ if not hasattr(socket, "IPPROTO_UDPLITE"): ++ return False ++ # Older Android versions block UDPLITE with SELinux. ++ if support.is_android and platform.android_ver().api_level < 29: ++ return False ++ ++ try: ++ sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDPLITE) ++ except OSError as exc: ++ # Linux 7.1 removed UDP Lite support ++ if exc.errno == errno.EPROTONOSUPPORT: ++ return False ++ raise ++ sock.close() ++ ++ return True ++ ++ ++ + @contextlib.contextmanager + def socket_setdefaulttimeout(timeout): + old_timeout = socket.getdefaulttimeout() +@@ -169,7 +189,7 @@ def socket_setdefaulttimeout(timeout): + + HAVE_SOCKET_VSOCK = _have_socket_vsock() + +-HAVE_SOCKET_UDPLITE = hasattr(socket, "IPPROTO_UDPLITE") ++HAVE_SOCKET_UDPLITE = _have_udp_lite() + + HAVE_SOCKET_BLUETOOTH = _have_socket_bluetooth() + +diff --git a/Misc/NEWS.d/next/Tests/2026-05-13-14-53-23.gh-issue-149776.orqgsn.rst b/Misc/NEWS.d/next/Tests/2026-05-13-14-53-23.gh-issue-149776.orqgsn.rst +new file mode 100644 +index 0000000000..e86a9130ff +--- /dev/null ++++ b/Misc/NEWS.d/next/Tests/2026-05-13-14-53-23.gh-issue-149776.orqgsn.rst +@@ -0,0 +1,2 @@ ++Fix test_socket on Linux kernel 7.1 and newer: skip UDP Lite tests if it's ++not supported. Patch by Victor Stinner. diff --git a/python3.11.spec b/python3.11.spec index f033534..2faee17 100644 --- a/python3.11.spec +++ b/python3.11.spec @@ -17,7 +17,7 @@ URL: https://www.python.org/ #global prerel ... %global upstream_version %{general_version}%{?prerel} Version: %{general_version}%{?prerel:~%{prerel}} -Release: 6%{?dist} +Release: 7%{?dist} License: Python-2.0.1 @@ -421,6 +421,13 @@ Patch485: 00485-cve-2026-4224.patch # (cherry-picked from commit acfe02f3b05436658d92add6b168538b30f357f0) Patch489: 00489-openssl-3.5.7.patch +# 00491 # ac14737379922303720216b61803474c84f291ef +# gh-149776: Skip UDP Lite tests if it's not supported +# +# Fix test_socket on Linux kernel 7.1 and newer: skip UDP Lite tests if +# it's not supported. +Patch491: 00491-gh-149776-skip-udp-lite-tests-if-it-s-not-supported.patch + # (New patches go here ^^^) # # When adding new patches to "python" and "python3" in Fedora, EL, etc., @@ -1753,6 +1760,10 @@ CheckPython optimized # ====================================================== %changelog +* Thu Jul 30 2026 Miro Hrončok - 3.11.15-7 + - Skip UDP Lite tests if it's not supported + - Fixes FTBFS on Linux kernel 7.1 and newer + * Thu Jul 16 2026 Fedora Release Engineering - 3.11.15-6 - Rebuilt for https://fedoraproject.org/wiki/Fedora_45_Mass_Rebuild From 278eb3fa417bf138a1cb9c618c718b6b68fe139c Mon Sep 17 00:00:00 2001 From: Karolina Surma Date: Thu, 13 Aug 2026 12:06:07 +0200 Subject: [PATCH 33/33] Update to Python 3.11.16 --- ...d-cflags-for-dtrace-systemtap-builds.patch | 6 +- ..._seterror-handling-ssl_error_syscall.patch | 10 +- 00478-cve-2026-4519.patch | 121 --------------- 00479-cve-2026-1502.patch | 106 ------------- 00480-cve-2026-4786.patch | 63 -------- 00482-cve-2026-6100.patch | 48 ------ 00483-cve-2026-2297.patch | 33 ---- 00484-cve-2026-3644.patch | 146 ------------------ 00485-cve-2026-4224.patch | 98 ------------ 00489-openssl-3.5.7.patch | 75 --------- ...udp-lite-tests-if-it-s-not-supported.patch | 64 -------- ...-test_large_content_length_truncated.patch | 23 +++ python3.11.spec | 70 ++------- sources | 4 +- 14 files changed, 42 insertions(+), 825 deletions(-) delete mode 100644 00478-cve-2026-4519.patch delete mode 100644 00479-cve-2026-1502.patch delete mode 100644 00480-cve-2026-4786.patch delete mode 100644 00482-cve-2026-6100.patch delete mode 100644 00483-cve-2026-2297.patch delete mode 100644 00484-cve-2026-3644.patch delete mode 100644 00485-cve-2026-4224.patch delete mode 100644 00489-openssl-3.5.7.patch delete mode 100644 00491-gh-149776-skip-udp-lite-tests-if-it-s-not-supported.patch create mode 100644 00494-increase-the-timeout-of-test_large_content_length_truncated.patch diff --git a/00452-properly-apply-exported-cflags-for-dtrace-systemtap-builds.patch b/00452-properly-apply-exported-cflags-for-dtrace-systemtap-builds.patch index 1417bdb..3fea025 100644 --- a/00452-properly-apply-exported-cflags-for-dtrace-systemtap-builds.patch +++ b/00452-properly-apply-exported-cflags-for-dtrace-systemtap-builds.patch @@ -20,10 +20,10 @@ Co-authored-by: stratakis create mode 100644 Misc/NEWS.d/next/Build/2025-03-31-19-22-41.gh-issue-131865.PIJy7X.rst diff --git a/Makefile.pre.in b/Makefile.pre.in -index 81d4d50f82..0bd3447638 100644 +index ad29e1a0ca..79b07194bb 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in -@@ -1453,7 +1453,7 @@ Python/frozen.o: $(FROZEN_FILES_OUT) +@@ -1458,7 +1458,7 @@ Python/frozen.o: $(FROZEN_FILES_OUT) # an include guard, so we can't use a pipeline to transform its output. Include/pydtrace_probes.h: $(srcdir)/Include/pydtrace.d $(MKDIR_P) Include @@ -32,7 +32,7 @@ index 81d4d50f82..0bd3447638 100644 : sed in-place edit with POSIX-only tools sed 's/PYTHON_/PyDTrace_/' $@ > $@.tmp mv $@.tmp $@ -@@ -1463,7 +1463,7 @@ Python/import.o: $(srcdir)/Include/pydtrace.h +@@ -1468,7 +1468,7 @@ Python/import.o: $(srcdir)/Include/pydtrace.h Modules/gcmodule.o: $(srcdir)/Include/pydtrace.h Python/pydtrace.o: $(srcdir)/Include/pydtrace.d $(DTRACE_DEPS) diff --git a/00462-fix-pyssl_seterror-handling-ssl_error_syscall.patch b/00462-fix-pyssl_seterror-handling-ssl_error_syscall.patch index 0016e57..e9b2851 100644 --- a/00462-fix-pyssl_seterror-handling-ssl_error_syscall.patch +++ b/00462-fix-pyssl_seterror-handling-ssl_error_syscall.patch @@ -22,10 +22,10 @@ Co-authored-by: Petr Viktorin create mode 100644 Misc/NEWS.d/next/Library/2024-02-18-09-50-31.gh-issue-115627.HGchj0.rst diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py -index 0b169c37d5..921c41bd0d 100644 +index aa8ce81db6..61cde99753 100644 --- a/Lib/test/test_ssl.py +++ b/Lib/test/test_ssl.py -@@ -2633,16 +2633,18 @@ def run(self): +@@ -2635,16 +2635,18 @@ def run(self): self.write(msg.lower()) except OSError as e: # handles SSLError and socket errors @@ -53,7 +53,7 @@ index 0b169c37d5..921c41bd0d 100644 try: self.write(b"ERROR\n") except OSError: -@@ -3337,8 +3339,8 @@ def test_wrong_cert_tls13(self): +@@ -3339,8 +3341,8 @@ def test_wrong_cert_tls13(self): suppress_ragged_eofs=False) as s: s.connect((HOST, server.port)) with self.assertRaisesRegex( @@ -64,7 +64,7 @@ index 0b169c37d5..921c41bd0d 100644 ): # TLS 1.3 perform client cert exchange after handshake s.write(b'data') -@@ -4610,8 +4612,8 @@ def msg_cb(conn, direction, version, content_type, msg_type, data): +@@ -4612,8 +4614,8 @@ def msg_cb(conn, direction, version, content_type, msg_type, data): # test sometimes fails with EOF error. Test passes as long as # server aborts connection with an error. with self.assertRaisesRegex( @@ -84,7 +84,7 @@ index 0000000000..75d926ab59 +Fix the :mod:`ssl` module error handling of connection terminate by peer. +It now throws an OSError with the appropriate error code instead of an EOFError. diff --git a/Modules/_ssl.c b/Modules/_ssl.c -index 6275d94d64..ee7b131920 100644 +index 9c2e8c391d..174e5dfce5 100644 --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -576,7 +576,7 @@ PySSL_ChainExceptions(PySSLSocket *sslsock) { diff --git a/00478-cve-2026-4519.patch b/00478-cve-2026-4519.patch deleted file mode 100644 index eb9d2ef..0000000 --- a/00478-cve-2026-4519.patch +++ /dev/null @@ -1,121 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: tomcruiseqi -Date: Wed, 25 Mar 2026 02:23:28 +0800 -Subject: 00478: CVE-2026-4519 - -Reject leading dashes in webbrowser URLs (GH-143931) (GH-146364) - -(cherry picked from commit 82a24a4442312bdcfc4c799885e8b3e00990f02b) - -Co-authored-by: Seth Michael Larson ---- - Lib/test/test_webbrowser.py | 5 +++++ - Lib/webbrowser.py | 14 ++++++++++++++ - .../2026-01-16-12-04-49.gh-issue-143930.zYC5x3.rst | 1 + - 3 files changed, 20 insertions(+) - create mode 100644 Misc/NEWS.d/next/Security/2026-01-16-12-04-49.gh-issue-143930.zYC5x3.rst - -diff --git a/Lib/test/test_webbrowser.py b/Lib/test/test_webbrowser.py -index 9d608d63a0..0ac985f56c 100644 ---- a/Lib/test/test_webbrowser.py -+++ b/Lib/test/test_webbrowser.py -@@ -59,6 +59,11 @@ def test_open(self): - options=[], - arguments=[URL]) - -+ def test_reject_dash_prefixes(self): -+ browser = self.browser_class(name=CMD_NAME) -+ with self.assertRaises(ValueError): -+ browser.open(f"--key=val {URL}") -+ - - class BackgroundBrowserCommandTest(CommandTestMixin, unittest.TestCase): - -diff --git a/Lib/webbrowser.py b/Lib/webbrowser.py -index 5d72524c08..0fd0aeb3c1 100755 ---- a/Lib/webbrowser.py -+++ b/Lib/webbrowser.py -@@ -155,6 +155,12 @@ def open_new(self, url): - def open_new_tab(self, url): - return self.open(url, 2) - -+ @staticmethod -+ def _check_url(url): -+ """Ensures that the URL is safe to pass to subprocesses as a parameter""" -+ if url and url.lstrip().startswith("-"): -+ raise ValueError(f"Invalid URL: {url}") -+ - - class GenericBrowser(BaseBrowser): - """Class for all browsers started with a command -@@ -172,6 +178,7 @@ def __init__(self, name): - - def open(self, url, new=0, autoraise=True): - sys.audit("webbrowser.open", url) -+ self._check_url(url) - cmdline = [self.name] + [arg.replace("%s", url) - for arg in self.args] - try: -@@ -192,6 +199,7 @@ def open(self, url, new=0, autoraise=True): - cmdline = [self.name] + [arg.replace("%s", url) - for arg in self.args] - sys.audit("webbrowser.open", url) -+ self._check_url(url) - try: - if sys.platform[:3] == 'win': - p = subprocess.Popen(cmdline) -@@ -257,6 +265,7 @@ def _invoke(self, args, remote, autoraise, url=None): - - def open(self, url, new=0, autoraise=True): - sys.audit("webbrowser.open", url) -+ self._check_url(url) - if new == 0: - action = self.remote_action - elif new == 1: -@@ -358,6 +367,7 @@ class Konqueror(BaseBrowser): - - def open(self, url, new=0, autoraise=True): - sys.audit("webbrowser.open", url) -+ self._check_url(url) - # XXX Currently I know no way to prevent KFM from opening a new win. - if new == 2: - action = "newTab" -@@ -442,6 +452,7 @@ def _remote(self, action): - - def open(self, url, new=0, autoraise=True): - sys.audit("webbrowser.open", url) -+ self._check_url(url) - if new: - ok = self._remote("LOADNEW " + url) - else: -@@ -605,6 +616,7 @@ def register_standard_browsers(): - class WindowsDefault(BaseBrowser): - def open(self, url, new=0, autoraise=True): - sys.audit("webbrowser.open", url) -+ self._check_url(url) - try: - os.startfile(url) - except OSError: -@@ -637,6 +649,7 @@ def __init__(self, name): - - def open(self, url, new=0, autoraise=True): - sys.audit("webbrowser.open", url) -+ self._check_url(url) - assert "'" not in url - # hack for local urls - if not ':' in url: -@@ -689,6 +702,7 @@ def _name(self, val): - - def open(self, url, new=0, autoraise=True): - sys.audit("webbrowser.open", url) -+ self._check_url(url) - if self.name == 'default': - script = 'open location "%s"' % url.replace('"', '%22') # opens in default browser - else: -diff --git a/Misc/NEWS.d/next/Security/2026-01-16-12-04-49.gh-issue-143930.zYC5x3.rst b/Misc/NEWS.d/next/Security/2026-01-16-12-04-49.gh-issue-143930.zYC5x3.rst -new file mode 100644 -index 0000000000..0f27eae99a ---- /dev/null -+++ b/Misc/NEWS.d/next/Security/2026-01-16-12-04-49.gh-issue-143930.zYC5x3.rst -@@ -0,0 +1 @@ -+Reject leading dashes in URLs passed to :func:`webbrowser.open` diff --git a/00479-cve-2026-1502.patch b/00479-cve-2026-1502.patch deleted file mode 100644 index b6ce808..0000000 --- a/00479-cve-2026-1502.patch +++ /dev/null @@ -1,106 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Seth Larson -Date: Fri, 10 Apr 2026 10:21:42 -0500 -Subject: 00479: CVE-2026-1502 - -Reject CR/LF in HTTP tunnel request headers - -Co-authored-by: Illia Volochii ---- - Lib/http/client.py | 11 ++++- - Lib/test/test_httplib.py | 45 +++++++++++++++++++ - ...-03-20-09-29-42.gh-issue-146211.PQVbs7.rst | 2 + - 3 files changed, 57 insertions(+), 1 deletion(-) - create mode 100644 Misc/NEWS.d/next/Security/2026-03-20-09-29-42.gh-issue-146211.PQVbs7.rst - -diff --git a/Lib/http/client.py b/Lib/http/client.py -index c977612732..8cf783ab30 100644 ---- a/Lib/http/client.py -+++ b/Lib/http/client.py -@@ -941,12 +941,21 @@ def _wrap_ipv6(self, ip): - return ip - - def _tunnel(self): -+ if _contains_disallowed_url_pchar_re.search(self._tunnel_host): -+ raise ValueError('Tunnel host can\'t contain control characters %r' -+ % (self._tunnel_host,)) - connect = b"CONNECT %s:%d HTTP/1.0\r\n" % ( - self._wrap_ipv6(self._tunnel_host.encode("ascii")), - self._tunnel_port) - headers = [connect] - for header, value in self._tunnel_headers.items(): -- headers.append(f"{header}: {value}\r\n".encode("latin-1")) -+ header_bytes = header.encode("latin-1") -+ value_bytes = value.encode("latin-1") -+ if not _is_legal_header_name(header_bytes): -+ raise ValueError('Invalid header name %r' % (header_bytes,)) -+ if _is_illegal_header_value(value_bytes): -+ raise ValueError('Invalid header value %r' % (value_bytes,)) -+ headers.append(b"%s: %s\r\n" % (header_bytes, value_bytes)) - headers.append(b"\r\n") - # Making a single send() call instead of one per line encourages - # the host OS to use a more optimal packet size instead of -diff --git a/Lib/test/test_httplib.py b/Lib/test/test_httplib.py -index 55363413b3..a4ab909ca9 100644 ---- a/Lib/test/test_httplib.py -+++ b/Lib/test/test_httplib.py -@@ -371,6 +371,51 @@ def test_invalid_headers(self): - with self.assertRaisesRegex(ValueError, 'Invalid header'): - conn.putheader(name, value) - -+ def test_invalid_tunnel_headers(self): -+ cases = ( -+ ('Invalid\r\nName', 'ValidValue'), -+ ('Invalid\rName', 'ValidValue'), -+ ('Invalid\nName', 'ValidValue'), -+ ('\r\nInvalidName', 'ValidValue'), -+ ('\rInvalidName', 'ValidValue'), -+ ('\nInvalidName', 'ValidValue'), -+ (' InvalidName', 'ValidValue'), -+ ('\tInvalidName', 'ValidValue'), -+ ('Invalid:Name', 'ValidValue'), -+ (':InvalidName', 'ValidValue'), -+ ('ValidName', 'Invalid\r\nValue'), -+ ('ValidName', 'Invalid\rValue'), -+ ('ValidName', 'Invalid\nValue'), -+ ('ValidName', 'InvalidValue\r\n'), -+ ('ValidName', 'InvalidValue\r'), -+ ('ValidName', 'InvalidValue\n'), -+ ) -+ for name, value in cases: -+ with self.subTest((name, value)): -+ conn = client.HTTPConnection('example.com') -+ conn.set_tunnel('tunnel', headers={ -+ name: value -+ }) -+ conn.sock = FakeSocket('') -+ with self.assertRaisesRegex(ValueError, 'Invalid header'): -+ conn._tunnel() # Called in .connect() -+ -+ def test_invalid_tunnel_host(self): -+ cases = ( -+ 'invalid\r.host', -+ '\ninvalid.host', -+ 'invalid.host\r\n', -+ 'invalid.host\x00', -+ 'invalid host', -+ ) -+ for tunnel_host in cases: -+ with self.subTest(tunnel_host): -+ conn = client.HTTPConnection('example.com') -+ conn.set_tunnel(tunnel_host) -+ conn.sock = FakeSocket('') -+ with self.assertRaisesRegex(ValueError, 'Tunnel host can\'t contain control characters'): -+ conn._tunnel() # Called in .connect() -+ - def test_headers_debuglevel(self): - body = ( - b'HTTP/1.1 200 OK\r\n' -diff --git a/Misc/NEWS.d/next/Security/2026-03-20-09-29-42.gh-issue-146211.PQVbs7.rst b/Misc/NEWS.d/next/Security/2026-03-20-09-29-42.gh-issue-146211.PQVbs7.rst -new file mode 100644 -index 0000000000..4993633b8e ---- /dev/null -+++ b/Misc/NEWS.d/next/Security/2026-03-20-09-29-42.gh-issue-146211.PQVbs7.rst -@@ -0,0 +1,2 @@ -+Reject CR/LF characters in tunnel request headers for the -+HTTPConnection.set_tunnel() method. diff --git a/00480-cve-2026-4786.patch b/00480-cve-2026-4786.patch deleted file mode 100644 index a0fcb66..0000000 --- a/00480-cve-2026-4786.patch +++ /dev/null @@ -1,63 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Stan Ulbrych -Date: Mon, 13 Apr 2026 22:41:51 +0100 -Subject: 00480: CVE-2026-4786 - -Fix webbrowser `%action` substitution bypass of dash-prefix check ---- - Lib/test/test_webbrowser.py | 8 ++++++++ - Lib/webbrowser.py | 5 +++-- - .../2026-03-31-09-15-51.gh-issue-148169.EZJzz2.rst | 2 ++ - 3 files changed, 13 insertions(+), 2 deletions(-) - create mode 100644 Misc/NEWS.d/next/Security/2026-03-31-09-15-51.gh-issue-148169.EZJzz2.rst - -diff --git a/Lib/test/test_webbrowser.py b/Lib/test/test_webbrowser.py -index 0ac985f56c..d629f889db 100644 ---- a/Lib/test/test_webbrowser.py -+++ b/Lib/test/test_webbrowser.py -@@ -99,6 +99,14 @@ def test_open_new_tab(self): - options=[], - arguments=[URL]) - -+ def test_reject_action_dash_prefixes(self): -+ browser = self.browser_class(name=CMD_NAME) -+ with self.assertRaises(ValueError): -+ browser.open('%action--incognito') -+ # new=1: action is "--new-window", so "%action" itself expands to -+ # a dash-prefixed flag even with no dash in the original URL. -+ with self.assertRaises(ValueError): -+ browser.open('%action', new=1) - - class MozillaCommandTest(CommandTestMixin, unittest.TestCase): - -diff --git a/Lib/webbrowser.py b/Lib/webbrowser.py -index 0fd0aeb3c1..026bdfbd7b 100755 ---- a/Lib/webbrowser.py -+++ b/Lib/webbrowser.py -@@ -265,7 +265,6 @@ def _invoke(self, args, remote, autoraise, url=None): - - def open(self, url, new=0, autoraise=True): - sys.audit("webbrowser.open", url) -- self._check_url(url) - if new == 0: - action = self.remote_action - elif new == 1: -@@ -279,7 +278,9 @@ def open(self, url, new=0, autoraise=True): - raise Error("Bad 'new' parameter to open(); " + - "expected 0, 1, or 2, got %s" % new) - -- args = [arg.replace("%s", url).replace("%action", action) -+ self._check_url(url.replace("%action", action)) -+ -+ args = [arg.replace("%action", action).replace("%s", url) - for arg in self.remote_args] - args = [arg for arg in args if arg] - success = self._invoke(args, True, autoraise, url) -diff --git a/Misc/NEWS.d/next/Security/2026-03-31-09-15-51.gh-issue-148169.EZJzz2.rst b/Misc/NEWS.d/next/Security/2026-03-31-09-15-51.gh-issue-148169.EZJzz2.rst -new file mode 100644 -index 0000000000..45cdeebe1b ---- /dev/null -+++ b/Misc/NEWS.d/next/Security/2026-03-31-09-15-51.gh-issue-148169.EZJzz2.rst -@@ -0,0 +1,2 @@ -+A bypass in :mod:`webbrowser` allowed URLs prefixed with ``%action`` to pass -+the dash-prefix safety check. diff --git a/00482-cve-2026-6100.patch b/00482-cve-2026-6100.patch deleted file mode 100644 index ad4c39b..0000000 --- a/00482-cve-2026-6100.patch +++ /dev/null @@ -1,48 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Stan Ulbrych -Date: Mon, 13 Apr 2026 22:42:36 +0100 -Subject: 00482: CVE-2026-6100 - -Fix a possible UAF in {LZMA,BZ2,_Zlib}Decompressor ---- - .../Security/2026-04-10-16-28-21.gh-issue-148395.kfzm0G.rst | 5 +++++ - Modules/_bz2module.c | 1 + - Modules/_lzmamodule.c | 1 + - 3 files changed, 7 insertions(+) - create mode 100644 Misc/NEWS.d/next/Security/2026-04-10-16-28-21.gh-issue-148395.kfzm0G.rst - -diff --git a/Misc/NEWS.d/next/Security/2026-04-10-16-28-21.gh-issue-148395.kfzm0G.rst b/Misc/NEWS.d/next/Security/2026-04-10-16-28-21.gh-issue-148395.kfzm0G.rst -new file mode 100644 -index 0000000000..349d1cf3ca ---- /dev/null -+++ b/Misc/NEWS.d/next/Security/2026-04-10-16-28-21.gh-issue-148395.kfzm0G.rst -@@ -0,0 +1,5 @@ -+Fix a dangling input pointer in :class:`lzma.LZMADecompressor`, -+and :class:`bz2.BZ2Decompressor` -+when memory allocation fails with :exc:`MemoryError`, which could let a -+subsequent :meth:`!decompress` call read or write through a stale pointer to -+the already-released caller buffer. -diff --git a/Modules/_bz2module.c b/Modules/_bz2module.c -index 798e9efc62..b08ac5e44e 100644 ---- a/Modules/_bz2module.c -+++ b/Modules/_bz2module.c -@@ -595,6 +595,7 @@ decompress(BZ2Decompressor *d, char *data, size_t len, Py_ssize_t max_length) - return result; - - error: -+ bzs->next_in = NULL; - Py_XDECREF(result); - return NULL; - } -diff --git a/Modules/_lzmamodule.c b/Modules/_lzmamodule.c -index 97453a2808..51106a6a07 100644 ---- a/Modules/_lzmamodule.c -+++ b/Modules/_lzmamodule.c -@@ -1105,6 +1105,7 @@ decompress(Decompressor *d, uint8_t *data, size_t len, Py_ssize_t max_length) - return result; - - error: -+ lzs->next_in = NULL; - Py_XDECREF(result); - return NULL; - } diff --git a/00483-cve-2026-2297.patch b/00483-cve-2026-2297.patch deleted file mode 100644 index b71b19f..0000000 --- a/00483-cve-2026-2297.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Steve Dower -Date: Wed, 4 Mar 2026 19:55:52 +0000 -Subject: 00483: CVE-2026-2297 - -Logging Bypass in Legacy .pyc File Handling ---- - Lib/importlib/_bootstrap_external.py | 2 +- - .../Security/2026-03-04-18-59-17.gh-issue-145506.6hwvEh.rst | 2 ++ - 2 files changed, 3 insertions(+), 1 deletion(-) - create mode 100644 Misc/NEWS.d/next/Security/2026-03-04-18-59-17.gh-issue-145506.6hwvEh.rst - -diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py -index e53f6acf38..588da3c7ad 100644 ---- a/Lib/importlib/_bootstrap_external.py -+++ b/Lib/importlib/_bootstrap_external.py -@@ -1126,7 +1126,7 @@ def get_filename(self, fullname): - - def get_data(self, path): - """Return the data from path as raw bytes.""" -- if isinstance(self, (SourceLoader, ExtensionFileLoader)): -+ if isinstance(self, (SourceLoader, SourcelessFileLoader, ExtensionFileLoader)): - with _io.open_code(str(path)) as file: - return file.read() - else: -diff --git a/Misc/NEWS.d/next/Security/2026-03-04-18-59-17.gh-issue-145506.6hwvEh.rst b/Misc/NEWS.d/next/Security/2026-03-04-18-59-17.gh-issue-145506.6hwvEh.rst -new file mode 100644 -index 0000000000..edeb9e640c ---- /dev/null -+++ b/Misc/NEWS.d/next/Security/2026-03-04-18-59-17.gh-issue-145506.6hwvEh.rst -@@ -0,0 +1,2 @@ -+Fixes CVE-2026-2297 by ensuring that ``SourcelessFileLoader`` uses -+:func:`io.open_code` when opening ``.pyc`` files. diff --git a/00484-cve-2026-3644.patch b/00484-cve-2026-3644.patch deleted file mode 100644 index b01be87..0000000 --- a/00484-cve-2026-3644.patch +++ /dev/null @@ -1,146 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Stan Ulbrych <89152624+StanFromIreland@users.noreply.github.com> -Date: Mon, 16 Mar 2026 13:43:43 +0000 -Subject: 00484: CVE-2026-3644 - -Incomplete control character validation in http.cookies - -Co-authored-by: Victor Stinner ---- - Lib/http/cookies.py | 24 ++++++++++-- - Lib/test/test_http_cookies.py | 38 +++++++++++++++++++ - ...-03-06-17-03-38.gh-issue-145599.kchwZV.rst | 4 ++ - 3 files changed, 62 insertions(+), 4 deletions(-) - create mode 100644 Misc/NEWS.d/next/Security/2026-03-06-17-03-38.gh-issue-145599.kchwZV.rst - -diff --git a/Lib/http/cookies.py b/Lib/http/cookies.py -index 5cfa7a8072..6b36ffa9f8 100644 ---- a/Lib/http/cookies.py -+++ b/Lib/http/cookies.py -@@ -335,9 +335,16 @@ def update(self, values): - key = key.lower() - if key not in self._reserved: - raise CookieError("Invalid attribute %r" % (key,)) -+ if _has_control_character(key, val): -+ raise CookieError("Control characters are not allowed in " -+ f"cookies {key!r} {val!r}") - data[key] = val - dict.update(self, data) - -+ def __ior__(self, values): -+ self.update(values) -+ return self -+ - def isReservedKey(self, K): - return K.lower() in self._reserved - -@@ -363,9 +370,15 @@ def __getstate__(self): - } - - def __setstate__(self, state): -- self._key = state['key'] -- self._value = state['value'] -- self._coded_value = state['coded_value'] -+ key = state['key'] -+ value = state['value'] -+ coded_value = state['coded_value'] -+ if _has_control_character(key, value, coded_value): -+ raise CookieError("Control characters are not allowed in cookies " -+ f"{key!r} {value!r} {coded_value!r}") -+ self._key = key -+ self._value = value -+ self._coded_value = coded_value - - def output(self, attrs=None, header="Set-Cookie:"): - return "%s %s" % (header, self.OutputString(attrs)) -@@ -377,13 +390,16 @@ def __repr__(self): - - def js_output(self, attrs=None): - # Print javascript -+ output_string = self.OutputString(attrs) -+ if _has_control_character(output_string): -+ raise CookieError("Control characters are not allowed in cookies") - return """ - -- """ % (self.OutputString(attrs).replace('"', r'\"')) -+ """ % (output_string.replace('"', r'\"')) - - def OutputString(self, attrs=None): - # Build up our result -diff --git a/Lib/test/test_http_cookies.py b/Lib/test/test_http_cookies.py -index 2438c57ef4..f9a846f8fa 100644 ---- a/Lib/test/test_http_cookies.py -+++ b/Lib/test/test_http_cookies.py -@@ -527,6 +527,14 @@ def test_control_characters(self): - with self.assertRaises(cookies.CookieError): - morsel["path"] = c0 - -+ # .__setstate__() -+ with self.assertRaises(cookies.CookieError): -+ morsel.__setstate__({'key': c0, 'value': 'val', 'coded_value': 'coded'}) -+ with self.assertRaises(cookies.CookieError): -+ morsel.__setstate__({'key': 'key', 'value': c0, 'coded_value': 'coded'}) -+ with self.assertRaises(cookies.CookieError): -+ morsel.__setstate__({'key': 'key', 'value': 'val', 'coded_value': c0}) -+ - # .setdefault() - with self.assertRaises(cookies.CookieError): - morsel.setdefault("path", c0) -@@ -541,6 +549,18 @@ def test_control_characters(self): - with self.assertRaises(cookies.CookieError): - morsel.set("path", "val", c0) - -+ # .update() -+ with self.assertRaises(cookies.CookieError): -+ morsel.update({"path": c0}) -+ with self.assertRaises(cookies.CookieError): -+ morsel.update({c0: "val"}) -+ -+ # .__ior__() -+ with self.assertRaises(cookies.CookieError): -+ morsel |= {"path": c0} -+ with self.assertRaises(cookies.CookieError): -+ morsel |= {c0: "val"} -+ - def test_control_characters_output(self): - # Tests that even if the internals of Morsel are modified - # that a call to .output() has control character safeguards. -@@ -561,6 +581,24 @@ def test_control_characters_output(self): - with self.assertRaises(cookies.CookieError): - cookie.output() - -+ # Tests that .js_output() also has control character safeguards. -+ for c0 in support.control_characters_c0(): -+ morsel = cookies.Morsel() -+ morsel.set("key", "value", "coded-value") -+ morsel._key = c0 # Override private variable. -+ cookie = cookies.SimpleCookie() -+ cookie["cookie"] = morsel -+ with self.assertRaises(cookies.CookieError): -+ cookie.js_output() -+ -+ morsel = cookies.Morsel() -+ morsel.set("key", "value", "coded-value") -+ morsel._coded_value = c0 # Override private variable. -+ cookie = cookies.SimpleCookie() -+ cookie["cookie"] = morsel -+ with self.assertRaises(cookies.CookieError): -+ cookie.js_output() -+ - - def load_tests(loader, tests, pattern): - tests.addTest(doctest.DocTestSuite(cookies)) -diff --git a/Misc/NEWS.d/next/Security/2026-03-06-17-03-38.gh-issue-145599.kchwZV.rst b/Misc/NEWS.d/next/Security/2026-03-06-17-03-38.gh-issue-145599.kchwZV.rst -new file mode 100644 -index 0000000000..fc2e503779 ---- /dev/null -+++ b/Misc/NEWS.d/next/Security/2026-03-06-17-03-38.gh-issue-145599.kchwZV.rst -@@ -0,0 +1,4 @@ -+Reject control characters in :class:`http.cookies.Morsel` -+:meth:`~http.cookies.Morsel.update` and -+:meth:`~http.cookies.BaseCookie.js_output`. -+This addresses `CVE-2026-3644 `_. diff --git a/00485-cve-2026-4224.patch b/00485-cve-2026-4224.patch deleted file mode 100644 index cb5a8b5..0000000 --- a/00485-cve-2026-4224.patch +++ /dev/null @@ -1,98 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Stan Ulbrych -Date: Wed, 8 Apr 2026 11:27:39 +0100 -Subject: 00485: CVE-2026-4224 -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Stack overflow parsing XML with deeply nested DTD content models - -Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com> ---- - Lib/test/test_pyexpat.py | 18 ++++++++++++++++++ - ...6-03-14-17-31-39.gh-issue-145986.ifSSr8.rst | 4 ++++ - Modules/pyexpat.c | 9 ++++++++- - 3 files changed, 30 insertions(+), 1 deletion(-) - create mode 100644 Misc/NEWS.d/next/Security/2026-03-14-17-31-39.gh-issue-145986.ifSSr8.rst - -diff --git a/Lib/test/test_pyexpat.py b/Lib/test/test_pyexpat.py -index 9aa2fcedad..8afce3ffe1 100644 ---- a/Lib/test/test_pyexpat.py -+++ b/Lib/test/test_pyexpat.py -@@ -675,6 +675,24 @@ def test_change_size_2(self): - parser.Parse(xml2, True) - self.assertEqual(self.n, 4) - -+class ElementDeclHandlerTest(unittest.TestCase): -+ def test_deeply_nested_content_model(self): -+ # This should raise a RecursionError and not crash. -+ # See https://github.com/python/cpython/issues/145986. -+ N = 500_000 -+ data = ( -+ b'\n]>\n\n' -+ ) -+ -+ parser = expat.ParserCreate() -+ parser.ElementDeclHandler = lambda _1, _2: None -+ with support.infinite_recursion(): -+ with self.assertRaises(RecursionError): -+ parser.Parse(data) -+ -+ - class MalformedInputTest(unittest.TestCase): - def test1(self): - xml = b"\0\r\n" -diff --git a/Misc/NEWS.d/next/Security/2026-03-14-17-31-39.gh-issue-145986.ifSSr8.rst b/Misc/NEWS.d/next/Security/2026-03-14-17-31-39.gh-issue-145986.ifSSr8.rst -new file mode 100644 -index 0000000000..cb9dbadb72 ---- /dev/null -+++ b/Misc/NEWS.d/next/Security/2026-03-14-17-31-39.gh-issue-145986.ifSSr8.rst -@@ -0,0 +1,4 @@ -+:mod:`xml.parsers.expat`: Fixed a crash caused by unbounded C recursion when -+converting deeply nested XML content models with -+:meth:`~xml.parsers.expat.xmlparser.ElementDeclHandler`. -+This addresses `CVE-2026-4224 `_. -diff --git a/Modules/pyexpat.c b/Modules/pyexpat.c -index 7b76ddfabd..13c4e8e0ad 100644 ---- a/Modules/pyexpat.c -+++ b/Modules/pyexpat.c -@@ -3,6 +3,7 @@ - #endif - - #include "Python.h" -+#include "pycore_ceval.h" // _Py_EnterRecursiveCall() - #include "pycore_runtime.h" // _Py_ID() - #include - -@@ -578,6 +579,10 @@ static PyObject * - conv_content_model(XML_Content * const model, - PyObject *(*conv_string)(const XML_Char *)) - { -+ if (_Py_EnterRecursiveCall(" in conv_content_model")) { -+ return NULL; -+ } -+ - PyObject *result = NULL; - PyObject *children = PyTuple_New(model->numchildren); - int i; -@@ -589,7 +594,7 @@ conv_content_model(XML_Content * const model, - conv_string); - if (child == NULL) { - Py_XDECREF(children); -- return NULL; -+ goto done; - } - PyTuple_SET_ITEM(children, i, child); - } -@@ -597,6 +602,8 @@ conv_content_model(XML_Content * const model, - model->type, model->quant, - conv_string,model->name, children); - } -+done: -+ _Py_LeaveRecursiveCall(); - return result; - } - diff --git a/00489-openssl-3.5.7.patch b/00489-openssl-3.5.7.patch deleted file mode 100644 index 5ba5e8b..0000000 --- a/00489-openssl-3.5.7.patch +++ /dev/null @@ -1,75 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: David Benjamin -Date: Fri, 24 Mar 2023 09:04:30 -0400 -Subject: 00489: Use BIO_eof to detect EOF for SSL_FILETYPE_ASN1 - -In PEM, we need to parse until error and then suppress `PEM_R_NO_START_LINE`, because PEM allows arbitrary leading and trailing data. DER, however, does not. Parsing until error and suppressing `ASN1_R_HEADER_TOO_LONG` doesn't quite work because that error also covers some cases that should be rejected. - -Instead, check `BIO_eof` early and stop the loop that way. - -This fixes https://github.com/python/cpython/issues/151504 and adds compatibility with OpenSSL 3.5.7+ - -(cherry-picked from commit acfe02f3b05436658d92add6b168538b30f357f0) ---- - Lib/test/test_ssl.py | 2 ++ - .../2022-12-20-10-55-14.gh-issue-100372.utfP65.rst | 2 ++ - Modules/_ssl.c | 10 ++++++---- - 3 files changed, 10 insertions(+), 4 deletions(-) - create mode 100644 Misc/NEWS.d/next/Library/2022-12-20-10-55-14.gh-issue-100372.utfP65.rst - -diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py -index 921c41bd0d..61cde99753 100644 ---- a/Lib/test/test_ssl.py -+++ b/Lib/test/test_ssl.py -@@ -1559,6 +1559,8 @@ def test_load_verify_cadata(self): - "not enough data: cadata does not contain a certificate" - ): - ctx.load_verify_locations(cadata=b"broken") -+ with self.assertRaises(ssl.SSLError): -+ ctx.load_verify_locations(cadata=cacert_der + b"A") - - @unittest.skipIf(Py_DEBUG_WIN32, "Avoid mixing debug/release CRT on Windows") - def test_load_dh_params(self): -diff --git a/Misc/NEWS.d/next/Library/2022-12-20-10-55-14.gh-issue-100372.utfP65.rst b/Misc/NEWS.d/next/Library/2022-12-20-10-55-14.gh-issue-100372.utfP65.rst -new file mode 100644 -index 0000000000..ec37aff509 ---- /dev/null -+++ b/Misc/NEWS.d/next/Library/2022-12-20-10-55-14.gh-issue-100372.utfP65.rst -@@ -0,0 +1,2 @@ -+:meth:`ssl.SSLContext.load_verify_locations` no longer incorrectly accepts -+some cases of trailing data when parsing DER. -diff --git a/Modules/_ssl.c b/Modules/_ssl.c -index ee7b131920..174e5dfce5 100644 ---- a/Modules/_ssl.c -+++ b/Modules/_ssl.c -@@ -3966,7 +3966,7 @@ _add_ca_certs(PySSLContext *self, const void *data, Py_ssize_t len, - { - BIO *biobuf = NULL; - X509_STORE *store; -- int retval = -1, err, loaded = 0; -+ int retval = -1, err, loaded = 0, was_bio_eof = 0; - - assert(filetype == SSL_FILETYPE_ASN1 || filetype == SSL_FILETYPE_PEM); - -@@ -3994,6 +3994,10 @@ _add_ca_certs(PySSLContext *self, const void *data, Py_ssize_t len, - int r; - - if (filetype == SSL_FILETYPE_ASN1) { -+ if (BIO_eof(biobuf)) { -+ was_bio_eof = 1; -+ break; -+ } - cert = d2i_X509_bio(biobuf, NULL); - } else { - cert = PEM_read_bio_X509(biobuf, NULL, -@@ -4029,9 +4033,7 @@ _add_ca_certs(PySSLContext *self, const void *data, Py_ssize_t len, - } - _setSSLError(get_state_ctx(self), msg, 0, __FILE__, __LINE__); - retval = -1; -- } else if ((filetype == SSL_FILETYPE_ASN1) && -- (ERR_GET_LIB(err) == ERR_LIB_ASN1) && -- (ERR_GET_REASON(err) == ASN1_R_HEADER_TOO_LONG)) { -+ } else if ((filetype == SSL_FILETYPE_ASN1) && was_bio_eof) { - /* EOF ASN1 file, not an error */ - ERR_clear_error(); - retval = 0; diff --git a/00491-gh-149776-skip-udp-lite-tests-if-it-s-not-supported.patch b/00491-gh-149776-skip-udp-lite-tests-if-it-s-not-supported.patch deleted file mode 100644 index 5dc9a0f..0000000 --- a/00491-gh-149776-skip-udp-lite-tests-if-it-s-not-supported.patch +++ /dev/null @@ -1,64 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Victor Stinner -Date: Wed, 13 May 2026 17:27:56 +0200 -Subject: 00491: gh-149776: Skip UDP Lite tests if it's not supported - -Fix test_socket on Linux kernel 7.1 and newer: skip UDP Lite tests if -it's not supported. - -(cherry picked from commit 3cfc249e11a132dc69624150843779aa96c72b2b) -(cherry picked from commit 49d08674d8dba50dc29539e3c7bce21d66066b06) ---- - Lib/test/test_socket.py | 22 ++++++++++++++++++- - ...-05-13-14-53-23.gh-issue-149776.orqgsn.rst | 2 ++ - 2 files changed, 23 insertions(+), 1 deletion(-) - create mode 100644 Misc/NEWS.d/next/Tests/2026-05-13-14-53-23.gh-issue-149776.orqgsn.rst - -diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py -index 5ea8c8e62c..c96185b2e5 100644 ---- a/Lib/test/test_socket.py -+++ b/Lib/test/test_socket.py -@@ -145,6 +145,26 @@ def _have_socket_bluetooth(): - return True - - -+def _have_udp_lite(): -+ if not hasattr(socket, "IPPROTO_UDPLITE"): -+ return False -+ # Older Android versions block UDPLITE with SELinux. -+ if support.is_android and platform.android_ver().api_level < 29: -+ return False -+ -+ try: -+ sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDPLITE) -+ except OSError as exc: -+ # Linux 7.1 removed UDP Lite support -+ if exc.errno == errno.EPROTONOSUPPORT: -+ return False -+ raise -+ sock.close() -+ -+ return True -+ -+ -+ - @contextlib.contextmanager - def socket_setdefaulttimeout(timeout): - old_timeout = socket.getdefaulttimeout() -@@ -169,7 +189,7 @@ def socket_setdefaulttimeout(timeout): - - HAVE_SOCKET_VSOCK = _have_socket_vsock() - --HAVE_SOCKET_UDPLITE = hasattr(socket, "IPPROTO_UDPLITE") -+HAVE_SOCKET_UDPLITE = _have_udp_lite() - - HAVE_SOCKET_BLUETOOTH = _have_socket_bluetooth() - -diff --git a/Misc/NEWS.d/next/Tests/2026-05-13-14-53-23.gh-issue-149776.orqgsn.rst b/Misc/NEWS.d/next/Tests/2026-05-13-14-53-23.gh-issue-149776.orqgsn.rst -new file mode 100644 -index 0000000000..e86a9130ff ---- /dev/null -+++ b/Misc/NEWS.d/next/Tests/2026-05-13-14-53-23.gh-issue-149776.orqgsn.rst -@@ -0,0 +1,2 @@ -+Fix test_socket on Linux kernel 7.1 and newer: skip UDP Lite tests if it's -+not supported. Patch by Victor Stinner. diff --git a/00494-increase-the-timeout-of-test_large_content_length_truncated.patch b/00494-increase-the-timeout-of-test_large_content_length_truncated.patch new file mode 100644 index 0000000..229b73a --- /dev/null +++ b/00494-increase-the-timeout-of-test_large_content_length_truncated.patch @@ -0,0 +1,23 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Karolina Surma +Date: Fri, 14 Aug 2026 09:38:26 +0200 +Subject: 00494: Increase the timeout of test_large_content_length_truncated + +It has started to fail randomly when run on s390x architecture. +--- + Lib/test/test_httpservers.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/Lib/test/test_httpservers.py b/Lib/test/test_httpservers.py +index b0b09daab0..59434936b7 100644 +--- a/Lib/test/test_httpservers.py ++++ b/Lib/test/test_httpservers.py +@@ -899,7 +899,7 @@ def test_large_content_length(self): + self.assertEqual(res.read(), b'%d %d' % (size, size) + self.linesep) + + def test_large_content_length_truncated(self): +- with support.swap_attr(self.request_handler, 'timeout', 0.001): ++ with support.swap_attr(self.request_handler, 'timeout', support.LOOPBACK_TIMEOUT): + for w in range(18, 65): + size = 1 << w + headers = {'Content-Length' : str(size)} diff --git a/python3.11.spec b/python3.11.spec index 2faee17..a736a7b 100644 --- a/python3.11.spec +++ b/python3.11.spec @@ -13,11 +13,11 @@ URL: https://www.python.org/ # WARNING When rebasing to a new Python version, # remember to update the python3-docs package as well -%global general_version %{pybasever}.15 +%global general_version %{pybasever}.16 #global prerel ... %global upstream_version %{general_version}%{?prerel} Version: %{general_version}%{?prerel:~%{prerel}} -Release: 7%{?dist} +Release: 1%{?dist} License: Python-2.0.1 @@ -367,66 +367,11 @@ Patch474: 00474-cve-2025-15366.patch # (cherry-picked from commit b234a2b67539f787e191d2ef19a7cbdce32874e7) Patch475: 00475-cve-2025-15367.patch -# 00478 # 40c5c88950b10eaf1c10c5afcc39887b8e23c997 -# CVE-2026-4519 +# 00494 # 430aab133397ed44cc9ee621fd311e02fee317b5 +# Increase the timeout of test_large_content_length_truncated # -# Reject leading dashes in webbrowser URLs (GH-143931) (GH-146364) -Patch478: 00478-cve-2026-4519.patch - -# 00479 # 6fe61dd71dec5b7c9de2b1994172981667d034a1 -# CVE-2026-1502 -# -# Reject CR/LF in HTTP tunnel request headers -Patch479: 00479-cve-2026-1502.patch - -# 00480 # 9f4b1483ecfbc8c08117133c239fba544fcb42e7 -# CVE-2026-4786 -# -# Fix webbrowser `%%action` substitution bypass of dash-prefix check -Patch480: 00480-cve-2026-4786.patch - -# 00482 # 2a21454e658935990766df8c3c48af9363e8422a -# CVE-2026-6100 -# -# Fix a possible UAF in {LZMA,BZ2,_Zlib}Decompressor -Patch482: 00482-cve-2026-6100.patch - -# 00483 # cdb097a23eac5a09fb063a0e91001f69ff324205 -# CVE-2026-2297 -# -# Logging Bypass in Legacy .pyc File Handling -Patch483: 00483-cve-2026-2297.patch - -# 00484 # cf0bd2f2cce15cb35558aa08de34e9d18a8089f7 -# CVE-2026-3644 -# -# Incomplete control character validation in http.cookies -Patch484: 00484-cve-2026-3644.patch - -# 00485 # 54d821ba2f5a03ccced037978fcdb0a7c4d6878f -# CVE-2026-4224 -# -# Stack overflow parsing XML with deeply nested DTD content models -Patch485: 00485-cve-2026-4224.patch - -# 00489 # 008af720a5f6f98ed3feb8ebdbf88ab9dea4db22 -# Use BIO_eof to detect EOF for SSL_FILETYPE_ASN1 -# -# In PEM, we need to parse until error and then suppress `PEM_R_NO_START_LINE`, because PEM allows arbitrary leading and trailing data. DER, however, does not. Parsing until error and suppressing `ASN1_R_HEADER_TOO_LONG` doesn't quite work because that error also covers some cases that should be rejected. -# -# Instead, check `BIO_eof` early and stop the loop that way. -# -# This fixes https://github.com/python/cpython/issues/151504 and adds compatibility with OpenSSL 3.5.7+ -# -# (cherry-picked from commit acfe02f3b05436658d92add6b168538b30f357f0) -Patch489: 00489-openssl-3.5.7.patch - -# 00491 # ac14737379922303720216b61803474c84f291ef -# gh-149776: Skip UDP Lite tests if it's not supported -# -# Fix test_socket on Linux kernel 7.1 and newer: skip UDP Lite tests if -# it's not supported. -Patch491: 00491-gh-149776-skip-udp-lite-tests-if-it-s-not-supported.patch +# It has started to fail randomly when run on s390x architecture. +Patch494: 00494-increase-the-timeout-of-test_large_content_length_truncated.patch # (New patches go here ^^^) # @@ -1760,6 +1705,9 @@ CheckPython optimized # ====================================================== %changelog +* Thu Aug 13 2026 Karolina Surma - 3.11.16-1 +- Update to Python 3.11.16 + * Thu Jul 30 2026 Miro Hrončok - 3.11.15-7 - Skip UDP Lite tests if it's not supported - Fixes FTBFS on Linux kernel 7.1 and newer diff --git a/sources b/sources index c0c09ac..737c40b 100644 --- a/sources +++ b/sources @@ -1,2 +1,2 @@ -SHA512 (Python-3.11.15.tar.xz) = 1667f4839acfd23d05917a12993983b7dc3ab4438a37c72496fd040ac6981f4dea9dc95461ca701a6862beedb56c423fb83398b8b18e39e1efe12f539fced1c1 -SHA512 (Python-3.11.15.tar.xz.asc) = 673822ca037acb521bf7d3e7433f83cc2d60c8d102cfbf6695234e2a50ce12a7003040ad4017438510ebbb1ff0ba6727253fae250b07bc0e3d24b5578e80be52 +SHA512 (Python-3.11.16.tar.xz) = f4e168d35596c2df080663d8e8b3472f03bace987d46b49b8410f2425ba193215b9880c7d03d4653ec31c83b72209d95866fc1cb6d666799145075b092f64a48 +SHA512 (Python-3.11.16.tar.xz.asc) = b31b3205e68951478fe76f4884a124ebb4955a711b6105754d4179acb48b16a5439ec8c35383a84787cd673fa1143f2f047c6d65944909b0f1a8e3c75a0e2efe