From c4313879e74cff08155b7a94821e7410e22a18ca Mon Sep 17 00:00:00 2001 From: Tomas Orsava Date: Wed, 20 Oct 2021 16:48:24 +0200 Subject: [PATCH 001/118] Use new macros %python_wheel_dir and %python_wheel_pkg_prefix ..for build/requiring wheel packages and for the file location. This does not actually change the name or the contents of the subpackage. --- python3.11.spec | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/python3.11.spec b/python3.11.spec index 6cbe62f..c8cabc6 100644 --- a/python3.11.spec +++ b/python3.11.spec @@ -226,8 +226,8 @@ BuildRequires: /usr/bin/dtrace BuildRequires: /usr/sbin/ifconfig %if %{with rpmwheels} -BuildRequires: python-setuptools-wheel -BuildRequires: python-pip-wheel +BuildRequires: %{python_wheel_pkg_prefix}-setuptools-wheel +BuildRequires: %{python_wheel_pkg_prefix}-pip-wheel %endif %if %{without bootstrap} @@ -425,8 +425,8 @@ This package contains /usr/bin/python - the "python" command that runs Python 3. Summary: Python runtime libraries %if %{with rpmwheels} -Requires: python-setuptools-wheel -Requires: python-pip-wheel +Requires: %{python_wheel_pkg_prefix}-setuptools-wheel +Requires: %{python_wheel_pkg_prefix}-pip-wheel %else Provides: bundled(python3dist(pip)) = %{pip_version} Provides: bundled(python3dist(setuptools)) = %{setuptools_version} @@ -583,8 +583,8 @@ Provides: python%{pyshortver} = %{version}-%{release} Obsoletes: python%{pyshortver} < %{version}-%{release} %if %{with rpmwheels} -Requires: python-setuptools-wheel -Requires: python-pip-wheel +Requires: %{python_wheel_pkg_prefix}-setuptools-wheel +Requires: %{python_wheel_pkg_prefix}-pip-wheel %else Provides: bundled(python3dist(pip)) = %{pip_version} Provides: bundled(python3dist(setuptools)) = %{setuptools_version} @@ -717,7 +717,7 @@ BuildPython() { --with-ssl-default-suites=openssl \ --without-static-libpython \ %if %{with rpmwheels} - --with-wheel-pkg-dir=%{_datadir}/python-wheels \ + --with-wheel-pkg-dir=%{python_wheel_dir} \ %endif %if %{with valgrind} --with-valgrind \ From 9ff3c6864390e76a229254144b1de62b8714667b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Hrn=C4=8Diar?= Date: Fri, 10 Dec 2021 09:58:04 +0100 Subject: [PATCH 002/118] Update to 3.11.0a3 Bootstrap bcond is flipped because this update solves the issue when python3.11 didn't built with --without-bootstrap. Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=2025026 --- 00251-change-user-install-location.patch | 12 ++++++------ python3.11.spec | 7 +++++-- sources | 4 ++-- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/00251-change-user-install-location.patch b/00251-change-user-install-location.patch index 7523995..aae2255 100644 --- a/00251-change-user-install-location.patch +++ b/00251-change-user-install-location.patch @@ -33,10 +33,10 @@ Co-authored-by: Lumír Balhar 3 files changed, 36 insertions(+), 2 deletions(-) diff --git a/Lib/site.py b/Lib/site.py -index e129f3b485..ab771c70dd 100644 +index b11cd48e69..63ddd5b21b 100644 --- a/Lib/site.py +++ b/Lib/site.py -@@ -380,8 +380,15 @@ def getsitepackages(prefixes=None): +@@ -377,8 +377,15 @@ def getsitepackages(prefixes=None): return sitepackages def addsitepackages(known_paths, prefixes=None): @@ -54,7 +54,7 @@ index e129f3b485..ab771c70dd 100644 if os.path.isdir(sitedir): addsitedir(sitedir, known_paths) diff --git a/Lib/sysconfig.py b/Lib/sysconfig.py -index daf9f00006..40e4edf0ae 100644 +index da918b7ba1..89e5c079ca 100644 --- a/Lib/sysconfig.py +++ b/Lib/sysconfig.py @@ -58,6 +58,31 @@ @@ -90,10 +90,10 @@ index daf9f00006..40e4edf0ae 100644 # NOTE: site.py has copy of this function. # Sync it when modify this function. diff --git a/Lib/test/test_sysconfig.py b/Lib/test/test_sysconfig.py -index 9408657c91..fd49b2bcce 100644 +index 506266d081..761cac2779 100644 --- a/Lib/test/test_sysconfig.py +++ b/Lib/test/test_sysconfig.py -@@ -263,7 +263,7 @@ def test_get_config_h_filename(self): +@@ -267,7 +267,7 @@ def test_get_config_h_filename(self): self.assertTrue(os.path.isfile(config_h), config_h) def test_get_scheme_names(self): @@ -102,7 +102,7 @@ index 9408657c91..fd49b2bcce 100644 if HAS_USER_BASE: wanted.extend(['nt_user', 'osx_framework_user', 'posix_user']) self.assertEqual(get_scheme_names(), tuple(sorted(wanted))) -@@ -274,6 +274,8 @@ def test_symlink(self): # Issue 7880 +@@ -278,6 +278,8 @@ def test_symlink(self): # Issue 7880 cmd = "-c", "import sysconfig; print(sysconfig.get_platform())" self.assertEqual(py.call_real(*cmd), py.call_link(*cmd)) diff --git a/python3.11.spec b/python3.11.spec index c8cabc6..646da9a 100644 --- a/python3.11.spec +++ b/python3.11.spec @@ -14,7 +14,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}.0 -%global prerel a2 +%global prerel a3 %global upstream_version %{general_version}%{?prerel} Version: %{general_version}%{?prerel:~%{prerel}} Release: 1%{?dist} @@ -60,7 +60,7 @@ License: Python # IMPORTANT: When bootstrapping, it's very likely the wheels for pip and # setuptools are not available. Turn off the rpmwheels bcond until # the two packages are built with wheels to get around the issue. -%bcond_without bootstrap +%bcond_with bootstrap # Whether to use RPM build wheels from the python-{pip,setuptools}-wheel package # Uses upstream bundled prebuilt wheels otherwise @@ -1598,6 +1598,9 @@ CheckPython optimized # ====================================================== %changelog +* Fri Dec 10 2021 Tomáš Hrnčiar - 3.11.0~a3-1 +- Update to 3.11.0a3 + * Mon Nov 15 2021 Tomáš Hrnčiar - 3.11.0~a2-1 - Update to 3.11.0a2 - Patch 251 was updated to include specific install scheme for virtualenv diff --git a/sources b/sources index 9c67a35..a51b5ab 100644 --- a/sources +++ b/sources @@ -1,2 +1,2 @@ -SHA512 (Python-3.11.0a2.tar.xz) = 9a7c4d2be0cdf5801aaf6ec6337390a2f0e711badf0e0e35bcf0e5c98f652c68cf523afb991e87f4a1d1604eed3d19c56654d55922986ab27234e82675b20391 -SHA512 (Python-3.11.0a2.tar.xz.asc) = 617181a854c884c6d3a79368000ca82430bc391573ae3a1b25f69939bce3d2d365e8ca7166d941856a78f3598ab4e7720a144ecb6c3a9de1aff5928799c2988d +SHA512 (Python-3.11.0a3.tar.xz) = 69fe7a4c80ab4e7674685b072b9dea435dc7968306a1ce8b1356a1bb9b998ed6b9e35c17b5ecae3c490f5c71f524fa791bd996431d5dac550773cf5e8362a7ba +SHA512 (Python-3.11.0a3.tar.xz.asc) = 890d9092d2a155d65588f3a8f34e93b6e3e549b0507af856ffae1fbb3a2f3f1446f6bc69684c23116bed4e3a547a331173e83c3d52a7bff8caa368f955fe293d From 771f810493740f35e92e75cdd52dd9dd4b5fa621 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Mon, 13 Dec 2021 14:14:04 +0100 Subject: [PATCH 003/118] Supplement tox See https://lists.fedoraproject.org/archives/list/python-devel@lists.fedoraproject.org/thread/NVVUXSVSPFQOWIGBE2JNI67HEO7R63ZQ/ --- python3.11.spec | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/python3.11.spec b/python3.11.spec index 646da9a..114104e 100644 --- a/python3.11.spec +++ b/python3.11.spec @@ -17,7 +17,7 @@ URL: https://www.python.org/ %global prerel a3 %global upstream_version %{general_version}%{?prerel} Version: %{general_version}%{?prerel:~%{prerel}} -Release: 1%{?dist} +Release: 2%{?dist} License: Python @@ -466,6 +466,9 @@ Requires: (pyproject-rpm-macros if rpm-build) # Python developers are very likely to need pip Recommends: %{pkgname}-pip +# tox users are likely to need the devel subpackage +Supplements: tox + %if %{without bootstrap} Requires: (python3-rpm-generators if rpm-build) %endif @@ -593,6 +596,9 @@ Provides: bundled(python3dist(setuptools)) = %{setuptools_version} # The zoneinfo module needs tzdata Requires: tzdata +# The flatpackage is usable with tox +Supplements: tox + # The description for the flat package (SRPM and built) %description Python %{pybasever} package for developers. @@ -1598,6 +1604,9 @@ CheckPython optimized # ====================================================== %changelog +* Mon Dec 13 2021 Miro Hrončok - 3.11.0~a3-2 +- Supplement tox + * Fri Dec 10 2021 Tomáš Hrnčiar - 3.11.0~a3-1 - Update to 3.11.0a3 From d7572e7d38ee24c29a407360934203c02df4125b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Sat, 8 Jan 2022 11:12:38 +0100 Subject: [PATCH 004/118] Rebuilt for https://fedoraproject.org/wiki/Changes/LIBFFI34 --- python3.11.spec | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/python3.11.spec b/python3.11.spec index 114104e..1d8b474 100644 --- a/python3.11.spec +++ b/python3.11.spec @@ -17,7 +17,7 @@ URL: https://www.python.org/ %global prerel a3 %global upstream_version %{general_version}%{?prerel} Version: %{general_version}%{?prerel:~%{prerel}} -Release: 2%{?dist} +Release: 3%{?dist} License: Python @@ -1604,6 +1604,9 @@ CheckPython optimized # ====================================================== %changelog +* Sat Jan 08 2022 Miro Hrončok - 3.11.0~a3-3 +- Rebuilt for https://fedoraproject.org/wiki/Changes/LIBFFI34 + * Mon Dec 13 2021 Miro Hrončok - 3.11.0~a3-2 - Supplement tox From 0fad4d6fae6bddda0782147df907904795e38bce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Hrn=C4=8Diar?= Date: Mon, 17 Jan 2022 08:31:40 +0100 Subject: [PATCH 005/118] Update to 3.11.0a4 --- python3.11.spec | 12 ++++++++++-- sources | 4 ++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/python3.11.spec b/python3.11.spec index 1d8b474..a857c23 100644 --- a/python3.11.spec +++ b/python3.11.spec @@ -14,10 +14,10 @@ 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}.0 -%global prerel a3 +%global prerel a4 %global upstream_version %{general_version}%{?prerel} Version: %{general_version}%{?prerel:~%{prerel}} -Release: 3%{?dist} +Release: 1%{?dist} License: Python @@ -1310,6 +1310,11 @@ CheckPython optimized %{pylibdir}/importlib/metadata/*.py %{pylibdir}/importlib/metadata/__pycache__/*%{bytecode_suffixes} +%dir %{pylibdir}/importlib/resources/ +%dir %{pylibdir}/importlib/resources/__pycache__/ +%{pylibdir}/importlib/resources/*.py +%{pylibdir}/importlib/resources/__pycache__/*%{bytecode_suffixes} + %dir %{pylibdir}/json/ %dir %{pylibdir}/json/__pycache__/ %{pylibdir}/json/*.py @@ -1604,6 +1609,9 @@ CheckPython optimized # ====================================================== %changelog +* Mon Jan 17 2022 Tomáš Hrnčiar - 3.11.0~a4-1 +- Update to 3.11.0a4 + * Sat Jan 08 2022 Miro Hrončok - 3.11.0~a3-3 - Rebuilt for https://fedoraproject.org/wiki/Changes/LIBFFI34 diff --git a/sources b/sources index a51b5ab..d2b1bf4 100644 --- a/sources +++ b/sources @@ -1,2 +1,2 @@ -SHA512 (Python-3.11.0a3.tar.xz) = 69fe7a4c80ab4e7674685b072b9dea435dc7968306a1ce8b1356a1bb9b998ed6b9e35c17b5ecae3c490f5c71f524fa791bd996431d5dac550773cf5e8362a7ba -SHA512 (Python-3.11.0a3.tar.xz.asc) = 890d9092d2a155d65588f3a8f34e93b6e3e549b0507af856ffae1fbb3a2f3f1446f6bc69684c23116bed4e3a547a331173e83c3d52a7bff8caa368f955fe293d +SHA512 (Python-3.11.0a4.tar.xz) = 721ed64f3fde360e9eae6d8f8a046091c7c08f14c860572ac868132dffa4ae0a46f3f57a3872fcc096551a66e4fa3b1c87f77baa52d8524da026bbdaa74837ec +SHA512 (Python-3.11.0a4.tar.xz.asc) = 21e56475186c3e6a029a51799cf8c86ac74d3810b5aa76e4b4bc063bacb2624b21b6ec3450dd9f91722162e57390617efb521351b11d262d6583655081277611 From a0869c012a1b824a1f1097909c68e8272d64f752 Mon Sep 17 00:00:00 2001 From: Fedora Release Engineering Date: Fri, 21 Jan 2022 16:48:54 +0000 Subject: [PATCH 006/118] - Rebuilt for https://fedoraproject.org/wiki/Fedora_36_Mass_Rebuild Signed-off-by: Fedora Release Engineering --- python3.11.spec | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/python3.11.spec b/python3.11.spec index a857c23..fcdc3db 100644 --- a/python3.11.spec +++ b/python3.11.spec @@ -17,7 +17,7 @@ URL: https://www.python.org/ %global prerel a4 %global upstream_version %{general_version}%{?prerel} Version: %{general_version}%{?prerel:~%{prerel}} -Release: 1%{?dist} +Release: 2%{?dist} License: Python @@ -1609,6 +1609,9 @@ CheckPython optimized # ====================================================== %changelog +* Fri Jan 21 2022 Fedora Release Engineering - 3.11.0~a4-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_36_Mass_Rebuild + * Mon Jan 17 2022 Tomáš Hrnčiar - 3.11.0~a4-1 - Update to 3.11.0a4 From 83ff9b9200883bed043f38d1104d8579e0ab67f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Hrn=C4=8Diar?= Date: Fri, 4 Feb 2022 08:48:48 +0100 Subject: [PATCH 007/118] Update to 3.11.0a5 --- 00251-change-user-install-location.patch | 6 +++--- 00328-pyc-timestamp-invalidation-mode.patch | 2 +- python3.11.spec | 7 +++++-- sources | 4 ++-- 4 files changed, 11 insertions(+), 8 deletions(-) diff --git a/00251-change-user-install-location.patch b/00251-change-user-install-location.patch index aae2255..7bcd790 100644 --- a/00251-change-user-install-location.patch +++ b/00251-change-user-install-location.patch @@ -54,7 +54,7 @@ index b11cd48e69..63ddd5b21b 100644 if os.path.isdir(sitedir): addsitedir(sitedir, known_paths) diff --git a/Lib/sysconfig.py b/Lib/sysconfig.py -index da918b7ba1..89e5c079ca 100644 +index d4a8a68028..491f82de45 100644 --- a/Lib/sysconfig.py +++ b/Lib/sysconfig.py @@ -58,6 +58,31 @@ @@ -90,7 +90,7 @@ index da918b7ba1..89e5c079ca 100644 # NOTE: site.py has copy of this function. # Sync it when modify this function. diff --git a/Lib/test/test_sysconfig.py b/Lib/test/test_sysconfig.py -index 506266d081..761cac2779 100644 +index 2c4120979d..3a2901b0bf 100644 --- a/Lib/test/test_sysconfig.py +++ b/Lib/test/test_sysconfig.py @@ -267,7 +267,7 @@ def test_get_config_h_filename(self): @@ -102,7 +102,7 @@ index 506266d081..761cac2779 100644 if HAS_USER_BASE: wanted.extend(['nt_user', 'osx_framework_user', 'posix_user']) self.assertEqual(get_scheme_names(), tuple(sorted(wanted))) -@@ -278,6 +278,8 @@ def test_symlink(self): # Issue 7880 +@@ -279,6 +279,8 @@ def test_symlink(self): # Issue 7880 cmd = "-c", "import sysconfig; print(sysconfig.get_platform())" self.assertEqual(py.call_real(*cmd), py.call_link(*cmd)) diff --git a/00328-pyc-timestamp-invalidation-mode.patch b/00328-pyc-timestamp-invalidation-mode.patch index 26f09f2..2ed7d8d 100644 --- a/00328-pyc-timestamp-invalidation-mode.patch +++ b/00328-pyc-timestamp-invalidation-mode.patch @@ -33,7 +33,7 @@ index 388614e51b..db52725016 100644 else: return PycInvalidationMode.TIMESTAMP diff --git a/Lib/test/test_py_compile.py b/Lib/test/test_py_compile.py -index 5ed98dbff1..f30c4e43de 100644 +index 794d6436b6..322e072b61 100644 --- a/Lib/test/test_py_compile.py +++ b/Lib/test/test_py_compile.py @@ -19,6 +19,7 @@ def without_source_date_epoch(fxn): diff --git a/python3.11.spec b/python3.11.spec index fcdc3db..cd09f2e 100644 --- a/python3.11.spec +++ b/python3.11.spec @@ -14,10 +14,10 @@ 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}.0 -%global prerel a4 +%global prerel a5 %global upstream_version %{general_version}%{?prerel} Version: %{general_version}%{?prerel:~%{prerel}} -Release: 2%{?dist} +Release: 1%{?dist} License: Python @@ -1609,6 +1609,9 @@ CheckPython optimized # ====================================================== %changelog +* Fri Feb 04 2022 Tomáš Hrnčiar - 3.11.0~a5-1 +- Update to 3.11.0a5 + * Fri Jan 21 2022 Fedora Release Engineering - 3.11.0~a4-2 - Rebuilt for https://fedoraproject.org/wiki/Fedora_36_Mass_Rebuild diff --git a/sources b/sources index d2b1bf4..2de9611 100644 --- a/sources +++ b/sources @@ -1,2 +1,2 @@ -SHA512 (Python-3.11.0a4.tar.xz) = 721ed64f3fde360e9eae6d8f8a046091c7c08f14c860572ac868132dffa4ae0a46f3f57a3872fcc096551a66e4fa3b1c87f77baa52d8524da026bbdaa74837ec -SHA512 (Python-3.11.0a4.tar.xz.asc) = 21e56475186c3e6a029a51799cf8c86ac74d3810b5aa76e4b4bc063bacb2624b21b6ec3450dd9f91722162e57390617efb521351b11d262d6583655081277611 +SHA512 (Python-3.11.0a5.tar.xz) = 219dc67d1968a9950a73a809335312cc2e624695503ee0e957ed0a969966376d9cc29f50a4721828fa42fb4d0fa1f4ed3595d17c8be0b8e0265bd38fa7434c94 +SHA512 (Python-3.11.0a5.tar.xz.asc) = 3c7fb2be22dc71c4b38100dbb4ed20371782f7e7df4f02e377e6329863cc0007c1ba0d5f96b36ae46da1e452e01ccf7f66eb3abf75f746a582c8d7a96a0d0a29 From 6a8d633a93b32291e154ab0769b4cf4f523a7193 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Mon, 7 Mar 2022 19:44:25 +0100 Subject: [PATCH 008/118] Update to 3.11.0a6, in bootstrap mode --- python3.11.spec | 7 +++++-- sources | 4 ++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/python3.11.spec b/python3.11.spec index cd09f2e..6f9ae73 100644 --- a/python3.11.spec +++ b/python3.11.spec @@ -14,7 +14,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}.0 -%global prerel a5 +%global prerel a6 %global upstream_version %{general_version}%{?prerel} Version: %{general_version}%{?prerel:~%{prerel}} Release: 1%{?dist} @@ -60,7 +60,7 @@ License: Python # IMPORTANT: When bootstrapping, it's very likely the wheels for pip and # setuptools are not available. Turn off the rpmwheels bcond until # the two packages are built with wheels to get around the issue. -%bcond_with bootstrap +%bcond_without bootstrap # Whether to use RPM build wheels from the python-{pip,setuptools}-wheel package # Uses upstream bundled prebuilt wheels otherwise @@ -1609,6 +1609,9 @@ CheckPython optimized # ====================================================== %changelog +* Mon Mar 07 2022 Miro Hrončok - 3.11.0~a6-1 +- Update to 3.11.0a6 + * Fri Feb 04 2022 Tomáš Hrnčiar - 3.11.0~a5-1 - Update to 3.11.0a5 diff --git a/sources b/sources index 2de9611..4e71106 100644 --- a/sources +++ b/sources @@ -1,2 +1,2 @@ -SHA512 (Python-3.11.0a5.tar.xz) = 219dc67d1968a9950a73a809335312cc2e624695503ee0e957ed0a969966376d9cc29f50a4721828fa42fb4d0fa1f4ed3595d17c8be0b8e0265bd38fa7434c94 -SHA512 (Python-3.11.0a5.tar.xz.asc) = 3c7fb2be22dc71c4b38100dbb4ed20371782f7e7df4f02e377e6329863cc0007c1ba0d5f96b36ae46da1e452e01ccf7f66eb3abf75f746a582c8d7a96a0d0a29 +SHA512 (Python-3.11.0a6.tar.xz) = 867f7aabe10977ccf31bcfd6968fd8bb880cf5c3671bb70364a9b37296dae7ab017624446c64c12f7753b59c1ebda9e494bed5f946c5586b54fd86b0289d04ea +SHA512 (Python-3.11.0a6.tar.xz.asc) = c29bef3fa59ef304f420a18657fe3448211e4f742cc119937335aaad36b9898d965d84fc6ea8a2f9f27865e237cc929b9843663292c44dd7b3ae329aa3fab1e9 From b082002382f7928c2ec821a887760815a1d0f3bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Tue, 8 Mar 2022 10:31:06 +0100 Subject: [PATCH 009/118] CI: Temporarily opt-out from Cython part of the smoke test, 3.11.0a6 breaks is once again --- tests/tests.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/tests.yml b/tests/tests.yml index 960e5b3..c82992d 100644 --- a/tests/tests.yml +++ b/tests/tests.yml @@ -20,10 +20,10 @@ run: rpm -qa - smoke: dir: python/smoke - run: VERSION=3.11 ./venv.sh + run: VERSION=3.11 CYTHON=false ./venv.sh - smoke_virtualenv: dir: python/smoke - run: VERSION=3.11 METHOD=virtualenv ./venv.sh + run: VERSION=3.11 CYTHON=false METHOD=virtualenv ./venv.sh - selftest: dir: python/selftest run: VERSION=3.11 X="" ./parallel.sh From 483c098fbaaac012e4a81592cb1263cd24c83108 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Tue, 8 Mar 2022 12:57:38 +0100 Subject: [PATCH 010/118] Finish bootstrapping 3.11.0a6 --- python3.11.spec | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/python3.11.spec b/python3.11.spec index 6f9ae73..d8003bc 100644 --- a/python3.11.spec +++ b/python3.11.spec @@ -17,7 +17,7 @@ URL: https://www.python.org/ %global prerel a6 %global upstream_version %{general_version}%{?prerel} Version: %{general_version}%{?prerel:~%{prerel}} -Release: 1%{?dist} +Release: 2%{?dist} License: Python @@ -60,7 +60,7 @@ License: Python # IMPORTANT: When bootstrapping, it's very likely the wheels for pip and # setuptools are not available. Turn off the rpmwheels bcond until # the two packages are built with wheels to get around the issue. -%bcond_without bootstrap +%bcond_with bootstrap # Whether to use RPM build wheels from the python-{pip,setuptools}-wheel package # Uses upstream bundled prebuilt wheels otherwise @@ -1609,6 +1609,9 @@ CheckPython optimized # ====================================================== %changelog +* Tue Mar 08 2022 Miro Hrončok - 3.11.0~a6-2 +- Finish bootstrapping 3.11.0a6 + * Mon Mar 07 2022 Miro Hrončok - 3.11.0~a6-1 - Update to 3.11.0a6 From 113681a061a75c3a7c959e59525bbb505d829423 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Hrn=C4=8Diar?= Date: Wed, 6 Apr 2022 11:36:00 +0200 Subject: [PATCH 011/118] Update to 3.11.0a7, in bootstrap mode --- 00251-change-user-install-location.patch | 28 ++++++++++-------------- python3.11.spec | 21 +++++++++++++----- sources | 4 ++-- 3 files changed, 29 insertions(+), 24 deletions(-) diff --git a/00251-change-user-install-location.patch b/00251-change-user-install-location.patch index 7bcd790..a6dc1c2 100644 --- a/00251-change-user-install-location.patch +++ b/00251-change-user-install-location.patch @@ -28,9 +28,9 @@ Co-authored-by: Michal Cyprian Co-authored-by: Lumír Balhar --- Lib/site.py | 9 ++++++++- - Lib/sysconfig.py | 25 +++++++++++++++++++++++++ + Lib/sysconfig.py | 19 +++++++++++++++++++ Lib/test/test_sysconfig.py | 4 +++- - 3 files changed, 36 insertions(+), 2 deletions(-) + 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/Lib/site.py b/Lib/site.py index b11cd48e69..63ddd5b21b 100644 @@ -54,22 +54,16 @@ index b11cd48e69..63ddd5b21b 100644 if os.path.isdir(sitedir): addsitedir(sitedir, known_paths) diff --git a/Lib/sysconfig.py b/Lib/sysconfig.py -index d4a8a68028..491f82de45 100644 +index 2a01342eda..447bfff83f 100644 --- a/Lib/sysconfig.py +++ b/Lib/sysconfig.py -@@ -58,6 +58,31 @@ - }, - } +@@ -103,6 +103,25 @@ + else: + _INSTALL_SCHEMES['venv'] = _INSTALL_SCHEMES['posix_venv'] +# backup the original posix_prefix as rpm_prefix +# RPM packages use it and we need to be able to read it even when changed +_INSTALL_SCHEMES['rpm_prefix'] = _INSTALL_SCHEMES['posix_prefix'] -+# Virtualenv >= 20.10.0 favors the "venv" scheme over the defaults when creating virtual environments. -+# See: https://github.com/pypa/virtualenv/commit/8da79db86d8a5c74d03667a40e64ff832076445e -+# See: https://bugs.python.org/issue45413 -+# "venv" should be the same as the unpatched posix_prefix for us, -+# so new virtual environments aren't created with paths like venv/local/bin/python. -+_INSTALL_SCHEMES['venv'] = _INSTALL_SCHEMES['posix_prefix'] + +if (not (hasattr(sys, 'real_prefix') or + sys.prefix != sys.base_prefix) and @@ -90,19 +84,19 @@ index d4a8a68028..491f82de45 100644 # NOTE: site.py has copy of this function. # Sync it when modify this function. diff --git a/Lib/test/test_sysconfig.py b/Lib/test/test_sysconfig.py -index 2c4120979d..3a2901b0bf 100644 +index c7ec78fa4d..e47139df1f 100644 --- a/Lib/test/test_sysconfig.py +++ b/Lib/test/test_sysconfig.py -@@ -267,7 +267,7 @@ def test_get_config_h_filename(self): +@@ -333,7 +333,7 @@ def test_get_config_h_filename(self): self.assertTrue(os.path.isfile(config_h), config_h) def test_get_scheme_names(self): -- wanted = ['nt', 'posix_home', 'posix_prefix'] -+ wanted = ['nt', 'posix_home', 'posix_prefix', 'rpm_prefix', 'venv'] +- wanted = ['nt', 'posix_home', 'posix_prefix', 'posix_venv', 'nt_venv', 'venv'] ++ wanted = ['nt', 'posix_home', 'posix_prefix', 'posix_venv', 'nt_venv', 'venv', 'rpm_prefix'] if HAS_USER_BASE: wanted.extend(['nt_user', 'osx_framework_user', 'posix_user']) self.assertEqual(get_scheme_names(), tuple(sorted(wanted))) -@@ -279,6 +279,8 @@ def test_symlink(self): # Issue 7880 +@@ -345,6 +345,8 @@ def test_symlink(self): # Issue 7880 cmd = "-c", "import sysconfig; print(sysconfig.get_platform())" self.assertEqual(py.call_real(*cmd), py.call_link(*cmd)) diff --git a/python3.11.spec b/python3.11.spec index d8003bc..acfa401 100644 --- a/python3.11.spec +++ b/python3.11.spec @@ -14,10 +14,10 @@ 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}.0 -%global prerel a6 +%global prerel a7 %global upstream_version %{general_version}%{?prerel} Version: %{general_version}%{?prerel:~%{prerel}} -Release: 2%{?dist} +Release: 1%{?dist} License: Python @@ -60,7 +60,7 @@ License: Python # IMPORTANT: When bootstrapping, it's very likely the wheels for pip and # setuptools are not available. Turn off the rpmwheels bcond until # the two packages are built with wheels to get around the issue. -%bcond_with bootstrap +%bcond_without bootstrap # Whether to use RPM build wheels from the python-{pip,setuptools}-wheel package # Uses upstream bundled prebuilt wheels otherwise @@ -68,7 +68,7 @@ License: Python # If the rpmwheels condition is disabled, we use the bundled wheel packages # from Python with the versions below. # This needs to be manually updated when we update Python. -%global pip_version 21.2.4 +%global pip_version 22.0.4 %global setuptools_version 58.1.0 # Expensive optimizations (mainly, profile-guided optimizations) @@ -267,7 +267,7 @@ Source11: idle3.appdata.xml # Was Patch0 in ivazquez' python3000 specfile Patch1: 00001-rpath.patch -# 00251 # 531494a5ded29dad59f617304dab4eb8b7f80b0b +# 00251 # 178b2099a8eb7c487f1a32c3f055be6c154c0116 # Change user install location # # Change the values of sysconfig's "posix_prefix" install scheme to /usr/local @@ -1323,11 +1323,19 @@ CheckPython optimized %{pylibdir}/logging %{pylibdir}/multiprocessing +%dir %{pylibdir}/re/ +%{pylibdir}/re/*.py +%{pylibdir}/re/__pycache__/*%{bytecode_suffixes} + %dir %{pylibdir}/sqlite3/ %dir %{pylibdir}/sqlite3/__pycache__/ %{pylibdir}/sqlite3/*.py %{pylibdir}/sqlite3/__pycache__/*%{bytecode_suffixes} +%dir %{pylibdir}/tomllib/ +%{pylibdir}/tomllib/*.py +%{pylibdir}/tomllib/__pycache__/*%{bytecode_suffixes} + %if %{without flatpackage} %exclude %{pylibdir}/turtle.py %exclude %{pylibdir}/__pycache__/turtle*%{bytecode_suffixes} @@ -1609,6 +1617,9 @@ CheckPython optimized # ====================================================== %changelog +* Wed Apr 06 2022 Tomáš Hrnčiar - 3.11.0~a7-1 +- Update to 3.11.0a7 + * Tue Mar 08 2022 Miro Hrončok - 3.11.0~a6-2 - Finish bootstrapping 3.11.0a6 diff --git a/sources b/sources index 4e71106..b5d0ea2 100644 --- a/sources +++ b/sources @@ -1,2 +1,2 @@ -SHA512 (Python-3.11.0a6.tar.xz) = 867f7aabe10977ccf31bcfd6968fd8bb880cf5c3671bb70364a9b37296dae7ab017624446c64c12f7753b59c1ebda9e494bed5f946c5586b54fd86b0289d04ea -SHA512 (Python-3.11.0a6.tar.xz.asc) = c29bef3fa59ef304f420a18657fe3448211e4f742cc119937335aaad36b9898d965d84fc6ea8a2f9f27865e237cc929b9843663292c44dd7b3ae329aa3fab1e9 +SHA512 (Python-3.11.0a7.tar.xz) = f193ff9dedece16a428db129f4aac9ee2ad5f73a7f7eda2063ed58bfe230a4bfef067fe6c03e2b26d01be1d3205cee8778489ea6543b74a9d2a1f415739a63ba +SHA512 (Python-3.11.0a7.tar.xz.asc) = eae66913e3a5efe70a0c3639537e5b19cd66175a61f6e8b46b194411e27df2ea3f6a8154ed05c5905f511815f011e80c5b06b3a836ea8749cb9825f85223ecc2 From 193c0d331e182c2dfac9d5ba9561094b250a4192 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Hrn=C4=8Diar?= Date: Thu, 7 Apr 2022 10:58:24 +0200 Subject: [PATCH 012/118] Finish bootstrapping 3.11.0a7 --- python3.11.spec | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/python3.11.spec b/python3.11.spec index acfa401..52e4832 100644 --- a/python3.11.spec +++ b/python3.11.spec @@ -17,7 +17,7 @@ URL: https://www.python.org/ %global prerel a7 %global upstream_version %{general_version}%{?prerel} Version: %{general_version}%{?prerel:~%{prerel}} -Release: 1%{?dist} +Release: 2%{?dist} License: Python @@ -60,7 +60,7 @@ License: Python # IMPORTANT: When bootstrapping, it's very likely the wheels for pip and # setuptools are not available. Turn off the rpmwheels bcond until # the two packages are built with wheels to get around the issue. -%bcond_without bootstrap +%bcond_with bootstrap # Whether to use RPM build wheels from the python-{pip,setuptools}-wheel package # Uses upstream bundled prebuilt wheels otherwise @@ -1617,6 +1617,9 @@ CheckPython optimized # ====================================================== %changelog +* Thu Apr 07 2022 Tomáš Hrnčiar - 3.11.0~a7-2 +- Finish bootstrapping 3.11.0a7 + * Wed Apr 06 2022 Tomáš Hrnčiar - 3.11.0~a7-1 - Update to 3.11.0a7 From 46f7eeb836a88d89720f496975757efb6f882e7b Mon Sep 17 00:00:00 2001 From: Tomas Orsava Date: Wed, 30 Mar 2022 15:38:21 +0200 Subject: [PATCH 013/118] Build Python 3.11 with subpackages (by disabling the flatpackage bcond) No change in not providing `python(abi)` for alternative Python versions Resolves: rhbz#2063227 --- python3.11.spec | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/python3.11.spec b/python3.11.spec index 52e4832..f0bbdf9 100644 --- a/python3.11.spec +++ b/python3.11.spec @@ -17,7 +17,7 @@ URL: https://www.python.org/ %global prerel a7 %global upstream_version %{general_version}%{?prerel} Version: %{general_version}%{?prerel:~%{prerel}} -Release: 2%{?dist} +Release: 3%{?dist} License: Python @@ -40,13 +40,10 @@ License: Python %endif # Flat package, i.e. no separate subpackages -# Default (in Fedora): if this is a main Python, it is not a flatpackage +# Default (in Fedora): don't use the flatpackage structure for Python 3.11 and +# higher, remove the bcond from the spec in the future # Not supported: Combination of flatpackage enabled and main_python enabled -%if %{with main_python} %bcond_with flatpackage -%else -%bcond_without flatpackage -%endif # When bootstrapping python3, we need to build setuptools. # but setuptools BR python3-devel and that brings in python3-rpm-generators; @@ -319,6 +316,13 @@ Patch328: 00328-pyc-timestamp-invalidation-mode.patch # Descriptions, and metadata for subpackages # ========================================== +%if %{without main_python} +# We'll not provide this, on purpose +# No package in Fedora shall ever depend on a alternative Python via this +%global __requires_exclude ^python\\(abi\\) = 3\\..+ +%global __provides_exclude ^python\\(abi\\) = 3\\..+ +%endif # without main_python + # this if branch is ~300 lines long and contains subpackages' definitions %if %{without flatpackage} %if %{with main_python} @@ -363,9 +367,11 @@ Recommends: %{_bindir}/python Provides: python%{pyshortver} = %{version}-%{release} Obsoletes: python%{pyshortver} < %{version}-%{release} +%if %{with main_python} # Packages with Python modules in standard locations automatically # depend on python(abi). Provide that here. Provides: python(abi) = %{pybasever} +%endif # with main_python Requires: %{pkgname}-libs%{?_isa} = %{version}-%{release} @@ -474,7 +480,10 @@ Requires: (python3-rpm-generators if rpm-build) %endif Provides: %{pkgname}-2to3 = %{version}-%{release} + +%if %{with main_python} Provides: 2to3 = %{version}-%{release} +%endif Conflicts: %{pkgname} < %{version}-%{release} @@ -492,8 +501,10 @@ Summary: A basic graphical development environment for Python Requires: %{pkgname} = %{version}-%{release} Requires: %{pkgname}-tkinter = %{version}-%{release} +%if %{with main_python} Provides: idle3 = %{version}-%{release} Provides: idle = %{version}-%{release} +%endif Provides: %{pkgname}-tools = %{version}-%{release} Provides: %{pkgname}-tools%{?_isa} = %{version}-%{release} @@ -571,11 +582,6 @@ The debug runtime additionally supports debug builds of C-API extensions %else # with flatpackage -# We'll not provide this, on purpose -# No package in Fedora shall ever depend on flatpackage via this -%global __requires_exclude ^python\\(abi\\) = 3\\..+ -%global __provides_exclude ^python\\(abi\\) = 3\\..+ - # Python interpreter packages used to be named (or provide) name pythonXY (e.g. # python39). However, to align it with the executable names and to prepare for # Python 3.10, they were renamed to pythonX.Y (e.g. python3.9, python3.10). We @@ -1617,6 +1623,11 @@ CheckPython optimized # ====================================================== %changelog +* Wed Apr 20 2022 Tomas Orsava - 3.11.0~a7-3 +- Build Python 3.11 with subpackages +- `python(abi)` is still not Provided for alternative Python versions +- Resolves: rhbz#2063227 + * Thu Apr 07 2022 Tomáš Hrnčiar - 3.11.0~a7-2 - Finish bootstrapping 3.11.0a7 From fad16c352182658d14b2af061e0367c045cd5a19 Mon Sep 17 00:00:00 2001 From: Tomas Orsava Date: Thu, 31 Mar 2022 13:58:41 +0200 Subject: [PATCH 014/118] Let there *not* be flatpackage Remove the flatpackage bcond entirely --- python3.11.spec | 94 ++++--------------------------------------------- 1 file changed, 7 insertions(+), 87 deletions(-) diff --git a/python3.11.spec b/python3.11.spec index f0bbdf9..fb8f37f 100644 --- a/python3.11.spec +++ b/python3.11.spec @@ -31,7 +31,6 @@ License: Python # Main Python, i.e. whether this is the main Python version in the distribution # that owns /usr/bin/python3 and other unique paths # This also means the built subpackages are called python3 rather than python3X -# WARNING: This also influences the flatpackage bcond below. # By default, this is determined by the %%__default_python3_pkgversion value %if "%{?__default_python3_pkgversion}" == "%{pybasever}" %bcond_without main_python @@ -39,12 +38,6 @@ License: Python %bcond_with main_python %endif -# Flat package, i.e. no separate subpackages -# Default (in Fedora): don't use the flatpackage structure for Python 3.11 and -# higher, remove the bcond from the spec in the future -# Not supported: Combination of flatpackage enabled and main_python enabled -%bcond_with flatpackage - # When bootstrapping python3, we need to build setuptools. # but setuptools BR python3-devel and that brings in python3-rpm-generators; # python3-rpm-generators needs python3-setuptools, so we cannot have it yet. @@ -76,11 +69,7 @@ License: Python # Extra build for debugging the interpreter or C-API extensions # (the -debug subpackages) -%if %{with flatpackage} -%bcond_with debug_build -%else %bcond_without debug_build -%endif # Support for the GDB debugger %bcond_without gdb_hooks @@ -316,15 +305,7 @@ Patch328: 00328-pyc-timestamp-invalidation-mode.patch # Descriptions, and metadata for subpackages # ========================================== -%if %{without main_python} -# We'll not provide this, on purpose -# No package in Fedora shall ever depend on a alternative Python via this -%global __requires_exclude ^python\\(abi\\) = 3\\..+ -%global __provides_exclude ^python\\(abi\\) = 3\\..+ -%endif # without main_python -# this if branch is ~300 lines long and contains subpackages' definitions -%if %{without flatpackage} %if %{with main_python} # Description for the python3X SRPM only: %description @@ -337,7 +318,7 @@ third-party libraries. Summary: Python %{pybasever} interpreter # In order to support multiple Python interpreters for development purposes, -# packages with the naming scheme flatpackage (e.g. python3.5) exist for +# packages with fully versioned naming scheme (e.g. python3.9*) exist for # non-default versions of Python 3. # For consistency, we provide python3.X from python3 as well. Provides: python%{pybasever} = %{version}-%{release} @@ -361,9 +342,6 @@ Recommends: %{_bindir}/python # python39). However, to align it with the executable names and to prepare for # Python 3.10, they were renamed to pythonX.Y (e.g. python3.9, python3.10). We # provide and obsolete the previous names. -# - Here are the tags for the nonflat package, regardless if main_python (e.g. -# python3) or not (e.g. python39). For the flat package, the provide is -# repeated many lines later. Provides: python%{pyshortver} = %{version}-%{release} Obsoletes: python%{pyshortver} < %{version}-%{release} @@ -371,7 +349,12 @@ Obsoletes: python%{pyshortver} < %{version}-%{release} # Packages with Python modules in standard locations automatically # depend on python(abi). Provide that here. Provides: python(abi) = %{pybasever} -%endif # with main_python +%else +# We'll not provide this, on purpose +# No package in Fedora shall ever depend on a alternative Python via this +%global __requires_exclude ^python\\(abi\\) = 3\\..+ +%global __provides_exclude ^python\\(abi\\) = 3\\..+ +%endif Requires: %{pkgname}-libs%{?_isa} = %{version}-%{release} @@ -580,41 +563,6 @@ The debug runtime additionally supports debug builds of C-API extensions (with the "d" ABI flag) for debugging issues in those extensions. %endif # with debug_build -%else # with flatpackage - -# Python interpreter packages used to be named (or provide) name pythonXY (e.g. -# python39). However, to align it with the executable names and to prepare for -# Python 3.10, they were renamed to pythonX.Y (e.g. python3.9, python3.10). We -# provide and obsolete the previous names. -# - Here are the tags for the flat package. For the nonflat package, the -# provide is repeated many lines above. -Provides: python%{pyshortver} = %{version}-%{release} -Obsoletes: python%{pyshortver} < %{version}-%{release} - -%if %{with rpmwheels} -Requires: %{python_wheel_pkg_prefix}-setuptools-wheel -Requires: %{python_wheel_pkg_prefix}-pip-wheel -%else -Provides: bundled(python3dist(pip)) = %{pip_version} -Provides: bundled(python3dist(setuptools)) = %{setuptools_version} -%endif - -# The zoneinfo module needs tzdata -Requires: tzdata - -# The flatpackage is usable with tox -Supplements: tox - -# The description for the flat package (SRPM and built) -%description -Python %{pybasever} package for developers. - -This package exists to allow developers to test their code against a newer -version of Python. This is not a full Python stack and if you wish to run -your applications with Python %{pybasever}, update your Fedora to a newer -version once Python %{pybasever} is stable. - -%endif # with flatpackage # ====================================================== # The prep phase of the build: @@ -1123,17 +1071,13 @@ CheckPython optimized %if %{with main_python} -%if %{without flatpackage} %files -n python-unversioned-command -%endif %{_bindir}/python %{_mandir}/*/python.1* %endif -%if %{without flatpackage} %files -n %{pkgname}-libs %doc README.rst -%endif %dir %{pylibdir} %dir %{dynload_dir} @@ -1141,9 +1085,7 @@ CheckPython optimized %license %{pylibdir}/LICENSE.txt %{pylibdir}/lib2to3 -%if %{without flatpackage} %exclude %{pylibdir}/lib2to3/tests -%endif %dir %{pylibdir}/unittest/ %dir %{pylibdir}/unittest/__pycache__/ @@ -1341,11 +1283,8 @@ CheckPython optimized %dir %{pylibdir}/tomllib/ %{pylibdir}/tomllib/*.py %{pylibdir}/tomllib/__pycache__/*%{bytecode_suffixes} - -%if %{without flatpackage} %exclude %{pylibdir}/turtle.py %exclude %{pylibdir}/__pycache__/turtle*%{bytecode_suffixes} -%endif %{pylibdir}/urllib %{pylibdir}/xml @@ -1376,15 +1315,10 @@ CheckPython optimized %endif -%if %{without flatpackage} %files -n %{pkgname}-devel -%endif - %{pylibdir}/config-%{LDVERSION_optimized}-%{platform_triplet}/* -%if %{without flatpackage} %exclude %{pylibdir}/config-%{LDVERSION_optimized}-%{platform_triplet}/Makefile %exclude %{_includedir}/python%{LDVERSION_optimized}/%{_pyconfig_h} -%endif %{_includedir}/python%{LDVERSION_optimized}/*.h %{_includedir}/python%{LDVERSION_optimized}/internal/ %{_includedir}/python%{LDVERSION_optimized}/cpython/ @@ -1419,10 +1353,7 @@ CheckPython optimized %{_libdir}/pkgconfig/python-%{pybasever}-embed.pc -%if %{without flatpackage} %files -n %{pkgname}-idle -%endif - %if %{with main_python} %{_bindir}/idle* %else @@ -1437,14 +1368,9 @@ CheckPython optimized %{_datadir}/icons/hicolor/*/apps/idle3.* %endif -%if %{without flatpackage} %files -n %{pkgname}-tkinter -%endif - %{pylibdir}/tkinter -%if %{without flatpackage} %exclude %{pylibdir}/tkinter/test -%endif %{dynload_dir}/_tkinter.%{SOABI_optimized}.so %{pylibdir}/turtle.py %{pylibdir}/__pycache__/turtle*%{bytecode_suffixes} @@ -1455,10 +1381,7 @@ CheckPython optimized %{pylibdir}/turtledemo/__pycache__/*%{bytecode_suffixes} -%if %{without flatpackage} %files -n %{pkgname}-test -%endif - %{pylibdir}/ctypes/test %{pylibdir}/distutils/tests %{pylibdir}/test @@ -1480,10 +1403,7 @@ CheckPython optimized # all of the other subpackages %if %{with debug_build} -%if %{without flatpackage} %files -n %{pkgname}-debug -%endif - %if %{with main_python} %{_bindir}/python3-debug %{_bindir}/python-debug From 6019a968b0dd924d72415af614d7e664a89eae37 Mon Sep 17 00:00:00 2001 From: Tomas Orsava Date: Wed, 30 Mar 2022 18:18:54 +0200 Subject: [PATCH 015/118] Obsolete python3.X-foo from individual subpackages e.g. python3-devel now Obsoletes python3.X-devel We are contemplating splitting alternative Pythons into subpackages, so we need to obsolete each of them from the main Python version. Related: rhbz#2063227 --- python3.11.spec | 34 ++++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/python3.11.spec b/python3.11.spec index fb8f37f..adb1d27 100644 --- a/python3.11.spec +++ b/python3.11.spec @@ -152,6 +152,20 @@ License: Python %{warn:Doing a main_python build with wrong %%__default_python3_pkgversion (0%{?__default_python3_pkgversion}, but this is %pyshortver)} %endif +%if %{with main_python} +# To keep the upgrade path clean, we Obsolete python3.X from the python3 +# package and python3.X-foo from individual subpackages. +# Note that using Obsoletes without package version is not standard practice. +# Here we assert that *any* version of the system's default interpreter is +# preferable to an "extra" interpreter. For example, python3-3.6.1 will +# replace python3.6-3.6.2. +%define unversioned_obsoletes_of_python3_X_if_main() %{expand:\ +Obsoletes: python%{pybasever}%{?1:-%{1}}\ +} +%else +%define unversioned_obsoletes_of_python3_X_if_main() %{nil} +%endif + # ======================= # Build-time requirements # ======================= @@ -323,12 +337,8 @@ Summary: Python %{pybasever} interpreter # For consistency, we provide python3.X from python3 as well. Provides: python%{pybasever} = %{version}-%{release} Provides: python%{pybasever}%{?_isa} = %{version}-%{release} -# To keep the upgrade path clean, we Obsolete python3.X. -# Note that using Obsoletes without package version is not standard practice. -# Here we assert that *any* version of the system's default interpreter is -# preferable to an "extra" interpreter. For example, python3-3.6.1 will -# replace python3.6-3.6.2. -Obsoletes: python%{pybasever} + +%unversioned_obsoletes_of_python3_X_if_main # https://fedoraproject.org/wiki/Changes/Move_usr_bin_python_into_separate_package # https://fedoraproject.org/wiki/Changes/Python_means_Python3 @@ -421,6 +431,8 @@ Provides: bundled(python3dist(pip)) = %{pip_version} Provides: bundled(python3dist(setuptools)) = %{setuptools_version} %endif +%unversioned_obsoletes_of_python3_X_if_main libs + # There are files in the standard library that have python shebang. # We've filtered the automatic requirement out so libs are installable without # the main package. This however makes it pulled in by default. @@ -452,6 +464,8 @@ Requires: (python-rpm-macros if rpm-build) Requires: (python3-rpm-macros if rpm-build) Requires: (pyproject-rpm-macros if rpm-build) +%unversioned_obsoletes_of_python3_X_if_main devel + # Python developers are very likely to need pip Recommends: %{pkgname}-pip @@ -484,6 +498,8 @@ Summary: A basic graphical development environment for Python Requires: %{pkgname} = %{version}-%{release} Requires: %{pkgname}-tkinter = %{version}-%{release} +%unversioned_obsoletes_of_python3_X_if_main idle + %if %{with main_python} Provides: idle3 = %{version}-%{release} Provides: idle = %{version}-%{release} @@ -510,6 +526,8 @@ configuration, browsers, and other dialogs. Summary: A GUI toolkit for Python Requires: %{pkgname} = %{version}-%{release} +%unversioned_obsoletes_of_python3_X_if_main tkinter + # The importable module "turtle" is here, so provide python3-turtle. # (We don't provide python3-turtledemo, that's not too useful when imported.) %py_provides %{pkgname}-turtle @@ -524,6 +542,8 @@ Summary: The self-test suite for the main python3 package Requires: %{pkgname} = %{version}-%{release} Requires: %{pkgname}-libs%{?_isa} = %{version}-%{release} +%unversioned_obsoletes_of_python3_X_if_main test + %description -n %{pkgname}-test The self-test suite for the Python interpreter. @@ -546,6 +566,8 @@ Requires: %{pkgname}-test%{?_isa} = %{version}-%{release} Requires: %{pkgname}-tkinter%{?_isa} = %{version}-%{release} Requires: %{pkgname}-idle%{?_isa} = %{version}-%{release} +%unversioned_obsoletes_of_python3_X_if_main debug + %description -n %{pkgname}-debug python3-debug provides a version of the Python runtime with numerous debugging features enabled, aimed at advanced Python users such as developers of Python From 294b2649fbb604c12e62bf05631852f7709c425d Mon Sep 17 00:00:00 2001 From: Tomas Orsava Date: Wed, 13 Apr 2022 17:22:23 +0200 Subject: [PATCH 016/118] Add new bcond for python_abi_provides_for_alt_pythons By default enabled on EL, disabled on Fedora --- python3.11.spec | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/python3.11.spec b/python3.11.spec index adb1d27..57f7653 100644 --- a/python3.11.spec +++ b/python3.11.spec @@ -38,6 +38,15 @@ License: Python %bcond_with main_python %endif +# If this is *not* Main Python, should it contain `Provides: python(abi) ...`? +# In Fedora no package shall depend on an alternative Python via this tag, so we do not provide it. +# In ELN/RHEL/CentOS we want to allow building against alternative stacks, so the Provide is enabled. +%if 0%{?fedora} +%bcond_with python_abi_provides_for_alt_pythons +%else +%bcond_without python_abi_provides_for_alt_pythons +%endif + # When bootstrapping python3, we need to build setuptools. # but setuptools BR python3-devel and that brings in python3-rpm-generators; # python3-rpm-generators needs python3-setuptools, so we cannot have it yet. @@ -355,13 +364,12 @@ Recommends: %{_bindir}/python Provides: python%{pyshortver} = %{version}-%{release} Obsoletes: python%{pyshortver} < %{version}-%{release} -%if %{with main_python} +%if %{with main_python} || %{with python_abi_provides_for_alt_pythons} # Packages with Python modules in standard locations automatically # depend on python(abi). Provide that here. Provides: python(abi) = %{pybasever} %else -# We'll not provide this, on purpose -# No package in Fedora shall ever depend on a alternative Python via this +# We exclude the `python(abi)` Provides %global __requires_exclude ^python\\(abi\\) = 3\\..+ %global __provides_exclude ^python\\(abi\\) = 3\\..+ %endif From ff6e0ec3a6867f7915afd39efc5747d96ef70adc Mon Sep 17 00:00:00 2001 From: Tomas Orsava Date: Wed, 27 Apr 2022 10:57:29 +0200 Subject: [PATCH 017/118] Do not Recommend python*-pip if this is not the main_python Because we do not ship pip for alternative stacks (outside of `venv`). --- python3.11.spec | 2 ++ 1 file changed, 2 insertions(+) diff --git a/python3.11.spec b/python3.11.spec index 57f7653..fabb803 100644 --- a/python3.11.spec +++ b/python3.11.spec @@ -474,8 +474,10 @@ Requires: (pyproject-rpm-macros if rpm-build) %unversioned_obsoletes_of_python3_X_if_main devel +%if %{with main_python} # Python developers are very likely to need pip Recommends: %{pkgname}-pip +%endif # tox users are likely to need the devel subpackage Supplements: tox From 93bef0917dda6ce4f5dcfd060dfa0bfff436212e Mon Sep 17 00:00:00 2001 From: Tomas Orsava Date: Wed, 27 Apr 2022 10:59:38 +0200 Subject: [PATCH 018/118] Drop old no-longer-needed Obsoletes of python311 and python3-tools --- python3.11.spec | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/python3.11.spec b/python3.11.spec index fabb803..d21c767 100644 --- a/python3.11.spec +++ b/python3.11.spec @@ -360,9 +360,8 @@ Recommends: %{_bindir}/python # Python interpreter packages used to be named (or provide) name pythonXY (e.g. # python39). However, to align it with the executable names and to prepare for # Python 3.10, they were renamed to pythonX.Y (e.g. python3.9, python3.10). We -# provide and obsolete the previous names. +# provide the previous names. Provides: python%{pyshortver} = %{version}-%{release} -Obsoletes: python%{pyshortver} < %{version}-%{release} %if %{with main_python} || %{with python_abi_provides_for_alt_pythons} # Packages with Python modules in standard locations automatically @@ -517,7 +516,6 @@ Provides: idle = %{version}-%{release} Provides: %{pkgname}-tools = %{version}-%{release} Provides: %{pkgname}-tools%{?_isa} = %{version}-%{release} -Obsoletes: %{pkgname}-tools < %{version}-%{release} %description -n %{pkgname}-idle IDLE is Python’s Integrated Development and Learning Environment. @@ -1578,6 +1576,7 @@ CheckPython optimized * Wed Apr 20 2022 Tomas Orsava - 3.11.0~a7-3 - Build Python 3.11 with subpackages - `python(abi)` is still not Provided for alternative Python versions +- Drop old no-longer-needed Obsoletes of python311 and python3-tools - Resolves: rhbz#2063227 * Thu Apr 07 2022 Tomáš Hrnčiar - 3.11.0~a7-2 From bc0e6d534a9e4f4a7e4d20f0a20a98eaf6a7c306 Mon Sep 17 00:00:00 2001 From: Tomas Orsava Date: Wed, 27 Apr 2022 11:28:17 +0200 Subject: [PATCH 019/118] Remove an rpmlintrc rule that was only relevant to flatpackages --- python3.11.rpmlintrc | 3 --- 1 file changed, 3 deletions(-) diff --git a/python3.11.rpmlintrc b/python3.11.rpmlintrc index da5ed3f..5fc9c03 100644 --- a/python3.11.rpmlintrc +++ b/python3.11.rpmlintrc @@ -19,9 +19,6 @@ addFilter(r'self-obsoletion python3\.\d+ obsoletes python3\.\d+') # intentionally hardcoded addFilter(r'hardcoded-library-path in %{_prefix}/lib/(debug/%{_libdir}|python%{pybasever})') -# intentional for our pythonXY package -addFilter(r'python3\.\d+\.[^:]+: (E|W): devel-file-in-non-devel-package') - # we have non binary stuff, python files addFilter(r'only-non-binary-in-usr-lib') From 0ff6a2eef69eb8650d94d71fed15357dbdf2ef11 Mon Sep 17 00:00:00 2001 From: Tomas Orsava Date: Wed, 27 Apr 2022 12:42:51 +0200 Subject: [PATCH 020/118] Move _sysconfigdata_d_linux*.py to the debug subpackage --- python3.11.spec | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/python3.11.spec b/python3.11.spec index d21c767..f158d2c 100644 --- a/python3.11.spec +++ b/python3.11.spec @@ -1237,6 +1237,10 @@ CheckPython optimized %dir %{pylibdir}/site-packages/ %dir %{pylibdir}/site-packages/__pycache__/ %{pylibdir}/site-packages/README.txt + +%exclude %{pylibdir}/_sysconfigdata_d_linux_%{platform_triplet}.py +%exclude %{pylibdir}/__pycache__/_sysconfigdata_d_linux_%{platform_triplet}%{bytecode_suffixes} + %{pylibdir}/*.py %dir %{pylibdir}/__pycache__/ %{pylibdir}/__pycache__/*%{bytecode_suffixes} @@ -1550,6 +1554,9 @@ CheckPython optimized %{dynload_dir}/_testinternalcapi.%{SOABI_debug}.so %{dynload_dir}/_testmultiphase.%{SOABI_debug}.so +%{pylibdir}/_sysconfigdata_d_linux_%{platform_triplet}.py +%{pylibdir}/__pycache__/_sysconfigdata_d_linux_%{platform_triplet}%{bytecode_suffixes} + %endif # with debug_build # We put the debug-gdb.py file inside /usr/lib/debug to avoid noise from ldconfig @@ -1577,6 +1584,7 @@ CheckPython optimized - Build Python 3.11 with subpackages - `python(abi)` is still not Provided for alternative Python versions - Drop old no-longer-needed Obsoletes of python311 and python3-tools +- Move _sysconfigdata_d_linux*.py to the debug subpackage - Resolves: rhbz#2063227 * Thu Apr 07 2022 Tomáš Hrnčiar - 3.11.0~a7-2 From 1993f3aaf26fe2240485f492d9fe63512f8213b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Hrn=C4=8Diar?= Date: Sun, 8 May 2022 09:44:42 +0200 Subject: [PATCH 021/118] Update to 3.11.0b1 --- 00251-change-user-install-location.patch | 4 ++-- python3.11.spec | 9 ++++++--- sources | 4 ++-- tests/tests.yml | 1 + 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/00251-change-user-install-location.patch b/00251-change-user-install-location.patch index a6dc1c2..9948b58 100644 --- a/00251-change-user-install-location.patch +++ b/00251-change-user-install-location.patch @@ -54,7 +54,7 @@ index b11cd48e69..63ddd5b21b 100644 if os.path.isdir(sitedir): addsitedir(sitedir, known_paths) diff --git a/Lib/sysconfig.py b/Lib/sysconfig.py -index 2a01342eda..447bfff83f 100644 +index e21b7303fe..37b04452bc 100644 --- a/Lib/sysconfig.py +++ b/Lib/sysconfig.py @@ -103,6 +103,25 @@ @@ -84,7 +84,7 @@ index 2a01342eda..447bfff83f 100644 # NOTE: site.py has copy of this function. # Sync it when modify this function. diff --git a/Lib/test/test_sysconfig.py b/Lib/test/test_sysconfig.py -index c7ec78fa4d..e47139df1f 100644 +index f2b93706b2..cc58f47cdb 100644 --- a/Lib/test/test_sysconfig.py +++ b/Lib/test/test_sysconfig.py @@ -333,7 +333,7 @@ def test_get_config_h_filename(self): diff --git a/python3.11.spec b/python3.11.spec index f158d2c..bbe7b1a 100644 --- a/python3.11.spec +++ b/python3.11.spec @@ -14,10 +14,10 @@ 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}.0 -%global prerel a7 +%global prerel b1 %global upstream_version %{general_version}%{?prerel} Version: %{general_version}%{?prerel:~%{prerel}} -Release: 3%{?dist} +Release: 1%{?dist} License: Python @@ -59,7 +59,7 @@ License: Python # IMPORTANT: When bootstrapping, it's very likely the wheels for pip and # setuptools are not available. Turn off the rpmwheels bcond until # the two packages are built with wheels to get around the issue. -%bcond_with bootstrap +%bcond_without bootstrap # Whether to use RPM build wheels from the python-{pip,setuptools}-wheel package # Uses upstream bundled prebuilt wheels otherwise @@ -1580,6 +1580,9 @@ CheckPython optimized # ====================================================== %changelog +* Sun May 08 2022 Tomáš Hrnčiar - 3.11.0~b1-1 +- Update to 3.11.0b1 + * Wed Apr 20 2022 Tomas Orsava - 3.11.0~a7-3 - Build Python 3.11 with subpackages - `python(abi)` is still not Provided for alternative Python versions diff --git a/sources b/sources index b5d0ea2..8012898 100644 --- a/sources +++ b/sources @@ -1,2 +1,2 @@ -SHA512 (Python-3.11.0a7.tar.xz) = f193ff9dedece16a428db129f4aac9ee2ad5f73a7f7eda2063ed58bfe230a4bfef067fe6c03e2b26d01be1d3205cee8778489ea6543b74a9d2a1f415739a63ba -SHA512 (Python-3.11.0a7.tar.xz.asc) = eae66913e3a5efe70a0c3639537e5b19cd66175a61f6e8b46b194411e27df2ea3f6a8154ed05c5905f511815f011e80c5b06b3a836ea8749cb9825f85223ecc2 +SHA512 (Python-3.11.0b1.tar.xz) = f59f2905315593b2f486827ed7a1ffcce9e0faaac671c16026373c3e40d1e1c7b3e1f3384c2fbcbff8acc72c2466cd11c20fd04fbb6e839510d85966b38ebbf1 +SHA512 (Python-3.11.0b1.tar.xz.asc) = e47f2ad1ebc98681f82de74250b5d890e13d1c3c3573da24a4e646f9cdd41e035b9405646e0aee331df120d977f544a215df370b7a4b203082cf489776eca5ff diff --git a/tests/tests.yml b/tests/tests.yml index c82992d..5452b18 100644 --- a/tests/tests.yml +++ b/tests/tests.yml @@ -32,6 +32,7 @@ run: VERSION=3.11 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 - python3.11 # the test subject - tox # for venv tests From ac73e8a04faf479fa9ba3b5f9590f9e613192c17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Hrn=C4=8Diar?= Date: Tue, 10 May 2022 12:56:18 +0200 Subject: [PATCH 022/118] Finish bootstrapping 3.11.0b1 --- python3.11.spec | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/python3.11.spec b/python3.11.spec index bbe7b1a..97fa646 100644 --- a/python3.11.spec +++ b/python3.11.spec @@ -17,7 +17,7 @@ URL: https://www.python.org/ %global prerel b1 %global upstream_version %{general_version}%{?prerel} Version: %{general_version}%{?prerel:~%{prerel}} -Release: 1%{?dist} +Release: 2%{?dist} License: Python @@ -59,7 +59,7 @@ License: Python # IMPORTANT: When bootstrapping, it's very likely the wheels for pip and # setuptools are not available. Turn off the rpmwheels bcond until # the two packages are built with wheels to get around the issue. -%bcond_without bootstrap +%bcond_with bootstrap # Whether to use RPM build wheels from the python-{pip,setuptools}-wheel package # Uses upstream bundled prebuilt wheels otherwise @@ -1580,6 +1580,9 @@ CheckPython optimized # ====================================================== %changelog +* Tue May 10 2022 Tomáš Hrnčiar - 3.11.0~b1-2 +- Finish bootstrapping 3.11.0b1 + * Sun May 08 2022 Tomáš Hrnčiar - 3.11.0~b1-1 - Update to 3.11.0b1 From f43b8c104eee11d1d6cc1af03e8ce32b21d24aa0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Tue, 31 May 2022 21:30:38 +0200 Subject: [PATCH 023/118] Don't exclude files that don't exist When built without debug_build, RPM warns: File not found: /builddir/build/BUILDROOT/python3.11-3.11.0~b2-1.fc37.x86_64/usr/lib64/python3.11/_sysconfigdata_d_linux_x86_64-linux-gnu.py File not found: /builddir/build/BUILDROOT/python3.11-3.11.0~b2-1.fc37.x86_64/usr/lib64/python3.11/__pycache__/_sysconfigdata_d_linux_x86_64-linux-gnu.cpython-311*.pyc This might become an error in some distant future. --- python3.11.spec | 2 ++ 1 file changed, 2 insertions(+) diff --git a/python3.11.spec b/python3.11.spec index 97fa646..b27c73c 100644 --- a/python3.11.spec +++ b/python3.11.spec @@ -1238,8 +1238,10 @@ CheckPython optimized %dir %{pylibdir}/site-packages/__pycache__/ %{pylibdir}/site-packages/README.txt +%if %{with debug_build} %exclude %{pylibdir}/_sysconfigdata_d_linux_%{platform_triplet}.py %exclude %{pylibdir}/__pycache__/_sysconfigdata_d_linux_%{platform_triplet}%{bytecode_suffixes} +%endif %{pylibdir}/*.py %dir %{pylibdir}/__pycache__/ From d7833ee87621535ea66f9d84fcac7dc5374c60d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Tue, 31 May 2022 21:47:07 +0200 Subject: [PATCH 024/118] Don't hardcode %{ABIFLAGS_debug} --- python3.11.spec | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/python3.11.spec b/python3.11.spec index b27c73c..8d63da8 100644 --- a/python3.11.spec +++ b/python3.11.spec @@ -1239,8 +1239,8 @@ CheckPython optimized %{pylibdir}/site-packages/README.txt %if %{with debug_build} -%exclude %{pylibdir}/_sysconfigdata_d_linux_%{platform_triplet}.py -%exclude %{pylibdir}/__pycache__/_sysconfigdata_d_linux_%{platform_triplet}%{bytecode_suffixes} +%exclude %{pylibdir}/_sysconfigdata_%{ABIFLAGS_debug}_linux_%{platform_triplet}.py +%exclude %{pylibdir}/__pycache__/_sysconfigdata_%{ABIFLAGS_debug}_linux_%{platform_triplet}%{bytecode_suffixes} %endif %{pylibdir}/*.py @@ -1556,8 +1556,8 @@ CheckPython optimized %{dynload_dir}/_testinternalcapi.%{SOABI_debug}.so %{dynload_dir}/_testmultiphase.%{SOABI_debug}.so -%{pylibdir}/_sysconfigdata_d_linux_%{platform_triplet}.py -%{pylibdir}/__pycache__/_sysconfigdata_d_linux_%{platform_triplet}%{bytecode_suffixes} +%{pylibdir}/_sysconfigdata_%{ABIFLAGS_debug}_linux_%{platform_triplet}.py +%{pylibdir}/__pycache__/_sysconfigdata_%{ABIFLAGS_debug}_linux_%{platform_triplet}%{bytecode_suffixes} %endif # with debug_build From f8d78fe8c74c54bdcc2d52e41cfe1d99472c41fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Tue, 31 May 2022 21:20:02 +0200 Subject: [PATCH 025/118] Update to 3.11.0b2 --- python3.11.spec | 7 +++++-- sources | 4 ++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/python3.11.spec b/python3.11.spec index 8d63da8..111050f 100644 --- a/python3.11.spec +++ b/python3.11.spec @@ -14,10 +14,10 @@ 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}.0 -%global prerel b1 +%global prerel b2 %global upstream_version %{general_version}%{?prerel} Version: %{general_version}%{?prerel:~%{prerel}} -Release: 2%{?dist} +Release: 1%{?dist} License: Python @@ -1582,6 +1582,9 @@ CheckPython optimized # ====================================================== %changelog +* Tue May 31 2022 Miro Hrončok - 3.11.0~b2-1 +- Update to 3.11.0b2 + * Tue May 10 2022 Tomáš Hrnčiar - 3.11.0~b1-2 - Finish bootstrapping 3.11.0b1 diff --git a/sources b/sources index 8012898..1709635 100644 --- a/sources +++ b/sources @@ -1,2 +1,2 @@ -SHA512 (Python-3.11.0b1.tar.xz) = f59f2905315593b2f486827ed7a1ffcce9e0faaac671c16026373c3e40d1e1c7b3e1f3384c2fbcbff8acc72c2466cd11c20fd04fbb6e839510d85966b38ebbf1 -SHA512 (Python-3.11.0b1.tar.xz.asc) = e47f2ad1ebc98681f82de74250b5d890e13d1c3c3573da24a4e646f9cdd41e035b9405646e0aee331df120d977f544a215df370b7a4b203082cf489776eca5ff +SHA512 (Python-3.11.0b2.tar.xz) = 3298b2fe66fb04435138b995174245648f38f2bb75e2a8d8c4bcacf2d4510734b90e860dc37347eef22e298fa5772374238559815bbf546fb4fe9c1f0dd952f0 +SHA512 (Python-3.11.0b2.tar.xz.asc) = 99a319fe3063af89c8b6201fef931b0748c8bf8781bed1ebb0ee55ce307f87c6524af23f80d1c57eb249153fcc3b5df5c06182f60ddc6eeeb59c5cce12c4e21f From 4e62ac5fa9f69e759328df1f5ab12a835016a61b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Wed, 1 Jun 2022 00:51:10 +0200 Subject: [PATCH 026/118] Ensure that AST nodes without explicit end positions can be compiled --- ...plicit-end-positions-can-be-compiled.patch | 186 ++++++++++++++++++ python3.11.spec | 4 + 2 files changed, 190 insertions(+) create mode 100644 00381-gh-92597-ensure-that-ast-nodes-without-explicit-end-positions-can-be-compiled.patch diff --git a/00381-gh-92597-ensure-that-ast-nodes-without-explicit-end-positions-can-be-compiled.patch b/00381-gh-92597-ensure-that-ast-nodes-without-explicit-end-positions-can-be-compiled.patch new file mode 100644 index 0000000..7c5a259 --- /dev/null +++ b/00381-gh-92597-ensure-that-ast-nodes-without-explicit-end-positions-can-be-compiled.patch @@ -0,0 +1,186 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Pablo Galindo Salgado +Date: Wed, 1 Jun 2022 00:00:47 +0100 +Subject: [PATCH] 00381: gh-92597: Ensure that AST nodes without explicit end + positions can be compiled + +(cherry picked from commit 705eaec28f7bee530b1c1635ba385a49a1feaf32) +--- + Lib/test/test_ast.py | 8 +++++++ + ...2-05-30-19-00-38.gh-issue-93359.zXV3A0.rst | 2 ++ + Parser/asdl_c.py | 14 ++++++++++- + Python/Python-ast.c | 24 +++++++++---------- + 4 files changed, 35 insertions(+), 13 deletions(-) + create mode 100644 Misc/NEWS.d/next/Core and Builtins/2022-05-30-19-00-38.gh-issue-93359.zXV3A0.rst + +diff --git a/Lib/test/test_ast.py b/Lib/test/test_ast.py +index 896eb5bedd..33df22cb35 100644 +--- a/Lib/test/test_ast.py ++++ b/Lib/test/test_ast.py +@@ -362,6 +362,14 @@ def test_invalid_position_information(self): + with self.assertRaises(ValueError): + compile(tree, '', 'exec') + ++ def test_compilation_of_ast_nodes_with_default_end_position_values(self): ++ tree = ast.Module(body=[ ++ ast.Import(names=[ast.alias(name='builtins', lineno=1, col_offset=0)], lineno=1, col_offset=0), ++ ast.Import(names=[ast.alias(name='traceback', lineno=0, col_offset=0)], lineno=0, col_offset=1) ++ ], type_ignores=[]) ++ ++ # Check that compilation doesn't crash. Note: this may crash explicitly only on debug mode. ++ compile(tree, "", "exec") + + def test_slice(self): + slc = ast.parse("x[::]").body[0].value.slice +diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-05-30-19-00-38.gh-issue-93359.zXV3A0.rst b/Misc/NEWS.d/next/Core and Builtins/2022-05-30-19-00-38.gh-issue-93359.zXV3A0.rst +new file mode 100644 +index 0000000000..36e5e52390 +--- /dev/null ++++ b/Misc/NEWS.d/next/Core and Builtins/2022-05-30-19-00-38.gh-issue-93359.zXV3A0.rst +@@ -0,0 +1,2 @@ ++Ensure that custom :mod:`ast` nodes without explicit end positions can be ++compiled. Patch by Pablo Galindo. +diff --git a/Parser/asdl_c.py b/Parser/asdl_c.py +index 3bfe320fe3..1101a3593d 100755 +--- a/Parser/asdl_c.py ++++ b/Parser/asdl_c.py +@@ -488,6 +488,12 @@ def visitProduct(self, prod, name): + + + class Obj2ModVisitor(PickleVisitor): ++ ++ attribute_special_defaults = { ++ "end_lineno": "lineno", ++ "end_col_offset": "col_offset", ++ } ++ + @contextmanager + def recursive_call(self, node, level): + self.emit('if (_Py_EnterRecursiveCall(" while traversing \'%s\' node")) {' % node, level, reflow=False) +@@ -637,7 +643,13 @@ def visitField(self, field, name, sum=None, prod=None, depth=0): + self.emit("if (tmp == NULL || tmp == Py_None) {", depth) + self.emit("Py_CLEAR(tmp);", depth+1) + if self.isNumeric(field): +- self.emit("%s = 0;" % field.name, depth+1) ++ if field.name in self.attribute_special_defaults: ++ self.emit( ++ "%s = %s;" % (field.name, self.attribute_special_defaults[field.name]), ++ depth+1, ++ ) ++ else: ++ self.emit("%s = 0;" % field.name, depth+1) + elif not self.isSimpleType(field): + self.emit("%s = NULL;" % field.name, depth+1) + else: +diff --git a/Python/Python-ast.c b/Python/Python-ast.c +index 3861eaf978..e52a72d43b 100644 +--- a/Python/Python-ast.c ++++ b/Python/Python-ast.c +@@ -5697,7 +5697,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* + } + if (tmp == NULL || tmp == Py_None) { + Py_CLEAR(tmp); +- end_lineno = 0; ++ end_lineno = lineno; + } + else { + int res; +@@ -5714,7 +5714,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* + } + if (tmp == NULL || tmp == Py_None) { + Py_CLEAR(tmp); +- end_col_offset = 0; ++ end_col_offset = col_offset; + } + else { + int res; +@@ -8114,7 +8114,7 @@ obj2ast_expr(struct ast_state *state, PyObject* obj, expr_ty* out, PyArena* + } + if (tmp == NULL || tmp == Py_None) { + Py_CLEAR(tmp); +- end_lineno = 0; ++ end_lineno = lineno; + } + else { + int res; +@@ -8131,7 +8131,7 @@ obj2ast_expr(struct ast_state *state, PyObject* obj, expr_ty* out, PyArena* + } + if (tmp == NULL || tmp == Py_None) { + Py_CLEAR(tmp); +- end_col_offset = 0; ++ end_col_offset = col_offset; + } + else { + int res; +@@ -10291,7 +10291,7 @@ obj2ast_excepthandler(struct ast_state *state, PyObject* obj, excepthandler_ty* + } + if (tmp == NULL || tmp == Py_None) { + Py_CLEAR(tmp); +- end_lineno = 0; ++ end_lineno = lineno; + } + else { + int res; +@@ -10308,7 +10308,7 @@ obj2ast_excepthandler(struct ast_state *state, PyObject* obj, excepthandler_ty* + } + if (tmp == NULL || tmp == Py_None) { + Py_CLEAR(tmp); +- end_col_offset = 0; ++ end_col_offset = col_offset; + } + else { + int res; +@@ -10755,7 +10755,7 @@ obj2ast_arg(struct ast_state *state, PyObject* obj, arg_ty* out, PyArena* arena) + } + if (tmp == NULL || tmp == Py_None) { + Py_CLEAR(tmp); +- end_lineno = 0; ++ end_lineno = lineno; + } + else { + int res; +@@ -10772,7 +10772,7 @@ obj2ast_arg(struct ast_state *state, PyObject* obj, arg_ty* out, PyArena* arena) + } + if (tmp == NULL || tmp == Py_None) { + Py_CLEAR(tmp); +- end_col_offset = 0; ++ end_col_offset = col_offset; + } + else { + int res; +@@ -10877,7 +10877,7 @@ obj2ast_keyword(struct ast_state *state, PyObject* obj, keyword_ty* out, + } + if (tmp == NULL || tmp == Py_None) { + Py_CLEAR(tmp); +- end_lineno = 0; ++ end_lineno = lineno; + } + else { + int res; +@@ -10894,7 +10894,7 @@ obj2ast_keyword(struct ast_state *state, PyObject* obj, keyword_ty* out, + } + if (tmp == NULL || tmp == Py_None) { + Py_CLEAR(tmp); +- end_col_offset = 0; ++ end_col_offset = col_offset; + } + else { + int res; +@@ -10999,7 +10999,7 @@ obj2ast_alias(struct ast_state *state, PyObject* obj, alias_ty* out, PyArena* + } + if (tmp == NULL || tmp == Py_None) { + Py_CLEAR(tmp); +- end_lineno = 0; ++ end_lineno = lineno; + } + else { + int res; +@@ -11016,7 +11016,7 @@ obj2ast_alias(struct ast_state *state, PyObject* obj, alias_ty* out, PyArena* + } + if (tmp == NULL || tmp == Py_None) { + Py_CLEAR(tmp); +- end_col_offset = 0; ++ end_col_offset = col_offset; + } + else { + int res; diff --git a/python3.11.spec b/python3.11.spec index 111050f..b1d1c51 100644 --- a/python3.11.spec +++ b/python3.11.spec @@ -310,6 +310,10 @@ Patch251: 00251-change-user-install-location.patch # Ideally, we should talk to upstream and explain why we don't want this Patch328: 00328-pyc-timestamp-invalidation-mode.patch +# 00381 # d7e0c24c40417744f227744f9d6875670b7c187e +# gh-92597: Ensure that AST nodes without explicit end positions can be compiled +Patch381: 00381-gh-92597-ensure-that-ast-nodes-without-explicit-end-positions-can-be-compiled.patch + # (New patches go here ^^^) # # When adding new patches to "python" and "python3" in Fedora, EL, etc., From d6b108d1a66f94df34c0d0b1eb058acae1e816a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Wed, 1 Jun 2022 19:08:28 +0200 Subject: [PATCH 027/118] Update to 3.11.0b3 Patch 381 was merged upstream (it was the motivation for an expedited release). --- ...plicit-end-positions-can-be-compiled.patch | 186 ------------------ python3.11.spec | 9 +- sources | 4 +- 3 files changed, 6 insertions(+), 193 deletions(-) delete mode 100644 00381-gh-92597-ensure-that-ast-nodes-without-explicit-end-positions-can-be-compiled.patch diff --git a/00381-gh-92597-ensure-that-ast-nodes-without-explicit-end-positions-can-be-compiled.patch b/00381-gh-92597-ensure-that-ast-nodes-without-explicit-end-positions-can-be-compiled.patch deleted file mode 100644 index 7c5a259..0000000 --- a/00381-gh-92597-ensure-that-ast-nodes-without-explicit-end-positions-can-be-compiled.patch +++ /dev/null @@ -1,186 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Pablo Galindo Salgado -Date: Wed, 1 Jun 2022 00:00:47 +0100 -Subject: [PATCH] 00381: gh-92597: Ensure that AST nodes without explicit end - positions can be compiled - -(cherry picked from commit 705eaec28f7bee530b1c1635ba385a49a1feaf32) ---- - Lib/test/test_ast.py | 8 +++++++ - ...2-05-30-19-00-38.gh-issue-93359.zXV3A0.rst | 2 ++ - Parser/asdl_c.py | 14 ++++++++++- - Python/Python-ast.c | 24 +++++++++---------- - 4 files changed, 35 insertions(+), 13 deletions(-) - create mode 100644 Misc/NEWS.d/next/Core and Builtins/2022-05-30-19-00-38.gh-issue-93359.zXV3A0.rst - -diff --git a/Lib/test/test_ast.py b/Lib/test/test_ast.py -index 896eb5bedd..33df22cb35 100644 ---- a/Lib/test/test_ast.py -+++ b/Lib/test/test_ast.py -@@ -362,6 +362,14 @@ def test_invalid_position_information(self): - with self.assertRaises(ValueError): - compile(tree, '', 'exec') - -+ def test_compilation_of_ast_nodes_with_default_end_position_values(self): -+ tree = ast.Module(body=[ -+ ast.Import(names=[ast.alias(name='builtins', lineno=1, col_offset=0)], lineno=1, col_offset=0), -+ ast.Import(names=[ast.alias(name='traceback', lineno=0, col_offset=0)], lineno=0, col_offset=1) -+ ], type_ignores=[]) -+ -+ # Check that compilation doesn't crash. Note: this may crash explicitly only on debug mode. -+ compile(tree, "", "exec") - - def test_slice(self): - slc = ast.parse("x[::]").body[0].value.slice -diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-05-30-19-00-38.gh-issue-93359.zXV3A0.rst b/Misc/NEWS.d/next/Core and Builtins/2022-05-30-19-00-38.gh-issue-93359.zXV3A0.rst -new file mode 100644 -index 0000000000..36e5e52390 ---- /dev/null -+++ b/Misc/NEWS.d/next/Core and Builtins/2022-05-30-19-00-38.gh-issue-93359.zXV3A0.rst -@@ -0,0 +1,2 @@ -+Ensure that custom :mod:`ast` nodes without explicit end positions can be -+compiled. Patch by Pablo Galindo. -diff --git a/Parser/asdl_c.py b/Parser/asdl_c.py -index 3bfe320fe3..1101a3593d 100755 ---- a/Parser/asdl_c.py -+++ b/Parser/asdl_c.py -@@ -488,6 +488,12 @@ def visitProduct(self, prod, name): - - - class Obj2ModVisitor(PickleVisitor): -+ -+ attribute_special_defaults = { -+ "end_lineno": "lineno", -+ "end_col_offset": "col_offset", -+ } -+ - @contextmanager - def recursive_call(self, node, level): - self.emit('if (_Py_EnterRecursiveCall(" while traversing \'%s\' node")) {' % node, level, reflow=False) -@@ -637,7 +643,13 @@ def visitField(self, field, name, sum=None, prod=None, depth=0): - self.emit("if (tmp == NULL || tmp == Py_None) {", depth) - self.emit("Py_CLEAR(tmp);", depth+1) - if self.isNumeric(field): -- self.emit("%s = 0;" % field.name, depth+1) -+ if field.name in self.attribute_special_defaults: -+ self.emit( -+ "%s = %s;" % (field.name, self.attribute_special_defaults[field.name]), -+ depth+1, -+ ) -+ else: -+ self.emit("%s = 0;" % field.name, depth+1) - elif not self.isSimpleType(field): - self.emit("%s = NULL;" % field.name, depth+1) - else: -diff --git a/Python/Python-ast.c b/Python/Python-ast.c -index 3861eaf978..e52a72d43b 100644 ---- a/Python/Python-ast.c -+++ b/Python/Python-ast.c -@@ -5697,7 +5697,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* - } - if (tmp == NULL || tmp == Py_None) { - Py_CLEAR(tmp); -- end_lineno = 0; -+ end_lineno = lineno; - } - else { - int res; -@@ -5714,7 +5714,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* - } - if (tmp == NULL || tmp == Py_None) { - Py_CLEAR(tmp); -- end_col_offset = 0; -+ end_col_offset = col_offset; - } - else { - int res; -@@ -8114,7 +8114,7 @@ obj2ast_expr(struct ast_state *state, PyObject* obj, expr_ty* out, PyArena* - } - if (tmp == NULL || tmp == Py_None) { - Py_CLEAR(tmp); -- end_lineno = 0; -+ end_lineno = lineno; - } - else { - int res; -@@ -8131,7 +8131,7 @@ obj2ast_expr(struct ast_state *state, PyObject* obj, expr_ty* out, PyArena* - } - if (tmp == NULL || tmp == Py_None) { - Py_CLEAR(tmp); -- end_col_offset = 0; -+ end_col_offset = col_offset; - } - else { - int res; -@@ -10291,7 +10291,7 @@ obj2ast_excepthandler(struct ast_state *state, PyObject* obj, excepthandler_ty* - } - if (tmp == NULL || tmp == Py_None) { - Py_CLEAR(tmp); -- end_lineno = 0; -+ end_lineno = lineno; - } - else { - int res; -@@ -10308,7 +10308,7 @@ obj2ast_excepthandler(struct ast_state *state, PyObject* obj, excepthandler_ty* - } - if (tmp == NULL || tmp == Py_None) { - Py_CLEAR(tmp); -- end_col_offset = 0; -+ end_col_offset = col_offset; - } - else { - int res; -@@ -10755,7 +10755,7 @@ obj2ast_arg(struct ast_state *state, PyObject* obj, arg_ty* out, PyArena* arena) - } - if (tmp == NULL || tmp == Py_None) { - Py_CLEAR(tmp); -- end_lineno = 0; -+ end_lineno = lineno; - } - else { - int res; -@@ -10772,7 +10772,7 @@ obj2ast_arg(struct ast_state *state, PyObject* obj, arg_ty* out, PyArena* arena) - } - if (tmp == NULL || tmp == Py_None) { - Py_CLEAR(tmp); -- end_col_offset = 0; -+ end_col_offset = col_offset; - } - else { - int res; -@@ -10877,7 +10877,7 @@ obj2ast_keyword(struct ast_state *state, PyObject* obj, keyword_ty* out, - } - if (tmp == NULL || tmp == Py_None) { - Py_CLEAR(tmp); -- end_lineno = 0; -+ end_lineno = lineno; - } - else { - int res; -@@ -10894,7 +10894,7 @@ obj2ast_keyword(struct ast_state *state, PyObject* obj, keyword_ty* out, - } - if (tmp == NULL || tmp == Py_None) { - Py_CLEAR(tmp); -- end_col_offset = 0; -+ end_col_offset = col_offset; - } - else { - int res; -@@ -10999,7 +10999,7 @@ obj2ast_alias(struct ast_state *state, PyObject* obj, alias_ty* out, PyArena* - } - if (tmp == NULL || tmp == Py_None) { - Py_CLEAR(tmp); -- end_lineno = 0; -+ end_lineno = lineno; - } - else { - int res; -@@ -11016,7 +11016,7 @@ obj2ast_alias(struct ast_state *state, PyObject* obj, alias_ty* out, PyArena* - } - if (tmp == NULL || tmp == Py_None) { - Py_CLEAR(tmp); -- end_col_offset = 0; -+ end_col_offset = col_offset; - } - else { - int res; diff --git a/python3.11.spec b/python3.11.spec index b1d1c51..fc317d9 100644 --- a/python3.11.spec +++ b/python3.11.spec @@ -14,7 +14,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}.0 -%global prerel b2 +%global prerel b3 %global upstream_version %{general_version}%{?prerel} Version: %{general_version}%{?prerel:~%{prerel}} Release: 1%{?dist} @@ -310,10 +310,6 @@ Patch251: 00251-change-user-install-location.patch # Ideally, we should talk to upstream and explain why we don't want this Patch328: 00328-pyc-timestamp-invalidation-mode.patch -# 00381 # d7e0c24c40417744f227744f9d6875670b7c187e -# gh-92597: Ensure that AST nodes without explicit end positions can be compiled -Patch381: 00381-gh-92597-ensure-that-ast-nodes-without-explicit-end-positions-can-be-compiled.patch - # (New patches go here ^^^) # # When adding new patches to "python" and "python3" in Fedora, EL, etc., @@ -1586,6 +1582,9 @@ CheckPython optimized # ====================================================== %changelog +* Wed Jun 01 2022 Miro Hrončok - 3.11.0~b3-1 +- Update to 3.11.0b3 + * Tue May 31 2022 Miro Hrončok - 3.11.0~b2-1 - Update to 3.11.0b2 diff --git a/sources b/sources index 1709635..5a26218 100644 --- a/sources +++ b/sources @@ -1,2 +1,2 @@ -SHA512 (Python-3.11.0b2.tar.xz) = 3298b2fe66fb04435138b995174245648f38f2bb75e2a8d8c4bcacf2d4510734b90e860dc37347eef22e298fa5772374238559815bbf546fb4fe9c1f0dd952f0 -SHA512 (Python-3.11.0b2.tar.xz.asc) = 99a319fe3063af89c8b6201fef931b0748c8bf8781bed1ebb0ee55ce307f87c6524af23f80d1c57eb249153fcc3b5df5c06182f60ddc6eeeb59c5cce12c4e21f +SHA512 (Python-3.11.0b3.tar.xz) = 53c379311acc9d8ec645caea44f4b83b29fcbdacb7114eb7aac5a2f0229402eddb245abc8bd6665077e9c82ba0a821cc55ae7494d0667b84675248025e872498 +SHA512 (Python-3.11.0b3.tar.xz.asc) = b51a02e47de73f4998effd15eb99d356ef69cd69521f208f50de1b8acf69d5cf9c8a2f774ec8bc5e0e75534fe59efe019cffcff39bc525aa4641dc9b47efb5ef From 135d8791942a96b8dedba45744439af29540f153 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Hrn=C4=8Diar?= Date: Mon, 13 Jun 2022 11:58:44 +0200 Subject: [PATCH 028/118] Initial bootstrap for Python 3.11 mass rebuild --- python3.11.spec | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/python3.11.spec b/python3.11.spec index fc317d9..aa78ff6 100644 --- a/python3.11.spec +++ b/python3.11.spec @@ -17,7 +17,7 @@ URL: https://www.python.org/ %global prerel b3 %global upstream_version %{general_version}%{?prerel} Version: %{general_version}%{?prerel:~%{prerel}} -Release: 1%{?dist} +Release: 2%{?dist} License: Python @@ -59,11 +59,11 @@ License: Python # IMPORTANT: When bootstrapping, it's very likely the wheels for pip and # setuptools are not available. Turn off the rpmwheels bcond until # the two packages are built with wheels to get around the issue. -%bcond_with bootstrap +%bcond_without bootstrap # Whether to use RPM build wheels from the python-{pip,setuptools}-wheel package # Uses upstream bundled prebuilt wheels otherwise -%bcond_without rpmwheels +%bcond_with rpmwheels # If the rpmwheels condition is disabled, we use the bundled wheel packages # from Python with the versions below. # This needs to be manually updated when we update Python. @@ -71,10 +71,10 @@ License: Python %global setuptools_version 58.1.0 # Expensive optimizations (mainly, profile-guided optimizations) -%bcond_without optimizations +%bcond_with optimizations # Run the test suite in %%check -%bcond_without tests +%bcond_with tests # Extra build for debugging the interpreter or C-API extensions # (the -debug subpackages) @@ -1582,6 +1582,9 @@ CheckPython optimized # ====================================================== %changelog +* Mon Jun 13 2022 Tomáš Hrnčiar - 3.11.0~b3-2 +- Initial bootstrap for Python 3.11 mass rebuild + * Wed Jun 01 2022 Miro Hrončok - 3.11.0~b3-1 - Update to 3.11.0b3 From 3a1b573f2d1c1991d792bcb43ba9000099b68bd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Hrn=C4=8Diar?= Date: Mon, 13 Jun 2022 13:39:47 +0200 Subject: [PATCH 029/118] Finish bootstrapping for Python 3.11 mass rebuild --- python3.11.spec | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/python3.11.spec b/python3.11.spec index aa78ff6..490ff45 100644 --- a/python3.11.spec +++ b/python3.11.spec @@ -17,7 +17,7 @@ URL: https://www.python.org/ %global prerel b3 %global upstream_version %{general_version}%{?prerel} Version: %{general_version}%{?prerel:~%{prerel}} -Release: 2%{?dist} +Release: 3%{?dist} License: Python @@ -59,11 +59,11 @@ License: Python # IMPORTANT: When bootstrapping, it's very likely the wheels for pip and # setuptools are not available. Turn off the rpmwheels bcond until # the two packages are built with wheels to get around the issue. -%bcond_without bootstrap +%bcond_with bootstrap # Whether to use RPM build wheels from the python-{pip,setuptools}-wheel package # Uses upstream bundled prebuilt wheels otherwise -%bcond_with rpmwheels +%bcond_without rpmwheels # If the rpmwheels condition is disabled, we use the bundled wheel packages # from Python with the versions below. # This needs to be manually updated when we update Python. @@ -71,10 +71,10 @@ License: Python %global setuptools_version 58.1.0 # Expensive optimizations (mainly, profile-guided optimizations) -%bcond_with optimizations +%bcond_without optimizations # Run the test suite in %%check -%bcond_with tests +%bcond_without tests # Extra build for debugging the interpreter or C-API extensions # (the -debug subpackages) @@ -1582,6 +1582,9 @@ CheckPython optimized # ====================================================== %changelog +* Mon Jun 13 2022 Tomáš Hrnčiar - 3.11.0~b3-3 +- Finish bootstrapping for Python 3.11 mass rebuild + * Mon Jun 13 2022 Tomáš Hrnčiar - 3.11.0~b3-2 - Initial bootstrap for Python 3.11 mass rebuild From a5905dea5ffe192459ef574038c8923706798e3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Tue, 21 Jun 2022 12:50:11 +0200 Subject: [PATCH 030/118] Make C++ version of _Py_CAST work with 0/NULL --- ...version-of-_py_cast-work-with-0-null.patch | 82 +++++++++++++++++++ python3.11.spec | 18 +++- 2 files changed, 99 insertions(+), 1 deletion(-) create mode 100644 00383-gh-93442-make-c-version-of-_py_cast-work-with-0-null.patch diff --git a/00383-gh-93442-make-c-version-of-_py_cast-work-with-0-null.patch b/00383-gh-93442-make-c-version-of-_py_cast-work-with-0-null.patch new file mode 100644 index 0000000..a67c60d --- /dev/null +++ b/00383-gh-93442-make-c-version-of-_py_cast-work-with-0-null.patch @@ -0,0 +1,82 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: "Miss Islington (bot)" + <31488909+miss-islington@users.noreply.github.com> +Date: Sat, 4 Jun 2022 22:15:59 -0700 +Subject: [PATCH] 00383: gh-93442: Make C++ version of _Py_CAST work with + 0/NULL +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Add C++ overloads for _Py_CAST_impl() to handle 0/NULL. This will allow +C++ extensions that pass 0 or NULL to macros using _Py_CAST() to +continue to compile. Without this, you get an error like: + + invalid ‘static_cast’ from type ‘int’ to type ‘_object*’ + +The modern way to use a NULL value in C++ is to use nullptr. However, +we want to not break extensions that do things the old way. + +Co-authored-by: serge-sans-paille +(cherry picked from commit 8bcc3fa3453e28511d04eaa0aa7d8e1a3495d518) + +Co-authored-by: Neil Schemenauer +--- + Include/pyport.h | 14 ++++++++++++++ + Lib/test/_testcppext.cpp | 4 ++++ + .../2022-06-04-13-15-41.gh-issue-93442.4M4NDb.rst | 3 +++ + 3 files changed, 21 insertions(+) + create mode 100644 Misc/NEWS.d/next/C API/2022-06-04-13-15-41.gh-issue-93442.4M4NDb.rst + +diff --git a/Include/pyport.h b/Include/pyport.h +index 5a9adf162b..a78e290931 100644 +--- a/Include/pyport.h ++++ b/Include/pyport.h +@@ -24,9 +24,23 @@ + // + // The type argument must not be a constant type. + #ifdef __cplusplus ++#include + # define _Py_STATIC_CAST(type, expr) static_cast(expr) + extern "C++" { + namespace { ++ template ++ inline type _Py_CAST_impl(long int ptr) { ++ return reinterpret_cast(ptr); ++ } ++ template ++ inline type _Py_CAST_impl(int ptr) { ++ return reinterpret_cast(ptr); ++ } ++ template ++ inline type _Py_CAST_impl(std::nullptr_t) { ++ return static_cast(nullptr); ++ } ++ + template + inline type _Py_CAST_impl(expr_type *expr) { + return reinterpret_cast(expr); +diff --git a/Lib/test/_testcppext.cpp b/Lib/test/_testcppext.cpp +index eade7ccdaa..70f434e678 100644 +--- a/Lib/test/_testcppext.cpp ++++ b/Lib/test/_testcppext.cpp +@@ -74,6 +74,10 @@ test_api_casts(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args)) + Py_INCREF(strong_ref); + Py_DECREF(strong_ref); + ++ // gh-93442: Pass 0 as NULL for PyObject* ++ Py_XINCREF(0); ++ Py_XDECREF(0); ++ + Py_DECREF(obj); + Py_RETURN_NONE; + } +diff --git a/Misc/NEWS.d/next/C API/2022-06-04-13-15-41.gh-issue-93442.4M4NDb.rst b/Misc/NEWS.d/next/C API/2022-06-04-13-15-41.gh-issue-93442.4M4NDb.rst +new file mode 100644 +index 0000000000..f48ed37c81 +--- /dev/null ++++ b/Misc/NEWS.d/next/C API/2022-06-04-13-15-41.gh-issue-93442.4M4NDb.rst +@@ -0,0 +1,3 @@ ++Add C++ overloads for _Py_CAST_impl() to handle 0/NULL. This will allow C++ ++extensions that pass 0 or NULL to macros using _Py_CAST() to continue to ++compile. diff --git a/python3.11.spec b/python3.11.spec index 490ff45..504bc48 100644 --- a/python3.11.spec +++ b/python3.11.spec @@ -17,7 +17,7 @@ URL: https://www.python.org/ %global prerel b3 %global upstream_version %{general_version}%{?prerel} Version: %{general_version}%{?prerel:~%{prerel}} -Release: 3%{?dist} +Release: 4%{?dist} License: Python @@ -310,6 +310,19 @@ Patch251: 00251-change-user-install-location.patch # Ideally, we should talk to upstream and explain why we don't want this Patch328: 00328-pyc-timestamp-invalidation-mode.patch +# 00383 # b4e1d3233b9fbcd9a60370d0f29e65012bb9532d +# gh-93442: Make C++ version of _Py_CAST work with 0/NULL +# +# Add C++ overloads for _Py_CAST_impl() to handle 0/NULL. This will allow +# C++ extensions that pass 0 or NULL to macros using _Py_CAST() to +# continue to compile. Without this, you get an error like: +# +# invalid ‘static_cast’ from type ‘int’ to type ‘_object*’ +# +# The modern way to use a NULL value in C++ is to use nullptr. However, +# we want to not break extensions that do things the old way. +Patch383: 00383-gh-93442-make-c-version-of-_py_cast-work-with-0-null.patch + # (New patches go here ^^^) # # When adding new patches to "python" and "python3" in Fedora, EL, etc., @@ -1582,6 +1595,9 @@ CheckPython optimized # ====================================================== %changelog +* Tue Jun 21 2022 Miro Hrončok - 3.11.0~b3-4 +- Make C++ version of _Py_CAST work with 0/NULL + * Mon Jun 13 2022 Tomáš Hrnčiar - 3.11.0~b3-3 - Finish bootstrapping for Python 3.11 mass rebuild From d4eda6057aa0a63df8a4323fb85dee94cdc81950 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Mon, 20 Jun 2022 13:33:12 +0200 Subject: [PATCH 031/118] rpminspect: exclude the debug build from annocheck entirely --- rpminspect.yaml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/rpminspect.yaml b/rpminspect.yaml index 213d92c..a111efb 100644 --- a/rpminspect.yaml +++ b/rpminspect.yaml @@ -9,6 +9,13 @@ badfuncs: ignore: - /usr/lib*/python*/lib-dynload/_socket.* +# 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 + # don't report changed content of compiled files # that is expected with every toolchain update and not reproducible yet changedfiles: From 73f080a859b650c2c0ec0ceabaceb0a48a56b05a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Hrn=C4=8Diar?= Date: Mon, 20 Jun 2022 09:18:46 +0200 Subject: [PATCH 032/118] Fedora CI: Make CI tests compatible with both main and non-main Python --- tests/tests.yml | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/tests/tests.yml b/tests/tests.yml index 5452b18..f6b2e90 100644 --- a/tests/tests.yml +++ b/tests/tests.yml @@ -20,13 +20,22 @@ run: rpm -qa - smoke: dir: python/smoke - run: VERSION=3.11 CYTHON=false ./venv.sh + run: VERSION=3.11 ./venv.sh - smoke_virtualenv: dir: python/smoke - run: VERSION=3.11 CYTHON=false METHOD=virtualenv ./venv.sh + run: VERSION=3.11 METHOD=virtualenv ./venv.sh + - debugsmoke: + dir: python/smoke + run: PYTHON=python3.11d TOX=false VERSION=3.11 ./venv.sh - selftest: dir: python/selftest run: VERSION=3.11 X="" ./parallel.sh + - debugtest: + dir: python/selftest + run: VERSION=3.11 PYTHON=python3.11d X="" ./parallel.sh + - debugflags: + dir: python/flags + run: python3.11d ./assertflags.py -O0 - marshalparser: dir: python/marshalparser run: VERSION=3.11 SAMPLE=10 test_marshalparser_compatibility.sh @@ -35,6 +44,10 @@ - gcc-c++ # for test_cppext - gdb # for test_gdb - python3.11 # the test subject + - python3.11-debug # for leak testing + - python3.11-devel # for extension building in venv and selftest + - python3.11-tkinter # for selftest + - python3.11-test # for selftest - tox # for venv tests - virtualenv # for virtualenv tests - glibc-all-langpacks # for locale tests From 17d458f006d8e4b23490fda6b038105d34a2ebb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Tue, 21 Jun 2022 22:53:30 +0200 Subject: [PATCH 033/118] Build Python with the optimized Blake2 library libb2 See https://github.com/python/cpython/issues/91251 > Distributors are encouraged to build Python with the optimized Blake2 > library libb2. --- python3.11.spec | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/python3.11.spec b/python3.11.spec index 504bc48..d6c1695 100644 --- a/python3.11.spec +++ b/python3.11.spec @@ -17,7 +17,7 @@ URL: https://www.python.org/ %global prerel b3 %global upstream_version %{general_version}%{?prerel} Version: %{general_version}%{?prerel:~%{prerel}} -Release: 4%{?dist} +Release: 5%{?dist} License: Python @@ -199,6 +199,7 @@ BuildRequires: glibc-devel BuildRequires: gmp-devel BuildRequires: gnupg2 BuildRequires: libappstream-glib +BuildRequires: libb2-devel BuildRequires: libffi-devel BuildRequires: libnsl2-devel BuildRequires: libtirpc-devel @@ -1595,6 +1596,9 @@ CheckPython optimized # ====================================================== %changelog +* Tue Jun 21 2022 Miro Hrončok - 3.11.0~b3-5 +- Build Python with the optimized Blake2 library libb2 + * Tue Jun 21 2022 Miro Hrončok - 3.11.0~b3-4 - Make C++ version of _Py_CAST work with 0/NULL From 7ce324c29a947a8e4acbe4e06444a1ad79365060 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Hrn=C4=8Diar?= Date: Fri, 24 Jun 2022 11:59:24 +0200 Subject: [PATCH 034/118] Add patches #371 & #384 Clear and reset sqlite3 statements properly in cursor iternext (fixes rhbz#2099049) Revert a problematic fix of threading._shutdown() again (fixes rhbz#2100282) --- ...or-the-main-thread-gh-28549-gh-28589.patch | 103 ++++++++++++++++++ ...properly-in-cursor-iternext-gh-94042.patch | 90 +++++++++++++++ python3.11.spec | 21 +++- 3 files changed, 213 insertions(+), 1 deletion(-) create mode 100644 00371-revert-bpo-1596321-fix-threading-_shutdown-for-the-main-thread-gh-28549-gh-28589.patch create mode 100644 00384-gh-94028-clear-and-reset-sqlite3-statements-properly-in-cursor-iternext-gh-94042.patch 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 new file mode 100644 index 0000000..635b682 --- /dev/null +++ b/00371-revert-bpo-1596321-fix-threading-_shutdown-for-the-main-thread-gh-28549-gh-28589.patch @@ -0,0 +1,103 @@ +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)" + +This reverts commit 38c67738c64304928c68d5c2bd78bbb01d979b94. It +introduced regression causing FreeIPA's tests to fail. + +For more info see: +https://bodhi.fedoraproject.org/updates/FEDORA-2021-e152ce5f31 +https://github.com/GrahamDumpleton/mod_wsgi/issues/730 +--- + Lib/test/test_threading.py | 33 --------------------------------- + Lib/threading.py | 25 ++++++++----------------- + 2 files changed, 8 insertions(+), 50 deletions(-) + +diff --git a/Lib/test/test_threading.py b/Lib/test/test_threading.py +index 9c6561c099..84714c03fe 100644 +--- a/Lib/test/test_threading.py ++++ b/Lib/test/test_threading.py +@@ -956,39 +956,6 @@ def test_debug_deprecation(self): + b'is deprecated and will be removed in Python 3.12') + self.assertIn(msg, err) + +- def test_import_from_another_thread(self): +- # bpo-1596321: If the threading module is first import from a thread +- # different than the main thread, threading._shutdown() must handle +- # this case without logging an error at Python exit. +- code = textwrap.dedent(''' +- import _thread +- import sys +- +- event = _thread.allocate_lock() +- event.acquire() +- +- def import_threading(): +- import threading +- event.release() +- +- if 'threading' in sys.modules: +- raise Exception('threading is already imported') +- +- _thread.start_new_thread(import_threading, ()) +- +- # wait until the threading module is imported +- event.acquire() +- event.release() +- +- if 'threading' not in sys.modules: +- raise Exception('threading is not imported') +- +- # don't wait until the thread completes +- ''') +- rc, out, err = assert_python_ok("-c", code) +- self.assertEqual(out, b'') +- self.assertEqual(err, b'') +- + + class ThreadJoinOnShutdown(BaseTestCase): + +diff --git a/Lib/threading.py b/Lib/threading.py +index 8e7cdf6f62..a701401f28 100644 +--- a/Lib/threading.py ++++ b/Lib/threading.py +@@ -1546,29 +1546,20 @@ def _shutdown(): + + global _SHUTTING_DOWN + _SHUTTING_DOWN = True ++ # Main thread ++ tlock = _main_thread._tstate_lock ++ # The main thread isn't finished yet, so its thread state lock can't have ++ # been released. ++ assert tlock is not None ++ assert tlock.locked() ++ tlock.release() ++ _main_thread._stop() + + # Call registered threading atexit functions before threads are joined. + # Order is reversed, similar to atexit. + for atexit_call in reversed(_threading_atexits): + atexit_call() + +- # Main thread +- if _main_thread.ident == get_ident(): +- tlock = _main_thread._tstate_lock +- # The main thread isn't finished yet, so its thread state lock can't +- # have been released. +- assert tlock is not None +- assert tlock.locked() +- tlock.release() +- _main_thread._stop() +- else: +- # bpo-1596321: _shutdown() must be called in the main thread. +- # If the threading module was not imported by the main thread, +- # _main_thread is the thread which imported the threading module. +- # In this case, ignore _main_thread, similar behavior than for threads +- # spawned by C libraries or using _thread.start_new_thread(). +- pass +- + # Join all non-deamon threads + while True: + with _shutdown_locks_lock: diff --git a/00384-gh-94028-clear-and-reset-sqlite3-statements-properly-in-cursor-iternext-gh-94042.patch b/00384-gh-94028-clear-and-reset-sqlite3-statements-properly-in-cursor-iternext-gh-94042.patch new file mode 100644 index 0000000..a2ce195 --- /dev/null +++ b/00384-gh-94028-clear-and-reset-sqlite3-statements-properly-in-cursor-iternext-gh-94042.patch @@ -0,0 +1,90 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Erlend Egeberg Aasland +Date: Tue, 21 Jun 2022 13:30:29 +0200 +Subject: [PATCH] 00384: gh-94028: Clear and reset sqlite3 statements properly + in cursor iternext (GH-94042) + +--- + Lib/test/test_sqlite3/test_transactions.py | 39 +++++++++++++++++++ + ...2-06-20-23-14-43.gh-issue-94028.UofEcX.rst | 3 ++ + Modules/_sqlite/cursor.c | 3 ++ + 3 files changed, 45 insertions(+) + create mode 100644 Misc/NEWS.d/next/Library/2022-06-20-23-14-43.gh-issue-94028.UofEcX.rst + +diff --git a/Lib/test/test_sqlite3/test_transactions.py b/Lib/test/test_sqlite3/test_transactions.py +index 040ab1ee60..226a1d03fa 100644 +--- a/Lib/test/test_sqlite3/test_transactions.py ++++ b/Lib/test/test_sqlite3/test_transactions.py +@@ -141,6 +141,45 @@ def test_rollback_cursor_consistency(self): + con.rollback() + self.assertEqual(cur.fetchall(), [(1,), (2,), (3,)]) + ++ def test_multiple_cursors_and_iternext(self): ++ # gh-94028: statements are cleared and reset in cursor iternext. ++ ++ # Provoke the gh-94028 by using a cursor cache. ++ CURSORS = {} ++ def sql(cx, sql, *args): ++ cu = cx.cursor() ++ cu.execute(sql, args) ++ CURSORS[id(sql)] = cu ++ return cu ++ ++ self.con1.execute("create table t(t)") ++ sql(self.con1, "insert into t values (?), (?), (?)", "u1", "u2", "u3") ++ self.con1.commit() ++ ++ # On second connection, verify rows are visible, then delete them. ++ count = sql(self.con2, "select count(*) from t").fetchone()[0] ++ self.assertEqual(count, 3) ++ changes = sql(self.con2, "delete from t").rowcount ++ self.assertEqual(changes, 3) ++ self.con2.commit() ++ ++ # Back in original connection, create 2 new users. ++ sql(self.con1, "insert into t values (?)", "u4") ++ sql(self.con1, "insert into t values (?)", "u5") ++ ++ # The second connection cannot see uncommitted changes. ++ count = sql(self.con2, "select count(*) from t").fetchone()[0] ++ self.assertEqual(count, 0) ++ ++ # First connection can see its own changes. ++ count = sql(self.con1, "select count(*) from t").fetchone()[0] ++ self.assertEqual(count, 2) ++ ++ # The second connection can now see the changes. ++ self.con1.commit() ++ count = sql(self.con2, "select count(*) from t").fetchone()[0] ++ self.assertEqual(count, 2) ++ + + class RollbackTests(unittest.TestCase): + """bpo-44092: sqlite3 now leaves it to SQLite to resolve rollback issues""" +diff --git a/Misc/NEWS.d/next/Library/2022-06-20-23-14-43.gh-issue-94028.UofEcX.rst b/Misc/NEWS.d/next/Library/2022-06-20-23-14-43.gh-issue-94028.UofEcX.rst +new file mode 100644 +index 0000000000..5775b2276d +--- /dev/null ++++ b/Misc/NEWS.d/next/Library/2022-06-20-23-14-43.gh-issue-94028.UofEcX.rst +@@ -0,0 +1,3 @@ ++Fix a regression in the :mod:`sqlite3` where statement objects were not ++properly cleared and reset after use in cursor iters. The regression was ++introduced by PR 27884 in Python 3.11a1. Patch by Erlend E. Aasland. +diff --git a/Modules/_sqlite/cursor.c b/Modules/_sqlite/cursor.c +index c58def5f03..8048d83683 100644 +--- a/Modules/_sqlite/cursor.c ++++ b/Modules/_sqlite/cursor.c +@@ -1126,10 +1126,13 @@ pysqlite_cursor_iternext(pysqlite_Cursor *self) + int rc = stmt_step(stmt); + if (rc == SQLITE_DONE) { + (void)stmt_reset(self->statement); ++ Py_CLEAR(self->statement); + } + else if (rc != SQLITE_ROW) { + (void)_pysqlite_seterror(self->connection->state, + self->connection->db); ++ (void)stmt_reset(self->statement); ++ Py_CLEAR(self->statement); + Py_DECREF(row); + return NULL; + } diff --git a/python3.11.spec b/python3.11.spec index d6c1695..7fdecbb 100644 --- a/python3.11.spec +++ b/python3.11.spec @@ -17,7 +17,7 @@ URL: https://www.python.org/ %global prerel b3 %global upstream_version %{general_version}%{?prerel} Version: %{general_version}%{?prerel:~%{prerel}} -Release: 5%{?dist} +Release: 6%{?dist} License: Python @@ -311,6 +311,17 @@ Patch251: 00251-change-user-install-location.patch # Ideally, we should talk to upstream and explain why we don't want this Patch328: 00328-pyc-timestamp-invalidation-mode.patch +# 00371 # c1754d9c2750f89cb702e1b63a99201f5f7cff00 +# 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. +# +# For more info see: +# https://bodhi.fedoraproject.org/updates/FEDORA-2021-e152ce5f31 +# 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 + # 00383 # b4e1d3233b9fbcd9a60370d0f29e65012bb9532d # gh-93442: Make C++ version of _Py_CAST work with 0/NULL # @@ -324,6 +335,10 @@ Patch328: 00328-pyc-timestamp-invalidation-mode.patch # we want to not break extensions that do things the old way. Patch383: 00383-gh-93442-make-c-version-of-_py_cast-work-with-0-null.patch +# 00384 # 7c809258e34925560cc13a377b1c6d9c03e83207 +# gh-94028: Clear and reset sqlite3 statements properly in cursor iternext (GH-94042) +Patch384: 00384-gh-94028-clear-and-reset-sqlite3-statements-properly-in-cursor-iternext-gh-94042.patch + # (New patches go here ^^^) # # When adding new patches to "python" and "python3" in Fedora, EL, etc., @@ -1596,6 +1611,10 @@ CheckPython optimized # ====================================================== %changelog +* Fri Jun 24 2022 Tomáš Hrnčiar - 3.11.0~b3-6 +- Clear and reset sqlite3 statements properly in cursor iternext (fixes rhbz#2099049) +- Revert a problematic fix of threading._shutdown() again (fixes rhbz#2100282) + * Tue Jun 21 2022 Miro Hrončok - 3.11.0~b3-5 - Build Python with the optimized Blake2 library libb2 From 0b91c9eccc0a845f4a0f0b0c8690ec1521c3003b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Fri, 8 Jul 2022 11:35:21 +0200 Subject: [PATCH 035/118] Fix speed regression in the re module which prevented chromium from building For details, see https://github.com/python/cpython/issues/94675 Backported from upstream 3.11 branch + https://github.com/python/cpython/pull/94685 Needs bootstrap for test_distutils (assert _sre.MAGIC == MAGIC, "SRE module mismatch"). --- ...-bpo-23689-re-module-fix-memory-leak.patch | 746 ++++++++++++++++++ python3.11.spec | 24 +- 2 files changed, 768 insertions(+), 2 deletions(-) create mode 100644 00385-gh-91404-revert-bpo-23689-re-module-fix-memory-leak.patch diff --git a/00385-gh-91404-revert-bpo-23689-re-module-fix-memory-leak.patch b/00385-gh-91404-revert-bpo-23689-re-module-fix-memory-leak.patch new file mode 100644 index 0000000..e7c2136 --- /dev/null +++ b/00385-gh-91404-revert-bpo-23689-re-module-fix-memory-leak.patch @@ -0,0 +1,746 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: "Miss Islington (bot)" + <31488909+miss-islington@users.noreply.github.com> +Date: Fri, 17 Jun 2022 01:43:56 -0700 +Subject: [PATCH] 00385: gh-91404: Revert "bpo-23689: re module, fix memory + leak..." +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This fixes a speed regression in the re module +which prevented chromium from building in Fedora. + +Revert "bpo-23689: re module, fix memory leak when a match is terminated by a signal or memory allocation failure" + +This reverts commit 6e3eee5c11b539e9aab39cff783acf57838c355a. + +Manual fixups to increase the MAGIC number and to handle conflicts with +a couple of changes that landed after that. + +(cherry picked from commit 4beee0c7b0c2cc78a893dde88fd8e34099dcf877) +Co-authored-by: Gregory P. Smith + +gh-94675: Add a regression test for rjsmin re slowdown + +Co-authored-by: Miro Hrončok +--- + Lib/re/_compiler.py | 59 ++++++----------- + Lib/re/_constants.py | 2 +- + Lib/test/test_re.py | 59 +++++++++-------- + ...2-06-15-21-35-11.gh-issue-91404.39TZzW.rst | 3 + + ...2-07-08-12-22-00.gh-issue-94675.IiTs5f.rst | 1 + + Modules/_sre/clinic/sre.c.h | 27 ++------ + Modules/_sre/sre.c | 65 +++++++------------ + Modules/_sre/sre.h | 4 -- + Modules/_sre/sre_constants.h | 2 +- + Modules/_sre/sre_lib.h | 30 +++++---- + 10 files changed, 105 insertions(+), 147 deletions(-) + create mode 100644 Misc/NEWS.d/next/Library/2022-06-15-21-35-11.gh-issue-91404.39TZzW.rst + create mode 100644 Misc/NEWS.d/next/Tests/2022-07-08-12-22-00.gh-issue-94675.IiTs5f.rst + +diff --git a/Lib/re/_compiler.py b/Lib/re/_compiler.py +index 4b5322338c..d8e0d2fdef 100644 +--- a/Lib/re/_compiler.py ++++ b/Lib/re/_compiler.py +@@ -28,21 +28,14 @@ + POSSESSIVE_REPEAT: (POSSESSIVE_REPEAT, SUCCESS, POSSESSIVE_REPEAT_ONE), + } + +-class _CompileData: +- __slots__ = ('code', 'repeat_count') +- def __init__(self): +- self.code = [] +- self.repeat_count = 0 +- + def _combine_flags(flags, add_flags, del_flags, + TYPE_FLAGS=_parser.TYPE_FLAGS): + if add_flags & TYPE_FLAGS: + flags &= ~TYPE_FLAGS + return (flags | add_flags) & ~del_flags + +-def _compile(data, pattern, flags): ++def _compile(code, pattern, flags): + # internal: compile a (sub)pattern +- code = data.code + emit = code.append + _len = len + LITERAL_CODES = _LITERAL_CODES +@@ -115,7 +108,7 @@ def _compile(data, pattern, flags): + skip = _len(code); emit(0) + emit(av[0]) + emit(av[1]) +- _compile(data, av[2], flags) ++ _compile(code, av[2], flags) + emit(SUCCESS) + code[skip] = _len(code) - skip + else: +@@ -123,11 +116,7 @@ def _compile(data, pattern, flags): + skip = _len(code); emit(0) + emit(av[0]) + emit(av[1]) +- # now op is in (MIN_REPEAT, MAX_REPEAT, POSSESSIVE_REPEAT) +- if op != POSSESSIVE_REPEAT: +- emit(data.repeat_count) +- data.repeat_count += 1 +- _compile(data, av[2], flags) ++ _compile(code, av[2], flags) + code[skip] = _len(code) - skip + emit(REPEATING_CODES[op][1]) + elif op is SUBPATTERN: +@@ -136,7 +125,7 @@ def _compile(data, pattern, flags): + emit(MARK) + emit((group-1)*2) + # _compile_info(code, p, _combine_flags(flags, add_flags, del_flags)) +- _compile(data, p, _combine_flags(flags, add_flags, del_flags)) ++ _compile(code, p, _combine_flags(flags, add_flags, del_flags)) + if group: + emit(MARK) + emit((group-1)*2+1) +@@ -148,7 +137,7 @@ def _compile(data, pattern, flags): + # pop their stack if they reach it + emit(ATOMIC_GROUP) + skip = _len(code); emit(0) +- _compile(data, av, flags) ++ _compile(code, av, flags) + emit(SUCCESS) + code[skip] = _len(code) - skip + elif op in SUCCESS_CODES: +@@ -163,7 +152,7 @@ def _compile(data, pattern, flags): + if lo != hi: + raise error("look-behind requires fixed-width pattern") + emit(lo) # look behind +- _compile(data, av[1], flags) ++ _compile(code, av[1], flags) + emit(SUCCESS) + code[skip] = _len(code) - skip + elif op is AT: +@@ -182,7 +171,7 @@ def _compile(data, pattern, flags): + for av in av[1]: + skip = _len(code); emit(0) + # _compile_info(code, av, flags) +- _compile(data, av, flags) ++ _compile(code, av, flags) + emit(JUMP) + tailappend(_len(code)); emit(0) + code[skip] = _len(code) - skip +@@ -210,12 +199,12 @@ def _compile(data, pattern, flags): + emit(op) + emit(av[0]-1) + skipyes = _len(code); emit(0) +- _compile(data, av[1], flags) ++ _compile(code, av[1], flags) + if av[2]: + emit(JUMP) + skipno = _len(code); emit(0) + code[skipyes] = _len(code) - skipyes + 1 +- _compile(data, av[2], flags) ++ _compile(code, av[2], flags) + code[skipno] = _len(code) - skipno + else: + code[skipyes] = _len(code) - skipyes + 1 +@@ -582,17 +571,17 @@ def isstring(obj): + def _code(p, flags): + + flags = p.state.flags | flags +- data = _CompileData() ++ code = [] + + # compile info block +- _compile_info(data.code, p, flags) ++ _compile_info(code, p, flags) + + # compile the pattern +- _compile(data, p.data, flags) ++ _compile(code, p.data, flags) + +- data.code.append(SUCCESS) ++ code.append(SUCCESS) + +- return data ++ return code + + def _hex_code(code): + return '[%s]' % ', '.join('%#0*x' % (_sre.CODESIZE*2+2, x) for x in code) +@@ -693,7 +682,7 @@ def print_2(*args): + else: + print_(FAILURE) + i += 1 +- elif op in (REPEAT_ONE, MIN_REPEAT_ONE, ++ elif op in (REPEAT, REPEAT_ONE, MIN_REPEAT_ONE, + POSSESSIVE_REPEAT, POSSESSIVE_REPEAT_ONE): + skip, min, max = code[i: i+3] + if max == MAXREPEAT: +@@ -701,13 +690,6 @@ def print_2(*args): + print_(op, skip, min, max, to=i+skip) + dis_(i+3, i+skip) + i += skip +- elif op is REPEAT: +- skip, min, max, repeat_index = code[i: i+4] +- if max == MAXREPEAT: +- max = 'MAXREPEAT' +- print_(op, skip, min, max, repeat_index, to=i+skip) +- dis_(i+4, i+skip) +- i += skip + elif op is GROUPREF_EXISTS: + arg, skip = code[i: i+2] + print_(op, arg, skip, to=i+skip) +@@ -762,11 +744,11 @@ def compile(p, flags=0): + else: + pattern = None + +- data = _code(p, flags) ++ code = _code(p, flags) + + if flags & SRE_FLAG_DEBUG: + print() +- dis(data.code) ++ dis(code) + + # map in either direction + groupindex = p.state.groupdict +@@ -775,6 +757,7 @@ def compile(p, flags=0): + indexgroup[i] = k + + return _sre.compile( +- pattern, flags | p.state.flags, data.code, +- p.state.groups-1, groupindex, tuple(indexgroup), +- data.repeat_count) ++ pattern, flags | p.state.flags, code, ++ p.state.groups-1, ++ groupindex, tuple(indexgroup) ++ ) +diff --git a/Lib/re/_constants.py b/Lib/re/_constants.py +index 1cc85c631f..10ee14bfab 100644 +--- a/Lib/re/_constants.py ++++ b/Lib/re/_constants.py +@@ -13,7 +13,7 @@ + + # update when constants are added or removed + +-MAGIC = 20220423 ++MAGIC = 20220615 + + from _sre import MAXREPEAT, MAXGROUPS + +diff --git a/Lib/test/test_re.py b/Lib/test/test_re.py +index 6d61412f16..5d946370ee 100644 +--- a/Lib/test/test_re.py ++++ b/Lib/test/test_re.py +@@ -1,6 +1,7 @@ + from test.support import (gc_collect, bigmemtest, _2G, + cpython_only, captured_stdout, +- check_disallow_instantiation, is_emscripten, is_wasi) ++ check_disallow_instantiation, is_emscripten, is_wasi, ++ SHORT_TIMEOUT) + import locale + import re + import string +@@ -11,6 +12,14 @@ + from re import Scanner + from weakref import proxy + ++# some platforms lack working multiprocessing ++try: ++ import _multiprocessing ++except ImportError: ++ multiprocessing = None ++else: ++ import multiprocessing ++ + # Misc tests from Tim Peters' re.doc + + # WARNING: Don't change details in these tests if you don't know +@@ -1796,12 +1805,9 @@ def test_dealloc(self): + long_overflow = 2**128 + self.assertRaises(TypeError, re.finditer, "a", {}) + with self.assertRaises(OverflowError): +- _sre.compile("abc", 0, [long_overflow], 0, {}, (), 0) ++ _sre.compile("abc", 0, [long_overflow], 0, {}, ()) + with self.assertRaises(TypeError): +- _sre.compile({}, 0, [], 0, [], [], 0) +- with self.assertRaises(RuntimeError): +- # invalid repeat_count -1 +- _sre.compile("abc", 0, [1], 0, {}, (), -1) ++ _sre.compile({}, 0, [], 0, [], []) + + def test_search_dot_unicode(self): + self.assertTrue(re.search("123.*-", '123abc-')) +@@ -2441,6 +2447,26 @@ def test_template_function_and_flag_is_deprecated(self): + self.assertTrue(template_re1.match('ahoy')) + self.assertFalse(template_re1.match('nope')) + ++ @unittest.skipIf(multiprocessing is None, 'test requires multiprocessing') ++ def test_regression_gh94675(self): ++ pattern = re.compile(r'(?<=[({}])(((//[^\n]*)?[\n])([\000-\040])*)*' ++ r'((/[^/\[\n]*(([^\n]|(\[\n]*(]*)*\]))' ++ r'[^/\[]*)*/))((((//[^\n]*)?[\n])' ++ r'([\000-\040]|(/\*[^*]*\*+' ++ r'([^/*]\*+)*/))*)+(?=[^\000-\040);\]}]))') ++ input_js = '''a(function() { ++ /////////////////////////////////////////////////////////////////// ++ });''' ++ p = multiprocessing.Process(target=pattern.sub, args=('', input_js)) ++ p.start() ++ p.join(SHORT_TIMEOUT) ++ try: ++ self.assertFalse(p.is_alive(), 'pattern.sub() timed out') ++ finally: ++ if p.is_alive(): ++ p.terminate() ++ p.join() ++ + + def get_debug_out(pat): + with captured_stdout() as out: +@@ -2540,27 +2566,6 @@ def test_possesive_repeat(self): + 14. SUCCESS + ''') + +- def test_repeat_index(self): +- self.assertEqual(get_debug_out(r'(?:ab)*?(?:cd)*'), '''\ +-MIN_REPEAT 0 MAXREPEAT +- LITERAL 97 +- LITERAL 98 +-MAX_REPEAT 0 MAXREPEAT +- LITERAL 99 +- LITERAL 100 +- +- 0. INFO 4 0b0 0 MAXREPEAT (to 5) +- 5: REPEAT 8 0 MAXREPEAT 0 (to 14) +-10. LITERAL 0x61 ('a') +-12. LITERAL 0x62 ('b') +-14: MIN_UNTIL +-15. REPEAT 8 0 MAXREPEAT 1 (to 24) +-20. LITERAL 0x63 ('c') +-22. LITERAL 0x64 ('d') +-24: MAX_UNTIL +-25. SUCCESS +-''') +- + + class PatternReprTests(unittest.TestCase): + def check(self, pattern, expected): +diff --git a/Misc/NEWS.d/next/Library/2022-06-15-21-35-11.gh-issue-91404.39TZzW.rst b/Misc/NEWS.d/next/Library/2022-06-15-21-35-11.gh-issue-91404.39TZzW.rst +new file mode 100644 +index 0000000000..e20b15c7b7 +--- /dev/null ++++ b/Misc/NEWS.d/next/Library/2022-06-15-21-35-11.gh-issue-91404.39TZzW.rst +@@ -0,0 +1,3 @@ ++Revert the :mod:`re` memory leak when a match is terminated by a signal or ++memory allocation failure as the implemented fix caused a major performance ++regression. +diff --git a/Misc/NEWS.d/next/Tests/2022-07-08-12-22-00.gh-issue-94675.IiTs5f.rst b/Misc/NEWS.d/next/Tests/2022-07-08-12-22-00.gh-issue-94675.IiTs5f.rst +new file mode 100644 +index 0000000000..d0005d9f60 +--- /dev/null ++++ b/Misc/NEWS.d/next/Tests/2022-07-08-12-22-00.gh-issue-94675.IiTs5f.rst +@@ -0,0 +1 @@ ++Add a regression test for :mod:`re` exponentional slowdown when using rjsmin. +diff --git a/Modules/_sre/clinic/sre.c.h b/Modules/_sre/clinic/sre.c.h +index e243c756e1..048a494f1b 100644 +--- a/Modules/_sre/clinic/sre.c.h ++++ b/Modules/_sre/clinic/sre.c.h +@@ -764,7 +764,7 @@ PyDoc_STRVAR(_sre_SRE_Pattern___deepcopy____doc__, + + PyDoc_STRVAR(_sre_compile__doc__, + "compile($module, /, pattern, flags, code, groups, groupindex,\n" +-" indexgroup, repeat_count)\n" ++" indexgroup)\n" + "--\n" + "\n"); + +@@ -774,24 +774,23 @@ PyDoc_STRVAR(_sre_compile__doc__, + static PyObject * + _sre_compile_impl(PyObject *module, PyObject *pattern, int flags, + PyObject *code, Py_ssize_t groups, PyObject *groupindex, +- PyObject *indexgroup, Py_ssize_t repeat_count); ++ PyObject *indexgroup); + + static PyObject * + _sre_compile(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) + { + PyObject *return_value = NULL; +- static const char * const _keywords[] = {"pattern", "flags", "code", "groups", "groupindex", "indexgroup", "repeat_count", NULL}; ++ static const char * const _keywords[] = {"pattern", "flags", "code", "groups", "groupindex", "indexgroup", NULL}; + static _PyArg_Parser _parser = {NULL, _keywords, "compile", 0}; +- PyObject *argsbuf[7]; ++ PyObject *argsbuf[6]; + PyObject *pattern; + int flags; + PyObject *code; + Py_ssize_t groups; + PyObject *groupindex; + PyObject *indexgroup; +- Py_ssize_t repeat_count; + +- args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 7, 7, 0, argsbuf); ++ args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 6, 6, 0, argsbuf); + if (!args) { + goto exit; + } +@@ -827,19 +826,7 @@ _sre_compile(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject + goto exit; + } + indexgroup = args[5]; +- { +- Py_ssize_t ival = -1; +- PyObject *iobj = _PyNumber_Index(args[6]); +- if (iobj != NULL) { +- ival = PyLong_AsSsize_t(iobj); +- Py_DECREF(iobj); +- } +- if (ival == -1 && PyErr_Occurred()) { +- goto exit; +- } +- repeat_count = ival; +- } +- return_value = _sre_compile_impl(module, pattern, flags, code, groups, groupindex, indexgroup, repeat_count); ++ return_value = _sre_compile_impl(module, pattern, flags, code, groups, groupindex, indexgroup); + + exit: + return return_value; +@@ -1129,4 +1116,4 @@ _sre_SRE_Scanner_search(ScannerObject *self, PyTypeObject *cls, PyObject *const + } + return _sre_SRE_Scanner_search_impl(self, cls); + } +-/*[clinic end generated code: output=97e7ce058366760b input=a9049054013a1b77]*/ ++/*[clinic end generated code: output=fd2f45c941620e6e input=a9049054013a1b77]*/ +diff --git a/Modules/_sre/sre.c b/Modules/_sre/sre.c +index 491734f243..0a7019a085 100644 +--- a/Modules/_sre/sre.c ++++ b/Modules/_sre/sre.c +@@ -427,12 +427,6 @@ state_init(SRE_STATE* state, PatternObject* pattern, PyObject* string, + state->lastmark = -1; + state->lastindex = -1; + +- state->repeats_array = PyMem_New(SRE_REPEAT, pattern->repeat_count); +- if (!state->repeats_array) { +- PyErr_NoMemory(); +- goto err; +- } +- + state->buffer.buf = NULL; + ptr = getstring(string, &length, &isbytes, &charsize, &state->buffer); + if (!ptr) +@@ -482,9 +476,6 @@ state_init(SRE_STATE* state, PatternObject* pattern, PyObject* string, + safely casted to `void*`, see bpo-39943 for details. */ + PyMem_Free((void*) state->mark); + state->mark = NULL; +- PyMem_Free(state->repeats_array); +- state->repeats_array = NULL; +- + if (state->buffer.buf) + PyBuffer_Release(&state->buffer); + return NULL; +@@ -500,8 +491,6 @@ state_fini(SRE_STATE* state) + /* See above PyMem_Del for why we explicitly cast here. */ + PyMem_Free((void*) state->mark); + state->mark = NULL; +- PyMem_Free(state->repeats_array); +- state->repeats_array = NULL; + } + + /* calculate offset from start of string */ +@@ -1418,15 +1407,14 @@ _sre.compile + groups: Py_ssize_t + groupindex: object(subclass_of='&PyDict_Type') + indexgroup: object(subclass_of='&PyTuple_Type') +- repeat_count: Py_ssize_t + + [clinic start generated code]*/ + + static PyObject * + _sre_compile_impl(PyObject *module, PyObject *pattern, int flags, + PyObject *code, Py_ssize_t groups, PyObject *groupindex, +- PyObject *indexgroup, Py_ssize_t repeat_count) +-/*[clinic end generated code: output=922af562d51b1657 input=77e39c322501ec2a]*/ ++ PyObject *indexgroup) ++/*[clinic end generated code: output=ef9c2b3693776404 input=0a68476dbbe5db30]*/ + { + /* "compile" pattern descriptor to pattern object */ + +@@ -1484,8 +1472,8 @@ _sre_compile_impl(PyObject *module, PyObject *pattern, int flags, + self->pattern = pattern; + + self->flags = flags; ++ + self->groups = groups; +- self->repeat_count = repeat_count; + + if (PyDict_GET_SIZE(groupindex) > 0) { + Py_INCREF(groupindex); +@@ -1657,7 +1645,7 @@ _validate_charset(SRE_CODE *code, SRE_CODE *end) + } + + static int +-_validate_inner(SRE_CODE *code, SRE_CODE *end, PatternObject *self) ++_validate_inner(SRE_CODE *code, SRE_CODE *end, Py_ssize_t groups) + { + /* Some variables are manipulated by the macros above */ + SRE_CODE op; +@@ -1678,8 +1666,8 @@ _validate_inner(SRE_CODE *code, SRE_CODE *end, PatternObject *self) + sre_match() code is robust even if they don't, and the worst + you can get is nonsensical match results. */ + GET_ARG; +- if (arg > 2 * (size_t)self->groups + 1) { +- VTRACE(("arg=%d, groups=%d\n", (int)arg, (int)self->groups)); ++ if (arg > 2 * (size_t)groups + 1) { ++ VTRACE(("arg=%d, groups=%d\n", (int)arg, (int)groups)); + FAIL; + } + break; +@@ -1808,7 +1796,7 @@ _validate_inner(SRE_CODE *code, SRE_CODE *end, PatternObject *self) + if (skip == 0) + break; + /* Stop 2 before the end; we check the JUMP below */ +- if (!_validate_inner(code, code+skip-3, self)) ++ if (!_validate_inner(code, code+skip-3, groups)) + FAIL; + code += skip-3; + /* Check that it ends with a JUMP, and that each JUMP +@@ -1837,7 +1825,7 @@ _validate_inner(SRE_CODE *code, SRE_CODE *end, PatternObject *self) + FAIL; + if (max > SRE_MAXREPEAT) + FAIL; +- if (!_validate_inner(code, code+skip-4, self)) ++ if (!_validate_inner(code, code+skip-4, groups)) + FAIL; + code += skip-4; + GET_OP; +@@ -1849,7 +1837,7 @@ _validate_inner(SRE_CODE *code, SRE_CODE *end, PatternObject *self) + case SRE_OP_REPEAT: + case SRE_OP_POSSESSIVE_REPEAT: + { +- SRE_CODE op1 = op, min, max, repeat_index; ++ SRE_CODE op1 = op, min, max; + GET_SKIP; + GET_ARG; min = arg; + GET_ARG; max = arg; +@@ -1857,17 +1845,9 @@ _validate_inner(SRE_CODE *code, SRE_CODE *end, PatternObject *self) + FAIL; + if (max > SRE_MAXREPEAT) + FAIL; +- if (op1 == SRE_OP_REPEAT) { +- GET_ARG; repeat_index = arg; +- if (repeat_index >= (size_t)self->repeat_count) +- FAIL; +- skip -= 4; +- } else { +- skip -= 3; +- } +- if (!_validate_inner(code, code+skip, self)) ++ if (!_validate_inner(code, code+skip-3, groups)) + FAIL; +- code += skip; ++ code += skip-3; + GET_OP; + if (op1 == SRE_OP_POSSESSIVE_REPEAT) { + if (op != SRE_OP_SUCCESS) +@@ -1883,7 +1863,7 @@ _validate_inner(SRE_CODE *code, SRE_CODE *end, PatternObject *self) + case SRE_OP_ATOMIC_GROUP: + { + GET_SKIP; +- if (!_validate_inner(code, code+skip-2, self)) ++ if (!_validate_inner(code, code+skip-2, groups)) + FAIL; + code += skip-2; + GET_OP; +@@ -1897,7 +1877,7 @@ _validate_inner(SRE_CODE *code, SRE_CODE *end, PatternObject *self) + case SRE_OP_GROUPREF_UNI_IGNORE: + case SRE_OP_GROUPREF_LOC_IGNORE: + GET_ARG; +- if (arg >= (size_t)self->groups) ++ if (arg >= (size_t)groups) + FAIL; + break; + +@@ -1906,7 +1886,7 @@ _validate_inner(SRE_CODE *code, SRE_CODE *end, PatternObject *self) + 'group' is either an integer group number or a group name, + 'then' and 'else' are sub-regexes, and 'else' is optional. */ + GET_ARG; +- if (arg >= (size_t)self->groups) ++ if (arg >= (size_t)groups) + FAIL; + GET_SKIP_ADJ(1); + code--; /* The skip is relative to the first arg! */ +@@ -1939,17 +1919,17 @@ _validate_inner(SRE_CODE *code, SRE_CODE *end, PatternObject *self) + code[skip-3] == SRE_OP_JUMP) + { + VTRACE(("both then and else parts present\n")); +- if (!_validate_inner(code+1, code+skip-3, self)) ++ if (!_validate_inner(code+1, code+skip-3, groups)) + FAIL; + code += skip-2; /* Position after JUMP, at */ + GET_SKIP; +- if (!_validate_inner(code, code+skip-1, self)) ++ if (!_validate_inner(code, code+skip-1, groups)) + FAIL; + code += skip-1; + } + else { + VTRACE(("only a then part present\n")); +- if (!_validate_inner(code+1, code+skip-1, self)) ++ if (!_validate_inner(code+1, code+skip-1, groups)) + FAIL; + code += skip-1; + } +@@ -1963,7 +1943,7 @@ _validate_inner(SRE_CODE *code, SRE_CODE *end, PatternObject *self) + if (arg & 0x80000000) + FAIL; /* Width too large */ + /* Stop 1 before the end; we check the SUCCESS below */ +- if (!_validate_inner(code+1, code+skip-2, self)) ++ if (!_validate_inner(code+1, code+skip-2, groups)) + FAIL; + code += skip-2; + GET_OP; +@@ -1982,19 +1962,18 @@ _validate_inner(SRE_CODE *code, SRE_CODE *end, PatternObject *self) + } + + static int +-_validate_outer(SRE_CODE *code, SRE_CODE *end, PatternObject *self) ++_validate_outer(SRE_CODE *code, SRE_CODE *end, Py_ssize_t groups) + { +- if (self->groups < 0 || (size_t)self->groups > SRE_MAXGROUPS || +- self->repeat_count < 0 || ++ if (groups < 0 || (size_t)groups > SRE_MAXGROUPS || + code >= end || end[-1] != SRE_OP_SUCCESS) + FAIL; +- return _validate_inner(code, end-1, self); ++ return _validate_inner(code, end-1, groups); + } + + static int + _validate(PatternObject *self) + { +- if (!_validate_outer(self->code, self->code+self->codesize, self)) ++ if (!_validate_outer(self->code, self->code+self->codesize, self->groups)) + { + PyErr_SetString(PyExc_RuntimeError, "invalid SRE code"); + return 0; +diff --git a/Modules/_sre/sre.h b/Modules/_sre/sre.h +index aff064d343..52ae3e11b5 100644 +--- a/Modules/_sre/sre.h ++++ b/Modules/_sre/sre.h +@@ -29,8 +29,6 @@ typedef struct { + Py_ssize_t groups; /* must be first! */ + PyObject* groupindex; /* dict */ + PyObject* indexgroup; /* tuple */ +- /* the number of REPEATs */ +- Py_ssize_t repeat_count; + /* compatibility */ + PyObject* pattern; /* pattern source (or None) */ + int flags; /* flags used when compiling pattern source */ +@@ -85,8 +83,6 @@ typedef struct { + size_t data_stack_base; + /* current repeat context */ + SRE_REPEAT *repeat; +- /* repeat contexts array */ +- SRE_REPEAT *repeats_array; + } SRE_STATE; + + typedef struct { +diff --git a/Modules/_sre/sre_constants.h b/Modules/_sre/sre_constants.h +index 590d5be7cb..c633514736 100644 +--- a/Modules/_sre/sre_constants.h ++++ b/Modules/_sre/sre_constants.h +@@ -11,7 +11,7 @@ + * See the sre.c file for information on usage and redistribution. + */ + +-#define SRE_MAGIC 20220423 ++#define SRE_MAGIC 20220615 + #define SRE_OP_FAILURE 0 + #define SRE_OP_SUCCESS 1 + #define SRE_OP_ANY 2 +diff --git a/Modules/_sre/sre_lib.h b/Modules/_sre/sre_lib.h +index 1e5b50170a..fb4c18b63d 100644 +--- a/Modules/_sre/sre_lib.h ++++ b/Modules/_sre/sre_lib.h +@@ -1079,12 +1079,17 @@ SRE(match)(SRE_STATE* state, const SRE_CODE* pattern, int toplevel) + by the UNTIL operator (MAX_UNTIL, MIN_UNTIL) */ + /* <1=min> <2=max> + <3=repeat_index> item tail */ +- TRACE(("|%p|%p|REPEAT %d %d %d\n", pattern, ptr, +- pattern[1], pattern[2], pattern[3])); +- +- /* install repeat context */ +- ctx->u.rep = &state->repeats_array[pattern[3]]; ++ TRACE(("|%p|%p|REPEAT %d %d\n", pattern, ptr, ++ pattern[1], pattern[2])); + ++ /* install new repeat context */ ++ /* TODO(https://github.com/python/cpython/issues/67877): Fix this ++ * potential memory leak. */ ++ ctx->u.rep = (SRE_REPEAT*) PyObject_Malloc(sizeof(*ctx->u.rep)); ++ if (!ctx->u.rep) { ++ PyErr_NoMemory(); ++ RETURN_FAILURE; ++ } + ctx->u.rep->count = -1; + ctx->u.rep->pattern = pattern; + ctx->u.rep->prev = state->repeat; +@@ -1094,6 +1099,7 @@ SRE(match)(SRE_STATE* state, const SRE_CODE* pattern, int toplevel) + state->ptr = ptr; + DO_JUMP(JUMP_REPEAT, jump_repeat, pattern+pattern[0]); + state->repeat = ctx->u.rep->prev; ++ PyObject_Free(ctx->u.rep); + + if (ret) { + RETURN_ON_ERROR(ret); +@@ -1103,8 +1109,7 @@ SRE(match)(SRE_STATE* state, const SRE_CODE* pattern, int toplevel) + + TARGET(SRE_OP_MAX_UNTIL): + /* maximizing repeat */ +- /* <1=min> <2=max> +- <3=repeat_index> item tail */ ++ /* <1=min> <2=max> item tail */ + + /* FIXME: we probably need to deal with zero-width + matches in here... */ +@@ -1124,7 +1129,7 @@ SRE(match)(SRE_STATE* state, const SRE_CODE* pattern, int toplevel) + /* not enough matches */ + ctx->u.rep->count = ctx->count; + DO_JUMP(JUMP_MAX_UNTIL_1, jump_max_until_1, +- ctx->u.rep->pattern+4); ++ ctx->u.rep->pattern+3); + if (ret) { + RETURN_ON_ERROR(ret); + RETURN_SUCCESS; +@@ -1146,7 +1151,7 @@ SRE(match)(SRE_STATE* state, const SRE_CODE* pattern, int toplevel) + DATA_PUSH(&ctx->u.rep->last_ptr); + ctx->u.rep->last_ptr = state->ptr; + DO_JUMP(JUMP_MAX_UNTIL_2, jump_max_until_2, +- ctx->u.rep->pattern+4); ++ ctx->u.rep->pattern+3); + DATA_POP(&ctx->u.rep->last_ptr); + if (ret) { + MARK_POP_DISCARD(ctx->lastmark); +@@ -1171,8 +1176,7 @@ SRE(match)(SRE_STATE* state, const SRE_CODE* pattern, int toplevel) + + TARGET(SRE_OP_MIN_UNTIL): + /* minimizing repeat */ +- /* <1=min> <2=max> +- <3=repeat_index> item tail */ ++ /* <1=min> <2=max> item tail */ + + ctx->u.rep = state->repeat; + if (!ctx->u.rep) +@@ -1189,7 +1193,7 @@ SRE(match)(SRE_STATE* state, const SRE_CODE* pattern, int toplevel) + /* not enough matches */ + ctx->u.rep->count = ctx->count; + DO_JUMP(JUMP_MIN_UNTIL_1, jump_min_until_1, +- ctx->u.rep->pattern+4); ++ ctx->u.rep->pattern+3); + if (ret) { + RETURN_ON_ERROR(ret); + RETURN_SUCCESS; +@@ -1232,7 +1236,7 @@ SRE(match)(SRE_STATE* state, const SRE_CODE* pattern, int toplevel) + DATA_PUSH(&ctx->u.rep->last_ptr); + ctx->u.rep->last_ptr = state->ptr; + DO_JUMP(JUMP_MIN_UNTIL_3,jump_min_until_3, +- ctx->u.rep->pattern+4); ++ ctx->u.rep->pattern+3); + DATA_POP(&ctx->u.rep->last_ptr); + if (ret) { + RETURN_ON_ERROR(ret); diff --git a/python3.11.spec b/python3.11.spec index 7fdecbb..5040d95 100644 --- a/python3.11.spec +++ b/python3.11.spec @@ -17,7 +17,7 @@ URL: https://www.python.org/ %global prerel b3 %global upstream_version %{general_version}%{?prerel} Version: %{general_version}%{?prerel:~%{prerel}} -Release: 6%{?dist} +Release: 7%{?dist} License: Python @@ -59,7 +59,7 @@ License: Python # IMPORTANT: When bootstrapping, it's very likely the wheels for pip and # setuptools are not available. Turn off the rpmwheels bcond until # the two packages are built with wheels to get around the issue. -%bcond_with bootstrap +%bcond_without bootstrap # Whether to use RPM build wheels from the python-{pip,setuptools}-wheel package # Uses upstream bundled prebuilt wheels otherwise @@ -339,6 +339,23 @@ Patch383: 00383-gh-93442-make-c-version-of-_py_cast-work-with-0-null.patch # gh-94028: Clear and reset sqlite3 statements properly in cursor iternext (GH-94042) Patch384: 00384-gh-94028-clear-and-reset-sqlite3-statements-properly-in-cursor-iternext-gh-94042.patch +# 00385 # 8696ca2373ef3d7595dfb62e2b63180621f40d5d +# gh-91404: Revert "bpo-23689: re module, fix memory leak..." +# +# This fixes a speed regression in the re module +# which prevented chromium from building in Fedora. +# +# Revert "bpo-23689: re module, fix memory leak when a match is terminated by a signal or memory allocation failure" +# +# This reverts commit 6e3eee5c11b539e9aab39cff783acf57838c355a. +# +# Manual fixups to increase the MAGIC number and to handle conflicts with +# a couple of changes that landed after that. +# +# +# gh-94675: Add a regression test for rjsmin re slowdown +Patch385: 00385-gh-91404-revert-bpo-23689-re-module-fix-memory-leak.patch + # (New patches go here ^^^) # # When adding new patches to "python" and "python3" in Fedora, EL, etc., @@ -1611,6 +1628,9 @@ CheckPython optimized # ====================================================== %changelog +* Fri Jul 08 2022 Miro Hrončok - 3.11.0~b3-7 +- Fix speed regression in the re module which prevented chromium from building + * Fri Jun 24 2022 Tomáš Hrnčiar - 3.11.0~b3-6 - Clear and reset sqlite3 statements properly in cursor iternext (fixes rhbz#2099049) - Revert a problematic fix of threading._shutdown() again (fixes rhbz#2100282) From c7432171d061da43dd9d7f2b03825bd2b7963143 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Sat, 9 Jul 2022 01:23:18 +0200 Subject: [PATCH 036/118] Finish bootstrap of the re module speed regression fix --- python3.11.spec | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/python3.11.spec b/python3.11.spec index 5040d95..a70ebd7 100644 --- a/python3.11.spec +++ b/python3.11.spec @@ -17,7 +17,7 @@ URL: https://www.python.org/ %global prerel b3 %global upstream_version %{general_version}%{?prerel} Version: %{general_version}%{?prerel:~%{prerel}} -Release: 7%{?dist} +Release: 8%{?dist} License: Python @@ -59,7 +59,7 @@ License: Python # IMPORTANT: When bootstrapping, it's very likely the wheels for pip and # setuptools are not available. Turn off the rpmwheels bcond until # the two packages are built with wheels to get around the issue. -%bcond_without bootstrap +%bcond_with bootstrap # Whether to use RPM build wheels from the python-{pip,setuptools}-wheel package # Uses upstream bundled prebuilt wheels otherwise @@ -1628,6 +1628,9 @@ CheckPython optimized # ====================================================== %changelog +* Fri Jul 08 2022 Miro Hrončok - 3.11.0~b3-8 +- Finish bootstrap of the re module speed regression fix + * Fri Jul 08 2022 Miro Hrončok - 3.11.0~b3-7 - Fix speed regression in the re module which prevented chromium from building From b2d80045f9ee94e83ec6ce65e44fc95f86f33a69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Tue, 12 Jul 2022 00:50:26 +0200 Subject: [PATCH 037/118] Update to 3.11.0b4 Patches 383 and 384 were merged upstream. Patch 385 was partially merged upstream, the PR with test is still open. --- 00251-change-user-install-location.patch | 10 +- 00328-pyc-timestamp-invalidation-mode.patch | 2 +- ...version-of-_py_cast-work-with-0-null.patch | 82 -- ...properly-in-cursor-iternext-gh-94042.patch | 90 --- ...-bpo-23689-re-module-fix-memory-leak.patch | 746 ------------------ ...gression-test-for-rjsmin-re-slowdown.patch | 77 ++ python3.11.spec | 42 +- sources | 4 +- 8 files changed, 95 insertions(+), 958 deletions(-) delete mode 100644 00383-gh-93442-make-c-version-of-_py_cast-work-with-0-null.patch delete mode 100644 00384-gh-94028-clear-and-reset-sqlite3-statements-properly-in-cursor-iternext-gh-94042.patch delete mode 100644 00385-gh-91404-revert-bpo-23689-re-module-fix-memory-leak.patch create mode 100644 00385-gh-94675-add-a-regression-test-for-rjsmin-re-slowdown.patch diff --git a/00251-change-user-install-location.patch b/00251-change-user-install-location.patch index 9948b58..7926cfc 100644 --- a/00251-change-user-install-location.patch +++ b/00251-change-user-install-location.patch @@ -33,7 +33,7 @@ Co-authored-by: Lumír Balhar 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/Lib/site.py b/Lib/site.py -index b11cd48e69..63ddd5b21b 100644 +index 69670d9d7f..104cb93899 100644 --- a/Lib/site.py +++ b/Lib/site.py @@ -377,8 +377,15 @@ def getsitepackages(prefixes=None): @@ -54,7 +54,7 @@ index b11cd48e69..63ddd5b21b 100644 if os.path.isdir(sitedir): addsitedir(sitedir, known_paths) diff --git a/Lib/sysconfig.py b/Lib/sysconfig.py -index e21b7303fe..37b04452bc 100644 +index ebe3711827..dca8aa89b6 100644 --- a/Lib/sysconfig.py +++ b/Lib/sysconfig.py @@ -103,6 +103,25 @@ @@ -84,10 +84,10 @@ index e21b7303fe..37b04452bc 100644 # NOTE: site.py has copy of this function. # Sync it when modify this function. diff --git a/Lib/test/test_sysconfig.py b/Lib/test/test_sysconfig.py -index f2b93706b2..cc58f47cdb 100644 +index 578ac1db50..e78ff15ad3 100644 --- a/Lib/test/test_sysconfig.py +++ b/Lib/test/test_sysconfig.py -@@ -333,7 +333,7 @@ def test_get_config_h_filename(self): +@@ -336,7 +336,7 @@ def test_get_config_h_filename(self): self.assertTrue(os.path.isfile(config_h), config_h) def test_get_scheme_names(self): @@ -96,7 +96,7 @@ index f2b93706b2..cc58f47cdb 100644 if HAS_USER_BASE: wanted.extend(['nt_user', 'osx_framework_user', 'posix_user']) self.assertEqual(get_scheme_names(), tuple(sorted(wanted))) -@@ -345,6 +345,8 @@ def test_symlink(self): # Issue 7880 +@@ -348,6 +348,8 @@ def test_symlink(self): # Issue 7880 cmd = "-c", "import sysconfig; print(sysconfig.get_platform())" self.assertEqual(py.call_real(*cmd), py.call_link(*cmd)) diff --git a/00328-pyc-timestamp-invalidation-mode.patch b/00328-pyc-timestamp-invalidation-mode.patch index 2ed7d8d..d04a267 100644 --- a/00328-pyc-timestamp-invalidation-mode.patch +++ b/00328-pyc-timestamp-invalidation-mode.patch @@ -33,7 +33,7 @@ index 388614e51b..db52725016 100644 else: return PycInvalidationMode.TIMESTAMP diff --git a/Lib/test/test_py_compile.py b/Lib/test/test_py_compile.py -index 794d6436b6..322e072b61 100644 +index a4a52b180d..e53f5d92aa 100644 --- a/Lib/test/test_py_compile.py +++ b/Lib/test/test_py_compile.py @@ -19,6 +19,7 @@ def without_source_date_epoch(fxn): diff --git a/00383-gh-93442-make-c-version-of-_py_cast-work-with-0-null.patch b/00383-gh-93442-make-c-version-of-_py_cast-work-with-0-null.patch deleted file mode 100644 index a67c60d..0000000 --- a/00383-gh-93442-make-c-version-of-_py_cast-work-with-0-null.patch +++ /dev/null @@ -1,82 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: "Miss Islington (bot)" - <31488909+miss-islington@users.noreply.github.com> -Date: Sat, 4 Jun 2022 22:15:59 -0700 -Subject: [PATCH] 00383: gh-93442: Make C++ version of _Py_CAST work with - 0/NULL -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Add C++ overloads for _Py_CAST_impl() to handle 0/NULL. This will allow -C++ extensions that pass 0 or NULL to macros using _Py_CAST() to -continue to compile. Without this, you get an error like: - - invalid ‘static_cast’ from type ‘int’ to type ‘_object*’ - -The modern way to use a NULL value in C++ is to use nullptr. However, -we want to not break extensions that do things the old way. - -Co-authored-by: serge-sans-paille -(cherry picked from commit 8bcc3fa3453e28511d04eaa0aa7d8e1a3495d518) - -Co-authored-by: Neil Schemenauer ---- - Include/pyport.h | 14 ++++++++++++++ - Lib/test/_testcppext.cpp | 4 ++++ - .../2022-06-04-13-15-41.gh-issue-93442.4M4NDb.rst | 3 +++ - 3 files changed, 21 insertions(+) - create mode 100644 Misc/NEWS.d/next/C API/2022-06-04-13-15-41.gh-issue-93442.4M4NDb.rst - -diff --git a/Include/pyport.h b/Include/pyport.h -index 5a9adf162b..a78e290931 100644 ---- a/Include/pyport.h -+++ b/Include/pyport.h -@@ -24,9 +24,23 @@ - // - // The type argument must not be a constant type. - #ifdef __cplusplus -+#include - # define _Py_STATIC_CAST(type, expr) static_cast(expr) - extern "C++" { - namespace { -+ template -+ inline type _Py_CAST_impl(long int ptr) { -+ return reinterpret_cast(ptr); -+ } -+ template -+ inline type _Py_CAST_impl(int ptr) { -+ return reinterpret_cast(ptr); -+ } -+ template -+ inline type _Py_CAST_impl(std::nullptr_t) { -+ return static_cast(nullptr); -+ } -+ - template - inline type _Py_CAST_impl(expr_type *expr) { - return reinterpret_cast(expr); -diff --git a/Lib/test/_testcppext.cpp b/Lib/test/_testcppext.cpp -index eade7ccdaa..70f434e678 100644 ---- a/Lib/test/_testcppext.cpp -+++ b/Lib/test/_testcppext.cpp -@@ -74,6 +74,10 @@ test_api_casts(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args)) - Py_INCREF(strong_ref); - Py_DECREF(strong_ref); - -+ // gh-93442: Pass 0 as NULL for PyObject* -+ Py_XINCREF(0); -+ Py_XDECREF(0); -+ - Py_DECREF(obj); - Py_RETURN_NONE; - } -diff --git a/Misc/NEWS.d/next/C API/2022-06-04-13-15-41.gh-issue-93442.4M4NDb.rst b/Misc/NEWS.d/next/C API/2022-06-04-13-15-41.gh-issue-93442.4M4NDb.rst -new file mode 100644 -index 0000000000..f48ed37c81 ---- /dev/null -+++ b/Misc/NEWS.d/next/C API/2022-06-04-13-15-41.gh-issue-93442.4M4NDb.rst -@@ -0,0 +1,3 @@ -+Add C++ overloads for _Py_CAST_impl() to handle 0/NULL. This will allow C++ -+extensions that pass 0 or NULL to macros using _Py_CAST() to continue to -+compile. diff --git a/00384-gh-94028-clear-and-reset-sqlite3-statements-properly-in-cursor-iternext-gh-94042.patch b/00384-gh-94028-clear-and-reset-sqlite3-statements-properly-in-cursor-iternext-gh-94042.patch deleted file mode 100644 index a2ce195..0000000 --- a/00384-gh-94028-clear-and-reset-sqlite3-statements-properly-in-cursor-iternext-gh-94042.patch +++ /dev/null @@ -1,90 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Erlend Egeberg Aasland -Date: Tue, 21 Jun 2022 13:30:29 +0200 -Subject: [PATCH] 00384: gh-94028: Clear and reset sqlite3 statements properly - in cursor iternext (GH-94042) - ---- - Lib/test/test_sqlite3/test_transactions.py | 39 +++++++++++++++++++ - ...2-06-20-23-14-43.gh-issue-94028.UofEcX.rst | 3 ++ - Modules/_sqlite/cursor.c | 3 ++ - 3 files changed, 45 insertions(+) - create mode 100644 Misc/NEWS.d/next/Library/2022-06-20-23-14-43.gh-issue-94028.UofEcX.rst - -diff --git a/Lib/test/test_sqlite3/test_transactions.py b/Lib/test/test_sqlite3/test_transactions.py -index 040ab1ee60..226a1d03fa 100644 ---- a/Lib/test/test_sqlite3/test_transactions.py -+++ b/Lib/test/test_sqlite3/test_transactions.py -@@ -141,6 +141,45 @@ def test_rollback_cursor_consistency(self): - con.rollback() - self.assertEqual(cur.fetchall(), [(1,), (2,), (3,)]) - -+ def test_multiple_cursors_and_iternext(self): -+ # gh-94028: statements are cleared and reset in cursor iternext. -+ -+ # Provoke the gh-94028 by using a cursor cache. -+ CURSORS = {} -+ def sql(cx, sql, *args): -+ cu = cx.cursor() -+ cu.execute(sql, args) -+ CURSORS[id(sql)] = cu -+ return cu -+ -+ self.con1.execute("create table t(t)") -+ sql(self.con1, "insert into t values (?), (?), (?)", "u1", "u2", "u3") -+ self.con1.commit() -+ -+ # On second connection, verify rows are visible, then delete them. -+ count = sql(self.con2, "select count(*) from t").fetchone()[0] -+ self.assertEqual(count, 3) -+ changes = sql(self.con2, "delete from t").rowcount -+ self.assertEqual(changes, 3) -+ self.con2.commit() -+ -+ # Back in original connection, create 2 new users. -+ sql(self.con1, "insert into t values (?)", "u4") -+ sql(self.con1, "insert into t values (?)", "u5") -+ -+ # The second connection cannot see uncommitted changes. -+ count = sql(self.con2, "select count(*) from t").fetchone()[0] -+ self.assertEqual(count, 0) -+ -+ # First connection can see its own changes. -+ count = sql(self.con1, "select count(*) from t").fetchone()[0] -+ self.assertEqual(count, 2) -+ -+ # The second connection can now see the changes. -+ self.con1.commit() -+ count = sql(self.con2, "select count(*) from t").fetchone()[0] -+ self.assertEqual(count, 2) -+ - - class RollbackTests(unittest.TestCase): - """bpo-44092: sqlite3 now leaves it to SQLite to resolve rollback issues""" -diff --git a/Misc/NEWS.d/next/Library/2022-06-20-23-14-43.gh-issue-94028.UofEcX.rst b/Misc/NEWS.d/next/Library/2022-06-20-23-14-43.gh-issue-94028.UofEcX.rst -new file mode 100644 -index 0000000000..5775b2276d ---- /dev/null -+++ b/Misc/NEWS.d/next/Library/2022-06-20-23-14-43.gh-issue-94028.UofEcX.rst -@@ -0,0 +1,3 @@ -+Fix a regression in the :mod:`sqlite3` where statement objects were not -+properly cleared and reset after use in cursor iters. The regression was -+introduced by PR 27884 in Python 3.11a1. Patch by Erlend E. Aasland. -diff --git a/Modules/_sqlite/cursor.c b/Modules/_sqlite/cursor.c -index c58def5f03..8048d83683 100644 ---- a/Modules/_sqlite/cursor.c -+++ b/Modules/_sqlite/cursor.c -@@ -1126,10 +1126,13 @@ pysqlite_cursor_iternext(pysqlite_Cursor *self) - int rc = stmt_step(stmt); - if (rc == SQLITE_DONE) { - (void)stmt_reset(self->statement); -+ Py_CLEAR(self->statement); - } - else if (rc != SQLITE_ROW) { - (void)_pysqlite_seterror(self->connection->state, - self->connection->db); -+ (void)stmt_reset(self->statement); -+ Py_CLEAR(self->statement); - Py_DECREF(row); - return NULL; - } diff --git a/00385-gh-91404-revert-bpo-23689-re-module-fix-memory-leak.patch b/00385-gh-91404-revert-bpo-23689-re-module-fix-memory-leak.patch deleted file mode 100644 index e7c2136..0000000 --- a/00385-gh-91404-revert-bpo-23689-re-module-fix-memory-leak.patch +++ /dev/null @@ -1,746 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: "Miss Islington (bot)" - <31488909+miss-islington@users.noreply.github.com> -Date: Fri, 17 Jun 2022 01:43:56 -0700 -Subject: [PATCH] 00385: gh-91404: Revert "bpo-23689: re module, fix memory - leak..." -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -This fixes a speed regression in the re module -which prevented chromium from building in Fedora. - -Revert "bpo-23689: re module, fix memory leak when a match is terminated by a signal or memory allocation failure" - -This reverts commit 6e3eee5c11b539e9aab39cff783acf57838c355a. - -Manual fixups to increase the MAGIC number and to handle conflicts with -a couple of changes that landed after that. - -(cherry picked from commit 4beee0c7b0c2cc78a893dde88fd8e34099dcf877) -Co-authored-by: Gregory P. Smith - -gh-94675: Add a regression test for rjsmin re slowdown - -Co-authored-by: Miro Hrončok ---- - Lib/re/_compiler.py | 59 ++++++----------- - Lib/re/_constants.py | 2 +- - Lib/test/test_re.py | 59 +++++++++-------- - ...2-06-15-21-35-11.gh-issue-91404.39TZzW.rst | 3 + - ...2-07-08-12-22-00.gh-issue-94675.IiTs5f.rst | 1 + - Modules/_sre/clinic/sre.c.h | 27 ++------ - Modules/_sre/sre.c | 65 +++++++------------ - Modules/_sre/sre.h | 4 -- - Modules/_sre/sre_constants.h | 2 +- - Modules/_sre/sre_lib.h | 30 +++++---- - 10 files changed, 105 insertions(+), 147 deletions(-) - create mode 100644 Misc/NEWS.d/next/Library/2022-06-15-21-35-11.gh-issue-91404.39TZzW.rst - create mode 100644 Misc/NEWS.d/next/Tests/2022-07-08-12-22-00.gh-issue-94675.IiTs5f.rst - -diff --git a/Lib/re/_compiler.py b/Lib/re/_compiler.py -index 4b5322338c..d8e0d2fdef 100644 ---- a/Lib/re/_compiler.py -+++ b/Lib/re/_compiler.py -@@ -28,21 +28,14 @@ - POSSESSIVE_REPEAT: (POSSESSIVE_REPEAT, SUCCESS, POSSESSIVE_REPEAT_ONE), - } - --class _CompileData: -- __slots__ = ('code', 'repeat_count') -- def __init__(self): -- self.code = [] -- self.repeat_count = 0 -- - def _combine_flags(flags, add_flags, del_flags, - TYPE_FLAGS=_parser.TYPE_FLAGS): - if add_flags & TYPE_FLAGS: - flags &= ~TYPE_FLAGS - return (flags | add_flags) & ~del_flags - --def _compile(data, pattern, flags): -+def _compile(code, pattern, flags): - # internal: compile a (sub)pattern -- code = data.code - emit = code.append - _len = len - LITERAL_CODES = _LITERAL_CODES -@@ -115,7 +108,7 @@ def _compile(data, pattern, flags): - skip = _len(code); emit(0) - emit(av[0]) - emit(av[1]) -- _compile(data, av[2], flags) -+ _compile(code, av[2], flags) - emit(SUCCESS) - code[skip] = _len(code) - skip - else: -@@ -123,11 +116,7 @@ def _compile(data, pattern, flags): - skip = _len(code); emit(0) - emit(av[0]) - emit(av[1]) -- # now op is in (MIN_REPEAT, MAX_REPEAT, POSSESSIVE_REPEAT) -- if op != POSSESSIVE_REPEAT: -- emit(data.repeat_count) -- data.repeat_count += 1 -- _compile(data, av[2], flags) -+ _compile(code, av[2], flags) - code[skip] = _len(code) - skip - emit(REPEATING_CODES[op][1]) - elif op is SUBPATTERN: -@@ -136,7 +125,7 @@ def _compile(data, pattern, flags): - emit(MARK) - emit((group-1)*2) - # _compile_info(code, p, _combine_flags(flags, add_flags, del_flags)) -- _compile(data, p, _combine_flags(flags, add_flags, del_flags)) -+ _compile(code, p, _combine_flags(flags, add_flags, del_flags)) - if group: - emit(MARK) - emit((group-1)*2+1) -@@ -148,7 +137,7 @@ def _compile(data, pattern, flags): - # pop their stack if they reach it - emit(ATOMIC_GROUP) - skip = _len(code); emit(0) -- _compile(data, av, flags) -+ _compile(code, av, flags) - emit(SUCCESS) - code[skip] = _len(code) - skip - elif op in SUCCESS_CODES: -@@ -163,7 +152,7 @@ def _compile(data, pattern, flags): - if lo != hi: - raise error("look-behind requires fixed-width pattern") - emit(lo) # look behind -- _compile(data, av[1], flags) -+ _compile(code, av[1], flags) - emit(SUCCESS) - code[skip] = _len(code) - skip - elif op is AT: -@@ -182,7 +171,7 @@ def _compile(data, pattern, flags): - for av in av[1]: - skip = _len(code); emit(0) - # _compile_info(code, av, flags) -- _compile(data, av, flags) -+ _compile(code, av, flags) - emit(JUMP) - tailappend(_len(code)); emit(0) - code[skip] = _len(code) - skip -@@ -210,12 +199,12 @@ def _compile(data, pattern, flags): - emit(op) - emit(av[0]-1) - skipyes = _len(code); emit(0) -- _compile(data, av[1], flags) -+ _compile(code, av[1], flags) - if av[2]: - emit(JUMP) - skipno = _len(code); emit(0) - code[skipyes] = _len(code) - skipyes + 1 -- _compile(data, av[2], flags) -+ _compile(code, av[2], flags) - code[skipno] = _len(code) - skipno - else: - code[skipyes] = _len(code) - skipyes + 1 -@@ -582,17 +571,17 @@ def isstring(obj): - def _code(p, flags): - - flags = p.state.flags | flags -- data = _CompileData() -+ code = [] - - # compile info block -- _compile_info(data.code, p, flags) -+ _compile_info(code, p, flags) - - # compile the pattern -- _compile(data, p.data, flags) -+ _compile(code, p.data, flags) - -- data.code.append(SUCCESS) -+ code.append(SUCCESS) - -- return data -+ return code - - def _hex_code(code): - return '[%s]' % ', '.join('%#0*x' % (_sre.CODESIZE*2+2, x) for x in code) -@@ -693,7 +682,7 @@ def print_2(*args): - else: - print_(FAILURE) - i += 1 -- elif op in (REPEAT_ONE, MIN_REPEAT_ONE, -+ elif op in (REPEAT, REPEAT_ONE, MIN_REPEAT_ONE, - POSSESSIVE_REPEAT, POSSESSIVE_REPEAT_ONE): - skip, min, max = code[i: i+3] - if max == MAXREPEAT: -@@ -701,13 +690,6 @@ def print_2(*args): - print_(op, skip, min, max, to=i+skip) - dis_(i+3, i+skip) - i += skip -- elif op is REPEAT: -- skip, min, max, repeat_index = code[i: i+4] -- if max == MAXREPEAT: -- max = 'MAXREPEAT' -- print_(op, skip, min, max, repeat_index, to=i+skip) -- dis_(i+4, i+skip) -- i += skip - elif op is GROUPREF_EXISTS: - arg, skip = code[i: i+2] - print_(op, arg, skip, to=i+skip) -@@ -762,11 +744,11 @@ def compile(p, flags=0): - else: - pattern = None - -- data = _code(p, flags) -+ code = _code(p, flags) - - if flags & SRE_FLAG_DEBUG: - print() -- dis(data.code) -+ dis(code) - - # map in either direction - groupindex = p.state.groupdict -@@ -775,6 +757,7 @@ def compile(p, flags=0): - indexgroup[i] = k - - return _sre.compile( -- pattern, flags | p.state.flags, data.code, -- p.state.groups-1, groupindex, tuple(indexgroup), -- data.repeat_count) -+ pattern, flags | p.state.flags, code, -+ p.state.groups-1, -+ groupindex, tuple(indexgroup) -+ ) -diff --git a/Lib/re/_constants.py b/Lib/re/_constants.py -index 1cc85c631f..10ee14bfab 100644 ---- a/Lib/re/_constants.py -+++ b/Lib/re/_constants.py -@@ -13,7 +13,7 @@ - - # update when constants are added or removed - --MAGIC = 20220423 -+MAGIC = 20220615 - - from _sre import MAXREPEAT, MAXGROUPS - -diff --git a/Lib/test/test_re.py b/Lib/test/test_re.py -index 6d61412f16..5d946370ee 100644 ---- a/Lib/test/test_re.py -+++ b/Lib/test/test_re.py -@@ -1,6 +1,7 @@ - from test.support import (gc_collect, bigmemtest, _2G, - cpython_only, captured_stdout, -- check_disallow_instantiation, is_emscripten, is_wasi) -+ check_disallow_instantiation, is_emscripten, is_wasi, -+ SHORT_TIMEOUT) - import locale - import re - import string -@@ -11,6 +12,14 @@ - from re import Scanner - from weakref import proxy - -+# some platforms lack working multiprocessing -+try: -+ import _multiprocessing -+except ImportError: -+ multiprocessing = None -+else: -+ import multiprocessing -+ - # Misc tests from Tim Peters' re.doc - - # WARNING: Don't change details in these tests if you don't know -@@ -1796,12 +1805,9 @@ def test_dealloc(self): - long_overflow = 2**128 - self.assertRaises(TypeError, re.finditer, "a", {}) - with self.assertRaises(OverflowError): -- _sre.compile("abc", 0, [long_overflow], 0, {}, (), 0) -+ _sre.compile("abc", 0, [long_overflow], 0, {}, ()) - with self.assertRaises(TypeError): -- _sre.compile({}, 0, [], 0, [], [], 0) -- with self.assertRaises(RuntimeError): -- # invalid repeat_count -1 -- _sre.compile("abc", 0, [1], 0, {}, (), -1) -+ _sre.compile({}, 0, [], 0, [], []) - - def test_search_dot_unicode(self): - self.assertTrue(re.search("123.*-", '123abc-')) -@@ -2441,6 +2447,26 @@ def test_template_function_and_flag_is_deprecated(self): - self.assertTrue(template_re1.match('ahoy')) - self.assertFalse(template_re1.match('nope')) - -+ @unittest.skipIf(multiprocessing is None, 'test requires multiprocessing') -+ def test_regression_gh94675(self): -+ pattern = re.compile(r'(?<=[({}])(((//[^\n]*)?[\n])([\000-\040])*)*' -+ r'((/[^/\[\n]*(([^\n]|(\[\n]*(]*)*\]))' -+ r'[^/\[]*)*/))((((//[^\n]*)?[\n])' -+ r'([\000-\040]|(/\*[^*]*\*+' -+ r'([^/*]\*+)*/))*)+(?=[^\000-\040);\]}]))') -+ input_js = '''a(function() { -+ /////////////////////////////////////////////////////////////////// -+ });''' -+ p = multiprocessing.Process(target=pattern.sub, args=('', input_js)) -+ p.start() -+ p.join(SHORT_TIMEOUT) -+ try: -+ self.assertFalse(p.is_alive(), 'pattern.sub() timed out') -+ finally: -+ if p.is_alive(): -+ p.terminate() -+ p.join() -+ - - def get_debug_out(pat): - with captured_stdout() as out: -@@ -2540,27 +2566,6 @@ def test_possesive_repeat(self): - 14. SUCCESS - ''') - -- def test_repeat_index(self): -- self.assertEqual(get_debug_out(r'(?:ab)*?(?:cd)*'), '''\ --MIN_REPEAT 0 MAXREPEAT -- LITERAL 97 -- LITERAL 98 --MAX_REPEAT 0 MAXREPEAT -- LITERAL 99 -- LITERAL 100 -- -- 0. INFO 4 0b0 0 MAXREPEAT (to 5) -- 5: REPEAT 8 0 MAXREPEAT 0 (to 14) --10. LITERAL 0x61 ('a') --12. LITERAL 0x62 ('b') --14: MIN_UNTIL --15. REPEAT 8 0 MAXREPEAT 1 (to 24) --20. LITERAL 0x63 ('c') --22. LITERAL 0x64 ('d') --24: MAX_UNTIL --25. SUCCESS --''') -- - - class PatternReprTests(unittest.TestCase): - def check(self, pattern, expected): -diff --git a/Misc/NEWS.d/next/Library/2022-06-15-21-35-11.gh-issue-91404.39TZzW.rst b/Misc/NEWS.d/next/Library/2022-06-15-21-35-11.gh-issue-91404.39TZzW.rst -new file mode 100644 -index 0000000000..e20b15c7b7 ---- /dev/null -+++ b/Misc/NEWS.d/next/Library/2022-06-15-21-35-11.gh-issue-91404.39TZzW.rst -@@ -0,0 +1,3 @@ -+Revert the :mod:`re` memory leak when a match is terminated by a signal or -+memory allocation failure as the implemented fix caused a major performance -+regression. -diff --git a/Misc/NEWS.d/next/Tests/2022-07-08-12-22-00.gh-issue-94675.IiTs5f.rst b/Misc/NEWS.d/next/Tests/2022-07-08-12-22-00.gh-issue-94675.IiTs5f.rst -new file mode 100644 -index 0000000000..d0005d9f60 ---- /dev/null -+++ b/Misc/NEWS.d/next/Tests/2022-07-08-12-22-00.gh-issue-94675.IiTs5f.rst -@@ -0,0 +1 @@ -+Add a regression test for :mod:`re` exponentional slowdown when using rjsmin. -diff --git a/Modules/_sre/clinic/sre.c.h b/Modules/_sre/clinic/sre.c.h -index e243c756e1..048a494f1b 100644 ---- a/Modules/_sre/clinic/sre.c.h -+++ b/Modules/_sre/clinic/sre.c.h -@@ -764,7 +764,7 @@ PyDoc_STRVAR(_sre_SRE_Pattern___deepcopy____doc__, - - PyDoc_STRVAR(_sre_compile__doc__, - "compile($module, /, pattern, flags, code, groups, groupindex,\n" --" indexgroup, repeat_count)\n" -+" indexgroup)\n" - "--\n" - "\n"); - -@@ -774,24 +774,23 @@ PyDoc_STRVAR(_sre_compile__doc__, - static PyObject * - _sre_compile_impl(PyObject *module, PyObject *pattern, int flags, - PyObject *code, Py_ssize_t groups, PyObject *groupindex, -- PyObject *indexgroup, Py_ssize_t repeat_count); -+ PyObject *indexgroup); - - static PyObject * - _sre_compile(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) - { - PyObject *return_value = NULL; -- static const char * const _keywords[] = {"pattern", "flags", "code", "groups", "groupindex", "indexgroup", "repeat_count", NULL}; -+ static const char * const _keywords[] = {"pattern", "flags", "code", "groups", "groupindex", "indexgroup", NULL}; - static _PyArg_Parser _parser = {NULL, _keywords, "compile", 0}; -- PyObject *argsbuf[7]; -+ PyObject *argsbuf[6]; - PyObject *pattern; - int flags; - PyObject *code; - Py_ssize_t groups; - PyObject *groupindex; - PyObject *indexgroup; -- Py_ssize_t repeat_count; - -- args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 7, 7, 0, argsbuf); -+ args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 6, 6, 0, argsbuf); - if (!args) { - goto exit; - } -@@ -827,19 +826,7 @@ _sre_compile(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject - goto exit; - } - indexgroup = args[5]; -- { -- Py_ssize_t ival = -1; -- PyObject *iobj = _PyNumber_Index(args[6]); -- if (iobj != NULL) { -- ival = PyLong_AsSsize_t(iobj); -- Py_DECREF(iobj); -- } -- if (ival == -1 && PyErr_Occurred()) { -- goto exit; -- } -- repeat_count = ival; -- } -- return_value = _sre_compile_impl(module, pattern, flags, code, groups, groupindex, indexgroup, repeat_count); -+ return_value = _sre_compile_impl(module, pattern, flags, code, groups, groupindex, indexgroup); - - exit: - return return_value; -@@ -1129,4 +1116,4 @@ _sre_SRE_Scanner_search(ScannerObject *self, PyTypeObject *cls, PyObject *const - } - return _sre_SRE_Scanner_search_impl(self, cls); - } --/*[clinic end generated code: output=97e7ce058366760b input=a9049054013a1b77]*/ -+/*[clinic end generated code: output=fd2f45c941620e6e input=a9049054013a1b77]*/ -diff --git a/Modules/_sre/sre.c b/Modules/_sre/sre.c -index 491734f243..0a7019a085 100644 ---- a/Modules/_sre/sre.c -+++ b/Modules/_sre/sre.c -@@ -427,12 +427,6 @@ state_init(SRE_STATE* state, PatternObject* pattern, PyObject* string, - state->lastmark = -1; - state->lastindex = -1; - -- state->repeats_array = PyMem_New(SRE_REPEAT, pattern->repeat_count); -- if (!state->repeats_array) { -- PyErr_NoMemory(); -- goto err; -- } -- - state->buffer.buf = NULL; - ptr = getstring(string, &length, &isbytes, &charsize, &state->buffer); - if (!ptr) -@@ -482,9 +476,6 @@ state_init(SRE_STATE* state, PatternObject* pattern, PyObject* string, - safely casted to `void*`, see bpo-39943 for details. */ - PyMem_Free((void*) state->mark); - state->mark = NULL; -- PyMem_Free(state->repeats_array); -- state->repeats_array = NULL; -- - if (state->buffer.buf) - PyBuffer_Release(&state->buffer); - return NULL; -@@ -500,8 +491,6 @@ state_fini(SRE_STATE* state) - /* See above PyMem_Del for why we explicitly cast here. */ - PyMem_Free((void*) state->mark); - state->mark = NULL; -- PyMem_Free(state->repeats_array); -- state->repeats_array = NULL; - } - - /* calculate offset from start of string */ -@@ -1418,15 +1407,14 @@ _sre.compile - groups: Py_ssize_t - groupindex: object(subclass_of='&PyDict_Type') - indexgroup: object(subclass_of='&PyTuple_Type') -- repeat_count: Py_ssize_t - - [clinic start generated code]*/ - - static PyObject * - _sre_compile_impl(PyObject *module, PyObject *pattern, int flags, - PyObject *code, Py_ssize_t groups, PyObject *groupindex, -- PyObject *indexgroup, Py_ssize_t repeat_count) --/*[clinic end generated code: output=922af562d51b1657 input=77e39c322501ec2a]*/ -+ PyObject *indexgroup) -+/*[clinic end generated code: output=ef9c2b3693776404 input=0a68476dbbe5db30]*/ - { - /* "compile" pattern descriptor to pattern object */ - -@@ -1484,8 +1472,8 @@ _sre_compile_impl(PyObject *module, PyObject *pattern, int flags, - self->pattern = pattern; - - self->flags = flags; -+ - self->groups = groups; -- self->repeat_count = repeat_count; - - if (PyDict_GET_SIZE(groupindex) > 0) { - Py_INCREF(groupindex); -@@ -1657,7 +1645,7 @@ _validate_charset(SRE_CODE *code, SRE_CODE *end) - } - - static int --_validate_inner(SRE_CODE *code, SRE_CODE *end, PatternObject *self) -+_validate_inner(SRE_CODE *code, SRE_CODE *end, Py_ssize_t groups) - { - /* Some variables are manipulated by the macros above */ - SRE_CODE op; -@@ -1678,8 +1666,8 @@ _validate_inner(SRE_CODE *code, SRE_CODE *end, PatternObject *self) - sre_match() code is robust even if they don't, and the worst - you can get is nonsensical match results. */ - GET_ARG; -- if (arg > 2 * (size_t)self->groups + 1) { -- VTRACE(("arg=%d, groups=%d\n", (int)arg, (int)self->groups)); -+ if (arg > 2 * (size_t)groups + 1) { -+ VTRACE(("arg=%d, groups=%d\n", (int)arg, (int)groups)); - FAIL; - } - break; -@@ -1808,7 +1796,7 @@ _validate_inner(SRE_CODE *code, SRE_CODE *end, PatternObject *self) - if (skip == 0) - break; - /* Stop 2 before the end; we check the JUMP below */ -- if (!_validate_inner(code, code+skip-3, self)) -+ if (!_validate_inner(code, code+skip-3, groups)) - FAIL; - code += skip-3; - /* Check that it ends with a JUMP, and that each JUMP -@@ -1837,7 +1825,7 @@ _validate_inner(SRE_CODE *code, SRE_CODE *end, PatternObject *self) - FAIL; - if (max > SRE_MAXREPEAT) - FAIL; -- if (!_validate_inner(code, code+skip-4, self)) -+ if (!_validate_inner(code, code+skip-4, groups)) - FAIL; - code += skip-4; - GET_OP; -@@ -1849,7 +1837,7 @@ _validate_inner(SRE_CODE *code, SRE_CODE *end, PatternObject *self) - case SRE_OP_REPEAT: - case SRE_OP_POSSESSIVE_REPEAT: - { -- SRE_CODE op1 = op, min, max, repeat_index; -+ SRE_CODE op1 = op, min, max; - GET_SKIP; - GET_ARG; min = arg; - GET_ARG; max = arg; -@@ -1857,17 +1845,9 @@ _validate_inner(SRE_CODE *code, SRE_CODE *end, PatternObject *self) - FAIL; - if (max > SRE_MAXREPEAT) - FAIL; -- if (op1 == SRE_OP_REPEAT) { -- GET_ARG; repeat_index = arg; -- if (repeat_index >= (size_t)self->repeat_count) -- FAIL; -- skip -= 4; -- } else { -- skip -= 3; -- } -- if (!_validate_inner(code, code+skip, self)) -+ if (!_validate_inner(code, code+skip-3, groups)) - FAIL; -- code += skip; -+ code += skip-3; - GET_OP; - if (op1 == SRE_OP_POSSESSIVE_REPEAT) { - if (op != SRE_OP_SUCCESS) -@@ -1883,7 +1863,7 @@ _validate_inner(SRE_CODE *code, SRE_CODE *end, PatternObject *self) - case SRE_OP_ATOMIC_GROUP: - { - GET_SKIP; -- if (!_validate_inner(code, code+skip-2, self)) -+ if (!_validate_inner(code, code+skip-2, groups)) - FAIL; - code += skip-2; - GET_OP; -@@ -1897,7 +1877,7 @@ _validate_inner(SRE_CODE *code, SRE_CODE *end, PatternObject *self) - case SRE_OP_GROUPREF_UNI_IGNORE: - case SRE_OP_GROUPREF_LOC_IGNORE: - GET_ARG; -- if (arg >= (size_t)self->groups) -+ if (arg >= (size_t)groups) - FAIL; - break; - -@@ -1906,7 +1886,7 @@ _validate_inner(SRE_CODE *code, SRE_CODE *end, PatternObject *self) - 'group' is either an integer group number or a group name, - 'then' and 'else' are sub-regexes, and 'else' is optional. */ - GET_ARG; -- if (arg >= (size_t)self->groups) -+ if (arg >= (size_t)groups) - FAIL; - GET_SKIP_ADJ(1); - code--; /* The skip is relative to the first arg! */ -@@ -1939,17 +1919,17 @@ _validate_inner(SRE_CODE *code, SRE_CODE *end, PatternObject *self) - code[skip-3] == SRE_OP_JUMP) - { - VTRACE(("both then and else parts present\n")); -- if (!_validate_inner(code+1, code+skip-3, self)) -+ if (!_validate_inner(code+1, code+skip-3, groups)) - FAIL; - code += skip-2; /* Position after JUMP, at */ - GET_SKIP; -- if (!_validate_inner(code, code+skip-1, self)) -+ if (!_validate_inner(code, code+skip-1, groups)) - FAIL; - code += skip-1; - } - else { - VTRACE(("only a then part present\n")); -- if (!_validate_inner(code+1, code+skip-1, self)) -+ if (!_validate_inner(code+1, code+skip-1, groups)) - FAIL; - code += skip-1; - } -@@ -1963,7 +1943,7 @@ _validate_inner(SRE_CODE *code, SRE_CODE *end, PatternObject *self) - if (arg & 0x80000000) - FAIL; /* Width too large */ - /* Stop 1 before the end; we check the SUCCESS below */ -- if (!_validate_inner(code+1, code+skip-2, self)) -+ if (!_validate_inner(code+1, code+skip-2, groups)) - FAIL; - code += skip-2; - GET_OP; -@@ -1982,19 +1962,18 @@ _validate_inner(SRE_CODE *code, SRE_CODE *end, PatternObject *self) - } - - static int --_validate_outer(SRE_CODE *code, SRE_CODE *end, PatternObject *self) -+_validate_outer(SRE_CODE *code, SRE_CODE *end, Py_ssize_t groups) - { -- if (self->groups < 0 || (size_t)self->groups > SRE_MAXGROUPS || -- self->repeat_count < 0 || -+ if (groups < 0 || (size_t)groups > SRE_MAXGROUPS || - code >= end || end[-1] != SRE_OP_SUCCESS) - FAIL; -- return _validate_inner(code, end-1, self); -+ return _validate_inner(code, end-1, groups); - } - - static int - _validate(PatternObject *self) - { -- if (!_validate_outer(self->code, self->code+self->codesize, self)) -+ if (!_validate_outer(self->code, self->code+self->codesize, self->groups)) - { - PyErr_SetString(PyExc_RuntimeError, "invalid SRE code"); - return 0; -diff --git a/Modules/_sre/sre.h b/Modules/_sre/sre.h -index aff064d343..52ae3e11b5 100644 ---- a/Modules/_sre/sre.h -+++ b/Modules/_sre/sre.h -@@ -29,8 +29,6 @@ typedef struct { - Py_ssize_t groups; /* must be first! */ - PyObject* groupindex; /* dict */ - PyObject* indexgroup; /* tuple */ -- /* the number of REPEATs */ -- Py_ssize_t repeat_count; - /* compatibility */ - PyObject* pattern; /* pattern source (or None) */ - int flags; /* flags used when compiling pattern source */ -@@ -85,8 +83,6 @@ typedef struct { - size_t data_stack_base; - /* current repeat context */ - SRE_REPEAT *repeat; -- /* repeat contexts array */ -- SRE_REPEAT *repeats_array; - } SRE_STATE; - - typedef struct { -diff --git a/Modules/_sre/sre_constants.h b/Modules/_sre/sre_constants.h -index 590d5be7cb..c633514736 100644 ---- a/Modules/_sre/sre_constants.h -+++ b/Modules/_sre/sre_constants.h -@@ -11,7 +11,7 @@ - * See the sre.c file for information on usage and redistribution. - */ - --#define SRE_MAGIC 20220423 -+#define SRE_MAGIC 20220615 - #define SRE_OP_FAILURE 0 - #define SRE_OP_SUCCESS 1 - #define SRE_OP_ANY 2 -diff --git a/Modules/_sre/sre_lib.h b/Modules/_sre/sre_lib.h -index 1e5b50170a..fb4c18b63d 100644 ---- a/Modules/_sre/sre_lib.h -+++ b/Modules/_sre/sre_lib.h -@@ -1079,12 +1079,17 @@ SRE(match)(SRE_STATE* state, const SRE_CODE* pattern, int toplevel) - by the UNTIL operator (MAX_UNTIL, MIN_UNTIL) */ - /* <1=min> <2=max> - <3=repeat_index> item tail */ -- TRACE(("|%p|%p|REPEAT %d %d %d\n", pattern, ptr, -- pattern[1], pattern[2], pattern[3])); -- -- /* install repeat context */ -- ctx->u.rep = &state->repeats_array[pattern[3]]; -+ TRACE(("|%p|%p|REPEAT %d %d\n", pattern, ptr, -+ pattern[1], pattern[2])); - -+ /* install new repeat context */ -+ /* TODO(https://github.com/python/cpython/issues/67877): Fix this -+ * potential memory leak. */ -+ ctx->u.rep = (SRE_REPEAT*) PyObject_Malloc(sizeof(*ctx->u.rep)); -+ if (!ctx->u.rep) { -+ PyErr_NoMemory(); -+ RETURN_FAILURE; -+ } - ctx->u.rep->count = -1; - ctx->u.rep->pattern = pattern; - ctx->u.rep->prev = state->repeat; -@@ -1094,6 +1099,7 @@ SRE(match)(SRE_STATE* state, const SRE_CODE* pattern, int toplevel) - state->ptr = ptr; - DO_JUMP(JUMP_REPEAT, jump_repeat, pattern+pattern[0]); - state->repeat = ctx->u.rep->prev; -+ PyObject_Free(ctx->u.rep); - - if (ret) { - RETURN_ON_ERROR(ret); -@@ -1103,8 +1109,7 @@ SRE(match)(SRE_STATE* state, const SRE_CODE* pattern, int toplevel) - - TARGET(SRE_OP_MAX_UNTIL): - /* maximizing repeat */ -- /* <1=min> <2=max> -- <3=repeat_index> item tail */ -+ /* <1=min> <2=max> item tail */ - - /* FIXME: we probably need to deal with zero-width - matches in here... */ -@@ -1124,7 +1129,7 @@ SRE(match)(SRE_STATE* state, const SRE_CODE* pattern, int toplevel) - /* not enough matches */ - ctx->u.rep->count = ctx->count; - DO_JUMP(JUMP_MAX_UNTIL_1, jump_max_until_1, -- ctx->u.rep->pattern+4); -+ ctx->u.rep->pattern+3); - if (ret) { - RETURN_ON_ERROR(ret); - RETURN_SUCCESS; -@@ -1146,7 +1151,7 @@ SRE(match)(SRE_STATE* state, const SRE_CODE* pattern, int toplevel) - DATA_PUSH(&ctx->u.rep->last_ptr); - ctx->u.rep->last_ptr = state->ptr; - DO_JUMP(JUMP_MAX_UNTIL_2, jump_max_until_2, -- ctx->u.rep->pattern+4); -+ ctx->u.rep->pattern+3); - DATA_POP(&ctx->u.rep->last_ptr); - if (ret) { - MARK_POP_DISCARD(ctx->lastmark); -@@ -1171,8 +1176,7 @@ SRE(match)(SRE_STATE* state, const SRE_CODE* pattern, int toplevel) - - TARGET(SRE_OP_MIN_UNTIL): - /* minimizing repeat */ -- /* <1=min> <2=max> -- <3=repeat_index> item tail */ -+ /* <1=min> <2=max> item tail */ - - ctx->u.rep = state->repeat; - if (!ctx->u.rep) -@@ -1189,7 +1193,7 @@ SRE(match)(SRE_STATE* state, const SRE_CODE* pattern, int toplevel) - /* not enough matches */ - ctx->u.rep->count = ctx->count; - DO_JUMP(JUMP_MIN_UNTIL_1, jump_min_until_1, -- ctx->u.rep->pattern+4); -+ ctx->u.rep->pattern+3); - if (ret) { - RETURN_ON_ERROR(ret); - RETURN_SUCCESS; -@@ -1232,7 +1236,7 @@ SRE(match)(SRE_STATE* state, const SRE_CODE* pattern, int toplevel) - DATA_PUSH(&ctx->u.rep->last_ptr); - ctx->u.rep->last_ptr = state->ptr; - DO_JUMP(JUMP_MIN_UNTIL_3,jump_min_until_3, -- ctx->u.rep->pattern+4); -+ ctx->u.rep->pattern+3); - DATA_POP(&ctx->u.rep->last_ptr); - if (ret) { - RETURN_ON_ERROR(ret); diff --git a/00385-gh-94675-add-a-regression-test-for-rjsmin-re-slowdown.patch b/00385-gh-94675-add-a-regression-test-for-rjsmin-re-slowdown.patch new file mode 100644 index 0000000..2628762 --- /dev/null +++ b/00385-gh-94675-add-a-regression-test-for-rjsmin-re-slowdown.patch @@ -0,0 +1,77 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= +Date: Fri, 8 Jul 2022 12:19:43 +0200 +Subject: [PATCH] 00385: gh-94675: Add a regression test for rjsmin re slowdown + +This tests a speed regression in the re module +which prevented chromium from building in Fedora. + +https://github.com/python/cpython/pull/94685 +--- + Lib/test/test_re.py | 31 ++++++++++++++++++- + ...2-07-08-12-22-00.gh-issue-94675.IiTs5f.rst | 1 + + 2 files changed, 31 insertions(+), 1 deletion(-) + create mode 100644 Misc/NEWS.d/next/Tests/2022-07-08-12-22-00.gh-issue-94675.IiTs5f.rst + +diff --git a/Lib/test/test_re.py b/Lib/test/test_re.py +index ab980793fa..5d946370ee 100644 +--- a/Lib/test/test_re.py ++++ b/Lib/test/test_re.py +@@ -1,6 +1,7 @@ + from test.support import (gc_collect, bigmemtest, _2G, + cpython_only, captured_stdout, +- check_disallow_instantiation, is_emscripten, is_wasi) ++ check_disallow_instantiation, is_emscripten, is_wasi, ++ SHORT_TIMEOUT) + import locale + import re + import string +@@ -11,6 +12,14 @@ + from re import Scanner + from weakref import proxy + ++# some platforms lack working multiprocessing ++try: ++ import _multiprocessing ++except ImportError: ++ multiprocessing = None ++else: ++ import multiprocessing ++ + # Misc tests from Tim Peters' re.doc + + # WARNING: Don't change details in these tests if you don't know +@@ -2438,6 +2447,26 @@ def test_template_function_and_flag_is_deprecated(self): + self.assertTrue(template_re1.match('ahoy')) + self.assertFalse(template_re1.match('nope')) + ++ @unittest.skipIf(multiprocessing is None, 'test requires multiprocessing') ++ def test_regression_gh94675(self): ++ pattern = re.compile(r'(?<=[({}])(((//[^\n]*)?[\n])([\000-\040])*)*' ++ r'((/[^/\[\n]*(([^\n]|(\[\n]*(]*)*\]))' ++ r'[^/\[]*)*/))((((//[^\n]*)?[\n])' ++ r'([\000-\040]|(/\*[^*]*\*+' ++ r'([^/*]\*+)*/))*)+(?=[^\000-\040);\]}]))') ++ input_js = '''a(function() { ++ /////////////////////////////////////////////////////////////////// ++ });''' ++ p = multiprocessing.Process(target=pattern.sub, args=('', input_js)) ++ p.start() ++ p.join(SHORT_TIMEOUT) ++ try: ++ self.assertFalse(p.is_alive(), 'pattern.sub() timed out') ++ finally: ++ if p.is_alive(): ++ p.terminate() ++ p.join() ++ + + def get_debug_out(pat): + with captured_stdout() as out: +diff --git a/Misc/NEWS.d/next/Tests/2022-07-08-12-22-00.gh-issue-94675.IiTs5f.rst b/Misc/NEWS.d/next/Tests/2022-07-08-12-22-00.gh-issue-94675.IiTs5f.rst +new file mode 100644 +index 0000000000..d0005d9f60 +--- /dev/null ++++ b/Misc/NEWS.d/next/Tests/2022-07-08-12-22-00.gh-issue-94675.IiTs5f.rst +@@ -0,0 +1 @@ ++Add a regression test for :mod:`re` exponentional slowdown when using rjsmin. diff --git a/python3.11.spec b/python3.11.spec index a70ebd7..2cf0fb0 100644 --- a/python3.11.spec +++ b/python3.11.spec @@ -14,10 +14,10 @@ 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}.0 -%global prerel b3 +%global prerel b4 %global upstream_version %{general_version}%{?prerel} Version: %{general_version}%{?prerel:~%{prerel}} -Release: 8%{?dist} +Release: 1%{?dist} License: Python @@ -322,39 +322,14 @@ Patch328: 00328-pyc-timestamp-invalidation-mode.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 -# 00383 # b4e1d3233b9fbcd9a60370d0f29e65012bb9532d -# gh-93442: Make C++ version of _Py_CAST work with 0/NULL +# 00385 # d7319d51c72f0a6c1af5f32a728de1e3f8fea514 +# gh-94675: Add a regression test for rjsmin re slowdown # -# Add C++ overloads for _Py_CAST_impl() to handle 0/NULL. This will allow -# C++ extensions that pass 0 or NULL to macros using _Py_CAST() to -# continue to compile. Without this, you get an error like: -# -# invalid ‘static_cast’ from type ‘int’ to type ‘_object*’ -# -# The modern way to use a NULL value in C++ is to use nullptr. However, -# we want to not break extensions that do things the old way. -Patch383: 00383-gh-93442-make-c-version-of-_py_cast-work-with-0-null.patch - -# 00384 # 7c809258e34925560cc13a377b1c6d9c03e83207 -# gh-94028: Clear and reset sqlite3 statements properly in cursor iternext (GH-94042) -Patch384: 00384-gh-94028-clear-and-reset-sqlite3-statements-properly-in-cursor-iternext-gh-94042.patch - -# 00385 # 8696ca2373ef3d7595dfb62e2b63180621f40d5d -# gh-91404: Revert "bpo-23689: re module, fix memory leak..." -# -# This fixes a speed regression in the re module +# This tests a speed regression in the re module # which prevented chromium from building in Fedora. # -# Revert "bpo-23689: re module, fix memory leak when a match is terminated by a signal or memory allocation failure" -# -# This reverts commit 6e3eee5c11b539e9aab39cff783acf57838c355a. -# -# Manual fixups to increase the MAGIC number and to handle conflicts with -# a couple of changes that landed after that. -# -# -# gh-94675: Add a regression test for rjsmin re slowdown -Patch385: 00385-gh-91404-revert-bpo-23689-re-module-fix-memory-leak.patch +# https://github.com/python/cpython/pull/94685 +Patch385: 00385-gh-94675-add-a-regression-test-for-rjsmin-re-slowdown.patch # (New patches go here ^^^) # @@ -1628,6 +1603,9 @@ CheckPython optimized # ====================================================== %changelog +* Mon Jul 11 2022 Miro Hrončok - 3.11.0~b4-1 +- Update to 3.11.0b4 + * Fri Jul 08 2022 Miro Hrončok - 3.11.0~b3-8 - Finish bootstrap of the re module speed regression fix diff --git a/sources b/sources index 5a26218..d91382e 100644 --- a/sources +++ b/sources @@ -1,2 +1,2 @@ -SHA512 (Python-3.11.0b3.tar.xz) = 53c379311acc9d8ec645caea44f4b83b29fcbdacb7114eb7aac5a2f0229402eddb245abc8bd6665077e9c82ba0a821cc55ae7494d0667b84675248025e872498 -SHA512 (Python-3.11.0b3.tar.xz.asc) = b51a02e47de73f4998effd15eb99d356ef69cd69521f208f50de1b8acf69d5cf9c8a2f774ec8bc5e0e75534fe59efe019cffcff39bc525aa4641dc9b47efb5ef +SHA512 (Python-3.11.0b4.tar.xz) = 1530f4dcba6325ac8e9bb955604fc504a4306e3291b667d1d8490b78e1c50924d81ff8ab50d08c736e70d3e42788aabaa162179a77c03860ee8064f17f93bb09 +SHA512 (Python-3.11.0b4.tar.xz.asc) = 8f6c633911755767d351fc86e031df6cedd6091ca5ec0ef55331ac65d2ad532c71e568c173513a2bbb2235e5e3fc9dd77e1b7ed230df1f0d8bd6e23da470b1e2 From 44b7dd93c43457abff4783398f54a44bce9a8ef4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Thu, 23 Jun 2022 13:40:55 +0200 Subject: [PATCH 038/118] CI tests config: Define and reuse the pybasever variable This will make future changes easier to backport to other Python versions. Note that with jinja2 expressions, we need to quote them to preserve valid yaml, see: https://docs.ansible.com/ansible/latest/user_guide/playbooks_variables.html#when-to-quote-variables-a-yaml-gotcha --- tests/tests.yml | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/tests/tests.yml b/tests/tests.yml index f6b2e90..3f9165b 100644 --- a/tests/tests.yml +++ b/tests/tests.yml @@ -15,39 +15,40 @@ 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=3.11 ./venv.sh + run: "VERSION={{ pybasever }} ./venv.sh" - smoke_virtualenv: dir: python/smoke - run: VERSION=3.11 METHOD=virtualenv ./venv.sh + run: "VERSION={{ pybasever }} METHOD=virtualenv ./venv.sh" - debugsmoke: dir: python/smoke - run: PYTHON=python3.11d TOX=false VERSION=3.11 ./venv.sh + run: "PYTHON=python{{ pybasever }}d TOX=false VERSION={{ pybasever }} ./venv.sh" - selftest: dir: python/selftest - run: VERSION=3.11 X="" ./parallel.sh + run: "VERSION={{ pybasever }} X='' ./parallel.sh" - debugtest: dir: python/selftest - run: VERSION=3.11 PYTHON=python3.11d X="" ./parallel.sh + run: "VERSION={{ pybasever }} PYTHON=python{{ pybasever }}d X='' ./parallel.sh" - debugflags: dir: python/flags - run: python3.11d ./assertflags.py -O0 + run: "python{{ pybasever }}d ./assertflags.py -O0" - marshalparser: dir: python/marshalparser - run: VERSION=3.11 SAMPLE=10 test_marshalparser_compatibility.sh + 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 - - python3.11 # the test subject - - python3.11-debug # for leak testing - - python3.11-devel # for extension building in venv and selftest - - python3.11-tkinter # for selftest - - python3.11-test # for selftest + - "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 From 2742991dbee2da0457c8de94b225d31b1edee422 Mon Sep 17 00:00:00 2001 From: Fedora Release Engineering Date: Fri, 22 Jul 2022 23:46:54 +0000 Subject: [PATCH 039/118] Rebuilt for https://fedoraproject.org/wiki/Fedora_37_Mass_Rebuild Signed-off-by: Fedora Release Engineering --- python3.11.spec | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/python3.11.spec b/python3.11.spec index 2cf0fb0..36e4e2f 100644 --- a/python3.11.spec +++ b/python3.11.spec @@ -17,7 +17,7 @@ URL: https://www.python.org/ %global prerel b4 %global upstream_version %{general_version}%{?prerel} Version: %{general_version}%{?prerel:~%{prerel}} -Release: 1%{?dist} +Release: 2%{?dist} License: Python @@ -1603,6 +1603,9 @@ CheckPython optimized # ====================================================== %changelog +* Fri Jul 22 2022 Fedora Release Engineering - 3.11.0~b4-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_37_Mass_Rebuild + * Mon Jul 11 2022 Miro Hrončok - 3.11.0~b4-1 - Update to 3.11.0b4 From 9518f2915c0e0a5a03161d9d80c111987f746d13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Hrn=C4=8Diar?= Date: Tue, 26 Jul 2022 13:15:25 +0200 Subject: [PATCH 040/118] Update to 3.11.0b5 --- python3.11.spec | 11 +++++++---- sources | 4 ++-- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/python3.11.spec b/python3.11.spec index 36e4e2f..283b19d 100644 --- a/python3.11.spec +++ b/python3.11.spec @@ -14,10 +14,10 @@ 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}.0 -%global prerel b4 +%global prerel b5 %global upstream_version %{general_version}%{?prerel} Version: %{general_version}%{?prerel:~%{prerel}} -Release: 2%{?dist} +Release: 1%{?dist} License: Python @@ -67,8 +67,8 @@ License: Python # If the rpmwheels condition is disabled, we use the bundled wheel packages # from Python with the versions below. # This needs to be manually updated when we update Python. -%global pip_version 22.0.4 -%global setuptools_version 58.1.0 +%global pip_version 22.2 +%global setuptools_version 63.2.0 # Expensive optimizations (mainly, profile-guided optimizations) %bcond_without optimizations @@ -1603,6 +1603,9 @@ CheckPython optimized # ====================================================== %changelog +* Tue Jul 26 2022 Tomáš Hrnčiar - 3.11.0~b5-1 +- Update to 3.11.0b5 + * Fri Jul 22 2022 Fedora Release Engineering - 3.11.0~b4-2 - Rebuilt for https://fedoraproject.org/wiki/Fedora_37_Mass_Rebuild diff --git a/sources b/sources index d91382e..3371ce1 100644 --- a/sources +++ b/sources @@ -1,2 +1,2 @@ -SHA512 (Python-3.11.0b4.tar.xz) = 1530f4dcba6325ac8e9bb955604fc504a4306e3291b667d1d8490b78e1c50924d81ff8ab50d08c736e70d3e42788aabaa162179a77c03860ee8064f17f93bb09 -SHA512 (Python-3.11.0b4.tar.xz.asc) = 8f6c633911755767d351fc86e031df6cedd6091ca5ec0ef55331ac65d2ad532c71e568c173513a2bbb2235e5e3fc9dd77e1b7ed230df1f0d8bd6e23da470b1e2 +SHA512 (Python-3.11.0b5.tar.xz) = b1013e449c9a0e9b61df5a266b5f05458d284b3524c6c44d44d8a5007bcb95ff754f21296cd695f353111575c7cce71f8a2808a9adf8c573512bf97f691d2200 +SHA512 (Python-3.11.0b5.tar.xz.asc) = 6f658c7623e7750c0c8c18b4a2fe86d6a2414f3b411487ca4d2dd9840165ae3e6eea8b3468b1376862181b7b58d3fe99681a00d290172a6986f0f2ead5d6c3bd From ab88d7f86ce4e75f73601b4fe128f0a178d20014 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Hrn=C4=8Diar?= Date: Mon, 8 Aug 2022 15:45:34 +0200 Subject: [PATCH 041/118] Update to 3.11.0rc1 --- ...gression-test-for-rjsmin-re-slowdown.patch | 77 ------------------- python3.11.spec | 16 ++-- sources | 4 +- 3 files changed, 7 insertions(+), 90 deletions(-) delete mode 100644 00385-gh-94675-add-a-regression-test-for-rjsmin-re-slowdown.patch diff --git a/00385-gh-94675-add-a-regression-test-for-rjsmin-re-slowdown.patch b/00385-gh-94675-add-a-regression-test-for-rjsmin-re-slowdown.patch deleted file mode 100644 index 2628762..0000000 --- a/00385-gh-94675-add-a-regression-test-for-rjsmin-re-slowdown.patch +++ /dev/null @@ -1,77 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= -Date: Fri, 8 Jul 2022 12:19:43 +0200 -Subject: [PATCH] 00385: gh-94675: Add a regression test for rjsmin re slowdown - -This tests a speed regression in the re module -which prevented chromium from building in Fedora. - -https://github.com/python/cpython/pull/94685 ---- - Lib/test/test_re.py | 31 ++++++++++++++++++- - ...2-07-08-12-22-00.gh-issue-94675.IiTs5f.rst | 1 + - 2 files changed, 31 insertions(+), 1 deletion(-) - create mode 100644 Misc/NEWS.d/next/Tests/2022-07-08-12-22-00.gh-issue-94675.IiTs5f.rst - -diff --git a/Lib/test/test_re.py b/Lib/test/test_re.py -index ab980793fa..5d946370ee 100644 ---- a/Lib/test/test_re.py -+++ b/Lib/test/test_re.py -@@ -1,6 +1,7 @@ - from test.support import (gc_collect, bigmemtest, _2G, - cpython_only, captured_stdout, -- check_disallow_instantiation, is_emscripten, is_wasi) -+ check_disallow_instantiation, is_emscripten, is_wasi, -+ SHORT_TIMEOUT) - import locale - import re - import string -@@ -11,6 +12,14 @@ - from re import Scanner - from weakref import proxy - -+# some platforms lack working multiprocessing -+try: -+ import _multiprocessing -+except ImportError: -+ multiprocessing = None -+else: -+ import multiprocessing -+ - # Misc tests from Tim Peters' re.doc - - # WARNING: Don't change details in these tests if you don't know -@@ -2438,6 +2447,26 @@ def test_template_function_and_flag_is_deprecated(self): - self.assertTrue(template_re1.match('ahoy')) - self.assertFalse(template_re1.match('nope')) - -+ @unittest.skipIf(multiprocessing is None, 'test requires multiprocessing') -+ def test_regression_gh94675(self): -+ pattern = re.compile(r'(?<=[({}])(((//[^\n]*)?[\n])([\000-\040])*)*' -+ r'((/[^/\[\n]*(([^\n]|(\[\n]*(]*)*\]))' -+ r'[^/\[]*)*/))((((//[^\n]*)?[\n])' -+ r'([\000-\040]|(/\*[^*]*\*+' -+ r'([^/*]\*+)*/))*)+(?=[^\000-\040);\]}]))') -+ input_js = '''a(function() { -+ /////////////////////////////////////////////////////////////////// -+ });''' -+ p = multiprocessing.Process(target=pattern.sub, args=('', input_js)) -+ p.start() -+ p.join(SHORT_TIMEOUT) -+ try: -+ self.assertFalse(p.is_alive(), 'pattern.sub() timed out') -+ finally: -+ if p.is_alive(): -+ p.terminate() -+ p.join() -+ - - def get_debug_out(pat): - with captured_stdout() as out: -diff --git a/Misc/NEWS.d/next/Tests/2022-07-08-12-22-00.gh-issue-94675.IiTs5f.rst b/Misc/NEWS.d/next/Tests/2022-07-08-12-22-00.gh-issue-94675.IiTs5f.rst -new file mode 100644 -index 0000000000..d0005d9f60 ---- /dev/null -+++ b/Misc/NEWS.d/next/Tests/2022-07-08-12-22-00.gh-issue-94675.IiTs5f.rst -@@ -0,0 +1 @@ -+Add a regression test for :mod:`re` exponentional slowdown when using rjsmin. diff --git a/python3.11.spec b/python3.11.spec index 283b19d..2dd5a12 100644 --- a/python3.11.spec +++ b/python3.11.spec @@ -14,7 +14,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}.0 -%global prerel b5 +%global prerel rc1 %global upstream_version %{general_version}%{?prerel} Version: %{general_version}%{?prerel:~%{prerel}} Release: 1%{?dist} @@ -67,7 +67,7 @@ License: Python # If the rpmwheels condition is disabled, we use the bundled wheel packages # from Python with the versions below. # This needs to be manually updated when we update Python. -%global pip_version 22.2 +%global pip_version 22.2.2 %global setuptools_version 63.2.0 # Expensive optimizations (mainly, profile-guided optimizations) @@ -322,15 +322,6 @@ Patch328: 00328-pyc-timestamp-invalidation-mode.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 -# 00385 # d7319d51c72f0a6c1af5f32a728de1e3f8fea514 -# gh-94675: Add a regression test for rjsmin re slowdown -# -# This tests a speed regression in the re module -# which prevented chromium from building in Fedora. -# -# https://github.com/python/cpython/pull/94685 -Patch385: 00385-gh-94675-add-a-regression-test-for-rjsmin-re-slowdown.patch - # (New patches go here ^^^) # # When adding new patches to "python" and "python3" in Fedora, EL, etc., @@ -1603,6 +1594,9 @@ CheckPython optimized # ====================================================== %changelog +* Mon Aug 08 2022 Tomáš Hrnčiar - 3.11.0~rc1-1 +- Update to 3.11.0rc1 + * Tue Jul 26 2022 Tomáš Hrnčiar - 3.11.0~b5-1 - Update to 3.11.0b5 diff --git a/sources b/sources index 3371ce1..ffb6ae6 100644 --- a/sources +++ b/sources @@ -1,2 +1,2 @@ -SHA512 (Python-3.11.0b5.tar.xz) = b1013e449c9a0e9b61df5a266b5f05458d284b3524c6c44d44d8a5007bcb95ff754f21296cd695f353111575c7cce71f8a2808a9adf8c573512bf97f691d2200 -SHA512 (Python-3.11.0b5.tar.xz.asc) = 6f658c7623e7750c0c8c18b4a2fe86d6a2414f3b411487ca4d2dd9840165ae3e6eea8b3468b1376862181b7b58d3fe99681a00d290172a6986f0f2ead5d6c3bd +SHA512 (Python-3.11.0rc1.tar.xz) = 2a72ea59277f8115e418ced671969fc0d5ba271c7740f70c665a4b450a59d7752278d061bd59f136dacfa608ed167f983c6589b214a973b1b63ea2115ea298bb +SHA512 (Python-3.11.0rc1.tar.xz.asc) = d4cffc90c2ed7b8ea7228a21f7ac902a92f27003f1420ad751b1691de950974ea174cb0471b6e19ed1548dc5382012fa9ad5fcf83c34646c7ea2d73c88799e38 From d75ca77a64851b840b817a05b76c917f77012353 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Tue, 9 Aug 2022 12:11:02 +0200 Subject: [PATCH 042/118] Don't use custom installation schemes --- 00251-change-user-install-location.patch | 171 ++++++++++++++++++----- python3.11.spec | 30 ++-- 2 files changed, 152 insertions(+), 49 deletions(-) diff --git a/00251-change-user-install-location.patch b/00251-change-user-install-location.patch index 7926cfc..6c3caac 100644 --- a/00251-change-user-install-location.patch +++ b/00251-change-user-install-location.patch @@ -1,37 +1,65 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Lumir Balhar +From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Mon, 15 Feb 2021 12:19:27 +0100 Subject: [PATCH] 00251: Change user install location MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit -Change the values of sysconfig's "posix_prefix" install scheme to /usr/local -when RPM build or venv/virtualenv is not detected, -to make pip, sysconfig and distutils install into an isolated location. +Set values of base and platbase in sysconfig from /usr +to /usr/local when RPM build is not detected +to make pip and similar tools install into separate location. -The original values are saved as an additional "rpm_prefix" install scheme. - -The site module adds the /usr/local paths to sys.path when site packages are -enabled and RPM build is not detected. +Set values of prefix and exec_prefix in distutils install command +to /usr/local if executable is /usr/bin/python* and RPM build +is not detected to make distutils and pypa/distutils install into separate location. Fedora Change: https://fedoraproject.org/wiki/Changes/Making_sudo_pip_safe +Downstream only. -Rewrote in Fedora 36+ to patch sysconfig instead of distutils, -see https://discuss.python.org/t/pep-632-deprecate-distutils-module/5134/104 +We've tried to rework in Fedora 36/Python 3.10 to follow https://bugs.python.org/issue43976 +but we have identified serious problems with that approach, +see https://bugzilla.redhat.com/2026979 or https://bugzilla.redhat.com/2097183 -Downstream only for now, waiting for https://bugs.python.org/issue43976 +pypa/distutils integration: https://github.com/pypa/distutils/pull/70 Co-authored-by: Petr Viktorin Co-authored-by: Miro Hrončok Co-authored-by: Michal Cyprian Co-authored-by: Lumír Balhar --- - Lib/site.py | 9 ++++++++- - Lib/sysconfig.py | 19 +++++++++++++++++++ - Lib/test/test_sysconfig.py | 4 +++- - 3 files changed, 30 insertions(+), 2 deletions(-) + Lib/distutils/command/install.py | 8 ++++-- + Lib/site.py | 9 +++++- + Lib/sysconfig.py | 49 +++++++++++++++++++++++++++++++- + Lib/test/test_sysconfig.py | 17 +++++++++-- + 4 files changed, 77 insertions(+), 6 deletions(-) +diff --git a/Lib/distutils/command/install.py b/Lib/distutils/command/install.py +index 01d5331a63..79f70f0de4 100644 +--- a/Lib/distutils/command/install.py ++++ b/Lib/distutils/command/install.py +@@ -159,6 +159,8 @@ class install(Command): + + negative_opt = {'no-compile' : 'compile'} + ++ # Allow Fedora to add components to the prefix ++ _prefix_addition = getattr(sysconfig, '_prefix_addition', '') + + def initialize_options(self): + """Initializes options.""" +@@ -441,8 +443,10 @@ def finalize_unix(self): + raise DistutilsOptionError( + "must not supply exec-prefix without prefix") + +- self.prefix = os.path.normpath(sys.prefix) +- self.exec_prefix = os.path.normpath(sys.exec_prefix) ++ self.prefix = ( ++ os.path.normpath(sys.prefix) + self._prefix_addition) ++ self.exec_prefix = ( ++ os.path.normpath(sys.exec_prefix) + self._prefix_addition) + + else: + if self.exec_prefix is None: diff --git a/Lib/site.py b/Lib/site.py index 69670d9d7f..104cb93899 100644 --- a/Lib/site.py @@ -54,40 +82,109 @@ index 69670d9d7f..104cb93899 100644 if os.path.isdir(sitedir): addsitedir(sitedir, known_paths) diff --git a/Lib/sysconfig.py b/Lib/sysconfig.py -index ebe3711827..dca8aa89b6 100644 +index ebe3711827..55af57b335 100644 --- a/Lib/sysconfig.py +++ b/Lib/sysconfig.py -@@ -103,6 +103,25 @@ +@@ -103,6 +103,11 @@ else: _INSTALL_SCHEMES['venv'] = _INSTALL_SCHEMES['posix_venv'] -+# backup the original posix_prefix as rpm_prefix -+# RPM packages use it and we need to be able to read it even when changed ++# For a brief period of time in the Fedora 36 life cycle, ++# this installation scheme existed and was documented in the release notes. ++# For backwards compatibility, we keep it here (at least on 3.10 and 3.11). +_INSTALL_SCHEMES['rpm_prefix'] = _INSTALL_SCHEMES['posix_prefix'] + -+if (not (hasattr(sys, 'real_prefix') or -+ sys.prefix != sys.base_prefix) and -+ 'RPM_BUILD_ROOT' not in os.environ): -+ _INSTALL_SCHEMES['posix_prefix'] = { -+ 'stdlib': '{installed_base}/{platlibdir}/python{py_version_short}', -+ 'platstdlib': '{platbase}/{platlibdir}/python{py_version_short}', -+ 'purelib': '{base}/local/lib/python{py_version_short}/site-packages', -+ 'platlib': '{platbase}/local/{platlibdir}/python{py_version_short}/site-packages', -+ 'include': -+ '{installed_base}/include/python{py_version_short}{abiflags}', -+ 'platinclude': -+ '{installed_platbase}/include/python{py_version_short}{abiflags}', -+ 'scripts': '{base}/local/bin', -+ 'data': '{base}/local', -+ } # NOTE: site.py has copy of this function. # Sync it when modify this function. +@@ -162,6 +167,19 @@ def joinuser(*args): + }, + } + ++# This is used by distutils.command.install in the stdlib ++# as well as pypa/distutils (e.g. bundled in setuptools). ++# The self.prefix value is set to sys.prefix + /local/ ++# if neither RPM build nor virtual environment is ++# detected to make distutils install packages ++# into the separate location. ++# https://fedoraproject.org/wiki/Changes/Making_sudo_pip_safe ++if (not (hasattr(sys, 'real_prefix') or ++ sys.prefix != sys.base_prefix) and ++ 'RPM_BUILD_ROOT' not in os.environ): ++ _prefix_addition = '/local' ++ ++ + _SCHEME_KEYS = ('stdlib', 'platstdlib', 'purelib', 'platlib', 'include', + 'scripts', 'data') + +@@ -258,11 +276,40 @@ def _extend_dict(target_dict, other_dict): + target_dict[key] = value + + ++_CONFIG_VARS_LOCAL = None ++ ++ ++def _config_vars_local(): ++ # This function returns the config vars with prefixes amended to /usr/local ++ # https://fedoraproject.org/wiki/Changes/Making_sudo_pip_safe ++ global _CONFIG_VARS_LOCAL ++ if _CONFIG_VARS_LOCAL is None: ++ _CONFIG_VARS_LOCAL = dict(get_config_vars()) ++ _CONFIG_VARS_LOCAL['base'] = '/usr/local' ++ _CONFIG_VARS_LOCAL['platbase'] = '/usr/local' ++ return _CONFIG_VARS_LOCAL ++ ++ + def _expand_vars(scheme, vars): + res = {} + if vars is None: + vars = {} +- _extend_dict(vars, get_config_vars()) ++ ++ # when we are not in a virtual environment or an RPM build ++ # we change '/usr' to '/usr/local' ++ # to avoid surprises, we explicitly check for the /usr/ prefix ++ # Python virtual environments have different prefixes ++ # we only do this for posix_prefix, not to mangle the venv scheme ++ # posix_prefix is used by sudo pip install ++ # we only change the defaults here, so explicit --prefix will take precedence ++ # https://fedoraproject.org/wiki/Changes/Making_sudo_pip_safe ++ if (scheme == 'posix_prefix' and ++ _PREFIX == '/usr' and ++ 'RPM_BUILD_ROOT' not in os.environ): ++ _extend_dict(vars, _config_vars_local()) ++ else: ++ _extend_dict(vars, get_config_vars()) ++ + if os.name == 'nt': + # On Windows we want to substitute 'lib' for schemes rather + # than the native value (without modifying vars, in case it diff --git a/Lib/test/test_sysconfig.py b/Lib/test/test_sysconfig.py -index 578ac1db50..e78ff15ad3 100644 +index 578ac1db50..dc58e7db18 100644 --- a/Lib/test/test_sysconfig.py +++ b/Lib/test/test_sysconfig.py -@@ -336,7 +336,7 @@ def test_get_config_h_filename(self): +@@ -111,8 +111,19 @@ def test_get_path(self): + for scheme in _INSTALL_SCHEMES: + for name in _INSTALL_SCHEMES[scheme]: + expected = _INSTALL_SCHEMES[scheme][name].format(**config_vars) ++ tested = get_path(name, scheme) ++ # https://fedoraproject.org/wiki/Changes/Making_sudo_pip_safe ++ if tested.startswith('/usr/local'): ++ # /usr/local should only be used in posix_prefix ++ self.assertEqual(scheme, 'posix_prefix') ++ # Fedora CI runs tests for venv and virtualenv that check for other prefixes ++ self.assertEqual(sys.prefix, '/usr') ++ # When building the RPM of Python, %check runs this with RPM_BUILD_ROOT set ++ # Fedora CI runs this with RPM_BUILD_ROOT unset ++ self.assertNotIn('RPM_BUILD_ROOT', os.environ) ++ tested = tested.replace('/usr/local', '/usr') + self.assertEqual( +- os.path.normpath(get_path(name, scheme)), ++ os.path.normpath(tested), + os.path.normpath(expected), + ) + +@@ -336,7 +347,7 @@ def test_get_config_h_filename(self): self.assertTrue(os.path.isfile(config_h), config_h) def test_get_scheme_names(self): @@ -96,7 +193,7 @@ index 578ac1db50..e78ff15ad3 100644 if HAS_USER_BASE: wanted.extend(['nt_user', 'osx_framework_user', 'posix_user']) self.assertEqual(get_scheme_names(), tuple(sorted(wanted))) -@@ -348,6 +348,8 @@ def test_symlink(self): # Issue 7880 +@@ -348,6 +359,8 @@ def test_symlink(self): # Issue 7880 cmd = "-c", "import sysconfig; print(sysconfig.get_platform())" self.assertEqual(py.call_real(*cmd), py.call_link(*cmd)) diff --git a/python3.11.spec b/python3.11.spec index 2dd5a12..67b517f 100644 --- a/python3.11.spec +++ b/python3.11.spec @@ -17,7 +17,7 @@ URL: https://www.python.org/ %global prerel rc1 %global upstream_version %{general_version}%{?prerel} Version: %{general_version}%{?prerel:~%{prerel}} -Release: 1%{?dist} +Release: 2%{?dist} License: Python @@ -277,24 +277,25 @@ Source11: idle3.appdata.xml # Was Patch0 in ivazquez' python3000 specfile Patch1: 00001-rpath.patch -# 00251 # 178b2099a8eb7c487f1a32c3f055be6c154c0116 +# 00251 # af0f1ba72e01cb93371ff21fb7ca889daa43fa7a # Change user install location # -# Change the values of sysconfig's "posix_prefix" install scheme to /usr/local -# when RPM build or venv/virtualenv is not detected, -# to make pip, sysconfig and distutils install into an isolated location. +# Set values of base and platbase in sysconfig from /usr +# to /usr/local when RPM build is not detected +# to make pip and similar tools install into separate location. # -# The original values are saved as an additional "rpm_prefix" install scheme. -# -# The site module adds the /usr/local paths to sys.path when site packages are -# enabled and RPM build is not detected. +# Set values of prefix and exec_prefix in distutils install command +# to /usr/local if executable is /usr/bin/python* and RPM build +# is not detected to make distutils and pypa/distutils install into separate location. # # Fedora Change: https://fedoraproject.org/wiki/Changes/Making_sudo_pip_safe +# Downstream only. # -# Rewrote in Fedora 36+ to patch sysconfig instead of distutils, -# see https://discuss.python.org/t/pep-632-deprecate-distutils-module/5134/104 +# We've tried to rework in Fedora 36/Python 3.10 to follow https://bugs.python.org/issue43976 +# but we have identified serious problems with that approach, +# see https://bugzilla.redhat.com/2026979 or https://bugzilla.redhat.com/2097183 # -# Downstream only for now, waiting for https://bugs.python.org/issue43976 +# pypa/distutils integration: https://github.com/pypa/distutils/pull/70 Patch251: 00251-change-user-install-location.patch # 00328 # 318e500c98f5e59eb1f23e0fcd32db69b9bd17e1 @@ -1594,6 +1595,11 @@ CheckPython optimized # ====================================================== %changelog +* Tue Aug 09 2022 Miro Hrončok - 3.11.0~rc1-2 +- Don't use custom installation schemes +- Fixes rhbz#2026979 +- Fixes rhbz#2097183 + * Mon Aug 08 2022 Tomáš Hrnčiar - 3.11.0~rc1-1 - Update to 3.11.0rc1 From 252afb8c115e3ecd34985fcb7e09d8831844584e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Fri, 5 Aug 2022 14:31:14 +0200 Subject: [PATCH 043/118] Update rpmlintrc to rpmlint 2 - Rename to rpmlint.toml - Change from Python function calls to TOML list - Remove rpmlint 1.1 workarounds - Add rpmlint 2.2 workarounds - Adjusts some filters to match rpmlint 2.2 messages --- python3.11.rpmlintrc | 95 -------------------------------------------- rpmlint.toml | 88 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+), 95 deletions(-) delete mode 100644 python3.11.rpmlintrc create mode 100644 rpmlint.toml diff --git a/python3.11.rpmlintrc b/python3.11.rpmlintrc deleted file mode 100644 index 5fc9c03..0000000 --- a/python3.11.rpmlintrc +++ /dev/null @@ -1,95 +0,0 @@ -# KNOWN BUGS: -# https://bugzilla.redhat.com/show_bug.cgi?id=1489816 -addFilter(r'crypto-policy-non-compliance-openssl') - - -# TESTS: -addFilter(r'(zero-length|pem-certificate|uncompressed-zip) /usr/lib(64)?/python3\.\d+/test') - - -# OTHER DELIBERATES: -# chroot function -addFilter(r'missing-call-to-chdir-with-chroot') - -# intentionally unversioned and selfobsoleted -addFilter(r'unversioned-explicit-obsoletes python') -addFilter(r'unversioned Obsoletes: Obsoletes: python3\.\d+$') -addFilter(r'self-obsoletion python3\.\d+ obsoletes python3\.\d+') - -# intentionally hardcoded -addFilter(r'hardcoded-library-path in %{_prefix}/lib/(debug/%{_libdir}|python%{pybasever})') - -# we have non binary stuff, python files -addFilter(r'only-non-binary-in-usr-lib') - -# some devel files that are deliberately needed -addFilter(r'devel-file-in-non-devel-package /usr/include/python3\.\d+m?/pyconfig-(32|64)\.h') -addFilter(r'devel-file-in-non-devel-package /usr/lib(64)?/python3\.\d+/distutils/tests/xxmodule\.c') - -# some bytecode is shipped without sources on purpose, as a space optimization -# if this regex needs to be relaxed in the future, make sure it **does not** match pyc files in __pycache__ -addFilter(r'python-bytecode-without-source /usr/lib(64)?/python3\.\d+/(encodings|pydoc_data)/[^/]+.pyc') - -# SORRY, NOT SORRY: -# manual pages -addFilter(r'no-manual-page-for-binary (idle|pydoc|pyvenv|2to3|python3?-debug|pathfix|msgfmt|pygettext)') -addFilter(r'no-manual-page-for-binary python3?.*-config$') -addFilter(r'no-manual-page-for-binary python3\.\d+dm?$') - -# missing documentation from subpackages -addFilter(r'^python3(\.\d+)?-(debug|tkinter|test|idle)\.[^:]+: (E|W): no-documentation') - -# platform python is obsoleted, but not provided -addFilter(r'obsolete-not-provided platform-python') - -# we have extra tokens at the end of %endif/%else directives, we consider them useful -addFilter(r'extra tokens at the end of %(endif|else) directive') - - -# RPMLINT IMPERFECTIONS -# https://github.com/rpm-software-management/rpmlint/issues/123 -addFilter(r'python-bytecode-wrong-magic-value .* expected 33\d\d \(3\.7\), found 3393') -# https://github.com/rpm-software-management/rpmlint/pull/133 -addFilter(r'python-bytecode-wrong-magic-value .* expected 33\d\d \(3\.7\), found 3394') - -# https://bugzilla.redhat.com/show_bug.cgi?id=1550562 -# https://github.com/rpm-software-management/rpmlint/issues/128 -addFilter(r'python-bytecode-inconsistent-mtime .* 1970') - -# we provide python(abi) manually to be sure. createrepo will merge this with the automatic -addFilter(r'python3(\.\d+)?\.[^:-]+: (E|W): useless-provides python\(abi\)') - -# debugsource -addFilter(r'^python3(\.\d+)?-debugsource\.[^:]+: (E|W): no-documentation') - -# debuginfo -addFilter(r'^python3(\.\d+)?-debuginfo\.[^:]+: (E|W): useless-provides debuginfo\(build-id\)') - -# this is OK for F28+ -addFilter(r'library-without-ldconfig-post') - -# debug package contains devel and non-devel files -addFilter(r'python3(\.\d+)?-debug\.[^:]+: (E|W): (non-)?devel-file-in-(non-)?devel-package') - -# this goes to other subpackage, hence not actually dangling, the read error is bogus -addFilter(r'dangling-relative-symlink /usr/lib(64)?/pkgconfig/python-3\.\d+dm?(-embed)?\.pc python-3\.\d+(-embed)?\.pc') -addFilter(r'read-error /usr/lib(64)?/pkgconfig/python-3\.\d+dm?(-embed)?\.pc \[Errno 2\]') - -# the python-unversioned-command package contains dangling symlinks by design -addFilter(r'^python-unversioned-command\.[^:]+: (E|W): dangling-relative-symlink ' - r'(/usr/bin/python \./python3|/usr/share/man/man1/python\.1\S* ./python3\.1\S*)$') - -# we need this macro to evaluate, even if the line starts with # -addFilter(r'macro-in-comment %\{_pyconfig(32|64)_h\}') - -# Python modules don't need to be linked against libc -# Since 3.8 they are no longer linked against libpython3.8.so.1.0 -addFilter(r'(E|W): library-not-linked-against-libc /usr/lib(64)?/python3\.\d+/lib-dynload/') -addFilter(r'(E|W): shared-lib-without-dependency-information /usr/lib(64)?/python3\.\d+/lib-dynload/') - -# specfile-errors are listed twice, once with reason and once without -# we filter out the empty ones -addFilter(r'\bpython3(\.\d+)?\.(src|spec): (E|W): specfile-error\s+$') - -# SPELLING ERRORS -addFilter(r'spelling-error .* en_US (bytecode|pyc|filename|tkinter|namespaces|pytest) ') diff --git a/rpmlint.toml b/rpmlint.toml new file mode 100644 index 0000000..b0b30a6 --- /dev/null +++ b/rpmlint.toml @@ -0,0 +1,88 @@ +Filters = [ + + # KNOWN BUGS: + # https://bugzilla.redhat.com/show_bug.cgi?id=1489816 + 'crypto-policy-non-compliance-openssl', + + + # TESTS: + '(zero-length|pem-certificate|uncompressed-zip) /usr/lib(64)?/python3\.\d+/test', + + + # OTHER DELIBERATES: + # chroot function + 'missing-call-to-chdir-with-chroot', + + # intentionally unversioned and selfobsoleted + 'unversioned-explicit-obsoletes python', + 'unversioned Obsoletes: Obsoletes: python3\.\d+$', + 'self-obsoletion python3\.\d+(-\S+)? obsoletes python3\.\d+(-\S+)?', + + # intentionally hardcoded + 'hardcoded-library-path in %{_prefix}/lib/(debug/%{_libdir}|python%{pybasever})', + + # we have non binary stuff, python files + 'only-non-binary-in-usr-lib', + + # some devel files that are deliberately needed + 'devel-file-in-non-devel-package /usr/include/python3\.\d+m?/pyconfig-(32|64)\.h', + 'devel-file-in-non-devel-package /usr/lib(64)?/python3\.\d+/distutils/tests/xxmodule\.c', + + # some bytecode is shipped without sources on purpose, as a space optimization + # if this regex needs to be relaxed in the future, make sure it **does not** match pyc files in __pycache__ + 'python-bytecode-without-source /usr/lib(64)?/python3\.\d+/(encodings|pydoc_data)/[^/]+.pyc', + + # SORRY, NOT SORRY: + # manual pages + 'no-manual-page-for-binary (idle|pydoc|pyvenv|2to3|python3?-debug|pathfix|msgfmt|pygettext)', + 'no-manual-page-for-binary python3?.*-config$', + 'no-manual-page-for-binary python3\.\d+dm?$', + + # missing documentation from subpackages + '^python3(\.\d+)?-(debug|tkinter|test|idle)\.[^:]+: (E|W): no-documentation', + + # platform python is obsoleted, but not provided + 'obsolete-not-provided platform-python', + + # we have extra tokens at the end of %endif/%else directives, we consider them useful + 'extra tokens at the end of %(endif|else) directive', + + + # RPMLINT IMPERFECTIONS + # https://github.com/rpm-software-management/rpmlint/issues/780 + '/usr/lib/debug', + + # we provide python(abi) manually to be sure. createrepo will merge this with the automatic + 'python3(\.\d+)?\.[^:-]+: (E|W): useless-provides python\(abi\)', + + # debugsource and debuginfo have no docs + '^python3(\.\d+)?-debug(source|info)\.[^:]+: (E|W): no-documentation', + + # this is OK for F28+ + 'library-without-ldconfig-post', + + # debug package contains devel and non-devel files + 'python3(\.\d+)?-debug\.[^:]+: (E|W): (non-)?devel-file-in-(non-)?devel-package', + + # this goes to other subpackage, hence not actually dangling + 'dangling-relative-symlink /usr/lib(64)?/pkgconfig/python-3\.\d+dm?(-embed)?\.pc python-3\.\d+(-embed)?\.pc', + + # the python-unversioned-command package contains dangling symlinks by design + '^python-unversioned-command\.[^:]+: (E|W): dangling-relative-symlink (/usr/bin/python \./python3|/usr/share/man/man1/python\.1\S* ./python3\.1\S*)$', + + # we need this macro to evaluate, even if the line starts with # + 'macro-in-comment %\{_pyconfig(32|64)_h\}', + + # Python modules don't need to be linked against libc + # Since 3.8 they are no longer linked against libpython3.8.so.1.0 + '(E|W): library-not-linked-against-libc /usr/lib(64)?/python3\.\d+/lib-dynload/', + '(E|W): shared-lib(rary)?-without-dependency-information /usr/lib(64)?/python3\.\d+/lib-dynload/', + + # specfile-errors are listed twice, once with reason and once without + # we filter out the empty ones + '\bpython3(\.\d+)?\.(src|spec): (E|W): specfile-error\s+$', + + # SPELLING ERRORS + 'spelling-error .* en_US (bytecode|pyc|filename|tkinter|namespaces|pytest) ', + +] From a71ba977876be314fc59759bce0f9f7eaea55af3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Fri, 5 Aug 2022 16:25:25 +0200 Subject: [PATCH 044/118] Add more rpmlint rules to avoid all reports we see and don't care about --- rpmlint.toml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/rpmlint.toml b/rpmlint.toml index b0b30a6..89e75b6 100644 --- a/rpmlint.toml +++ b/rpmlint.toml @@ -13,6 +13,9 @@ Filters = [ # chroot function 'missing-call-to-chdir-with-chroot', + # gethostbyname function calls gethostbyname + '(E|W): binary-or-shlib-calls-gethostbyname /usr/lib(64)?/python3\.\d+/lib-dynload/_socket\.', + # intentionally unversioned and selfobsoleted 'unversioned-explicit-obsoletes python', 'unversioned Obsoletes: Obsoletes: python3\.\d+$', @@ -27,11 +30,24 @@ Filters = [ # some devel files that are deliberately needed 'devel-file-in-non-devel-package /usr/include/python3\.\d+m?/pyconfig-(32|64)\.h', 'devel-file-in-non-devel-package /usr/lib(64)?/python3\.\d+/distutils/tests/xxmodule\.c', + # ...or are used as test data + 'devel-file-in-non-devel-package /usr/lib(64)?/python3\.\d+/test', # some bytecode is shipped without sources on purpose, as a space optimization # if this regex needs to be relaxed in the future, make sure it **does not** match pyc files in __pycache__ 'python-bytecode-without-source /usr/lib(64)?/python3\.\d+/(encodings|pydoc_data)/[^/]+.pyc', + # DUPLICATE FILES + # test data are often duplicated + '(E|W): files-duplicate /usr/lib(64)?/python3\.\d+/(test|__phello__)/', + # duplicated inits or mains are also common + '(E|W): files-duplicate .+__init__\.py.+__init__\.py', + '(E|W): files-duplicate .+__main__\.py.+__main__\.py', + # files in the debugsource package + '(E|W): files-duplicate /usr/src/debug', + # general waste report + '(E|W): files-duplicated-waste', + # SORRY, NOT SORRY: # manual pages 'no-manual-page-for-binary (idle|pydoc|pyvenv|2to3|python3?-debug|pathfix|msgfmt|pygettext)', @@ -65,6 +81,8 @@ Filters = [ 'python3(\.\d+)?-debug\.[^:]+: (E|W): (non-)?devel-file-in-(non-)?devel-package', # this goes to other subpackage, hence not actually dangling + 'dangling-relative-symlink /usr/bin/python python3', + 'dangling-relative-symlink /usr/share/man/man1/python\.1\.gz python3\.1\.gz', 'dangling-relative-symlink /usr/lib(64)?/pkgconfig/python-3\.\d+dm?(-embed)?\.pc python-3\.\d+(-embed)?\.pc', # the python-unversioned-command package contains dangling symlinks by design From 0c6709aa1336854a7225749f4e74c0c868e63601 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Mon, 5 Sep 2022 11:20:40 +0200 Subject: [PATCH 045/118] rpmlint: Remove a superfluous space in one of the filters The warnings look like: python3.11-debugsource.x86_64: W: files-duplicate /usr/src/debug/python3.11-3.11.0~rc1-2.fc38.x86_64/build/optimized/Include/pydtrace_probes.h /usr/src/debug/python3.11-3.11.0~rc1-2.fc38.x86_64/build/debug/Include/pydtrace_probes.h python3.11-debugsource.x86_64: W: files-duplicate /usr/src/debug/python3.11-3.11.0~rc1-2.fc38.x86_64/build/optimized/Modules/config.c /usr/src/debug/python3.11-3.11.0~rc1-2.fc38.x86_64/build/debug/Modules/config.c python3.11-debugsource.x86_64: W: files-duplicate /usr/src/debug/python3.11-3.11.0~rc1-2.fc38.x86_64/build/optimized/Python/deepfreeze/deepfreeze.c /usr/src/debug/python3.11-3.11.0~rc1-2.fc38.x86_64/build/debug/Python/deepfreeze/deepfreeze.c python3.11-debugsource.x86_64: W: files-duplicate /usr/src/debug/python3.11-3.11.0~rc1-2.fc38.x86_64/build/optimized/Python/frozen_modules/getpath.h /usr/src/debug/python3.11-3.11.0~rc1-2.fc38.x86_64/build/debug/Python/frozen_modules/getpath.h --- rpmlint.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rpmlint.toml b/rpmlint.toml index 89e75b6..b532441 100644 --- a/rpmlint.toml +++ b/rpmlint.toml @@ -44,7 +44,7 @@ Filters = [ '(E|W): files-duplicate .+__init__\.py.+__init__\.py', '(E|W): files-duplicate .+__main__\.py.+__main__\.py', # files in the debugsource package - '(E|W): files-duplicate /usr/src/debug', + '(E|W): files-duplicate /usr/src/debug', # general waste report '(E|W): files-duplicated-waste', From 216f3d53bcdd8415503a7541552ca566e097ae07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Mon, 18 Jul 2022 21:36:19 +0200 Subject: [PATCH 046/118] rpminspect: Explicitly list allowed badfuncs in the _socket module See https://github.com/rpminspect/rpminspect/pull/805 --- rpminspect.yaml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/rpminspect.yaml b/rpminspect.yaml index a111efb..83dfb5e 100644 --- a/rpminspect.yaml +++ b/rpminspect.yaml @@ -6,8 +6,10 @@ xml: # exclude _socket from ipv4 only functions check, it has both ipv4 and ipv6 only badfuncs: - ignore: - - /usr/lib*/python*/lib-dynload/_socket.* + allowed: + /usr/lib*/python*/lib-dynload/_socket.*: + - inet_aton + - inet_ntoa # exclude the debug build from annocheck entirely annocheck: From 38b3f29b55281d2244b82e1226e4893f0bf8940e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Tue, 13 Sep 2022 11:00:55 +0200 Subject: [PATCH 047/118] Update to 3.11.0rc2 --- ...g-_shutdown-for-the-main-thread-gh-28549-gh-28589.patch | 2 +- python3.11.spec | 7 +++++-- sources | 4 ++-- 3 files changed, 8 insertions(+), 5 deletions(-) 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 635b682..1d39233 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 @@ -60,7 +60,7 @@ index 9c6561c099..84714c03fe 100644 class ThreadJoinOnShutdown(BaseTestCase): diff --git a/Lib/threading.py b/Lib/threading.py -index 8e7cdf6f62..a701401f28 100644 +index 4f72938551..18c10e6489 100644 --- a/Lib/threading.py +++ b/Lib/threading.py @@ -1546,29 +1546,20 @@ def _shutdown(): diff --git a/python3.11.spec b/python3.11.spec index 67b517f..2923fd5 100644 --- a/python3.11.spec +++ b/python3.11.spec @@ -14,10 +14,10 @@ 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}.0 -%global prerel rc1 +%global prerel rc2 %global upstream_version %{general_version}%{?prerel} Version: %{general_version}%{?prerel:~%{prerel}} -Release: 2%{?dist} +Release: 1%{?dist} License: Python @@ -1595,6 +1595,9 @@ CheckPython optimized # ====================================================== %changelog +* Tue Sep 13 2022 Miro Hrončok - 3.11.0~rc2-1 +- Update to 3.11.0rc2 + * Tue Aug 09 2022 Miro Hrončok - 3.11.0~rc1-2 - Don't use custom installation schemes - Fixes rhbz#2026979 diff --git a/sources b/sources index ffb6ae6..345b6b6 100644 --- a/sources +++ b/sources @@ -1,2 +1,2 @@ -SHA512 (Python-3.11.0rc1.tar.xz) = 2a72ea59277f8115e418ced671969fc0d5ba271c7740f70c665a4b450a59d7752278d061bd59f136dacfa608ed167f983c6589b214a973b1b63ea2115ea298bb -SHA512 (Python-3.11.0rc1.tar.xz.asc) = d4cffc90c2ed7b8ea7228a21f7ac902a92f27003f1420ad751b1691de950974ea174cb0471b6e19ed1548dc5382012fa9ad5fcf83c34646c7ea2d73c88799e38 +SHA512 (Python-3.11.0rc2.tar.xz) = 8b37bc9df3c966bd35cffdb7d6406a3c1a5ccfbea10bd8dad498880e3b1492f8cdbbe227ab3a30557843eb05d8fb93077c791e25d71b33ed420992d54b6c9473 +SHA512 (Python-3.11.0rc2.tar.xz.asc) = 13e6bfa719db29aa169763399203168923cbfbb01d209e18269399ca84723582f480134edd3bf9f24785cd5ab0486411132d6bbb354fa45ebbba68bf4c70021a From 2d800732862d491c7f7c355c86d86467c249b1ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Tue, 23 Aug 2022 12:44:36 +0200 Subject: [PATCH 048/118] Update the license tag to SPDX See https://gitlab.com/fedora/legal/fedora-license-data/-/merge_requests/61 The LICENSE file differs from the text at https://spdx.org/licenses/Python-2.0.1.html only by: - not saying "Python 2.0.1" but "Python" which is considered OK - copyright years which is considered OK - formatting - listing the history and license for code examples from the documentation (the documentation is not shipped via this package) --- python3.11.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python3.11.spec b/python3.11.spec index 2923fd5..cbde66d 100644 --- a/python3.11.spec +++ b/python3.11.spec @@ -18,7 +18,7 @@ URL: https://www.python.org/ %global upstream_version %{general_version}%{?prerel} Version: %{general_version}%{?prerel:~%{prerel}} Release: 1%{?dist} -License: Python +License: Python-2.0.1 # ================================== From 58109b55ab538920043beccd697870fc8002ac01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Tue, 25 Oct 2022 00:46:26 +0200 Subject: [PATCH 049/118] Update to 3.11.0 --- python3.11.spec | 9 ++++++--- sources | 4 ++-- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/python3.11.spec b/python3.11.spec index cbde66d..1d5c46c 100644 --- a/python3.11.spec +++ b/python3.11.spec @@ -14,7 +14,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}.0 -%global prerel rc2 +#global prerel ... %global upstream_version %{general_version}%{?prerel} Version: %{general_version}%{?prerel:~%{prerel}} Release: 1%{?dist} @@ -67,8 +67,8 @@ License: Python-2.0.1 # If the rpmwheels condition is disabled, we use the bundled wheel packages # from Python with the versions below. # This needs to be manually updated when we update Python. -%global pip_version 22.2.2 -%global setuptools_version 63.2.0 +%global pip_version 22.3 +%global setuptools_version 65.5.0 # Expensive optimizations (mainly, profile-guided optimizations) %bcond_without optimizations @@ -1595,6 +1595,9 @@ CheckPython optimized # ====================================================== %changelog +* Mon Oct 24 2022 Miro Hrončok - 3.11.0-1 +- Update to 3.11.0 + * Tue Sep 13 2022 Miro Hrončok - 3.11.0~rc2-1 - Update to 3.11.0rc2 diff --git a/sources b/sources index 345b6b6..5763e8f 100644 --- a/sources +++ b/sources @@ -1,2 +1,2 @@ -SHA512 (Python-3.11.0rc2.tar.xz) = 8b37bc9df3c966bd35cffdb7d6406a3c1a5ccfbea10bd8dad498880e3b1492f8cdbbe227ab3a30557843eb05d8fb93077c791e25d71b33ed420992d54b6c9473 -SHA512 (Python-3.11.0rc2.tar.xz.asc) = 13e6bfa719db29aa169763399203168923cbfbb01d209e18269399ca84723582f480134edd3bf9f24785cd5ab0486411132d6bbb354fa45ebbba68bf4c70021a +SHA512 (Python-3.11.0.tar.xz) = 314eef88ae0d68760f34d7a32f238fd2ecb27c50963baa7357c42ad8159026ec50229a0b31d83c39710a472904a06422afc082f9658a90a1dc83ccb74c08039d +SHA512 (Python-3.11.0.tar.xz.asc) = d20fb152c5b16cfef1f59af588f7576eb45c903d9e15fd4ad0e15fd32bef7ffd951b99a062d2944234ecffcf29eb9266544e92d2f6584710cbb20ba38f8ac224 From 19bf071b14429785697266e02160592a27682f91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Hrn=C4=8Diar?= Date: Wed, 7 Dec 2022 11:57:51 +0100 Subject: [PATCH 050/118] Update to 3.11.1 --- 00251-change-user-install-location.patch | 2 +- python3.11.spec | 7 +++++-- sources | 4 ++-- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/00251-change-user-install-location.patch b/00251-change-user-install-location.patch index 6c3caac..53096ec 100644 --- a/00251-change-user-install-location.patch +++ b/00251-change-user-install-location.patch @@ -160,7 +160,7 @@ index ebe3711827..55af57b335 100644 # On Windows we want to substitute 'lib' for schemes rather # than the native value (without modifying vars, in case it diff --git a/Lib/test/test_sysconfig.py b/Lib/test/test_sysconfig.py -index 578ac1db50..dc58e7db18 100644 +index d96371d242..72b028435f 100644 --- a/Lib/test/test_sysconfig.py +++ b/Lib/test/test_sysconfig.py @@ -111,8 +111,19 @@ def test_get_path(self): diff --git a/python3.11.spec b/python3.11.spec index 1d5c46c..8f48027 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}.0 +%global general_version %{pybasever}.1 #global prerel ... %global upstream_version %{general_version}%{?prerel} Version: %{general_version}%{?prerel:~%{prerel}} @@ -67,7 +67,7 @@ License: Python-2.0.1 # If the rpmwheels condition is disabled, we use the bundled wheel packages # from Python with the versions below. # This needs to be manually updated when we update Python. -%global pip_version 22.3 +%global pip_version 22.3.1 %global setuptools_version 65.5.0 # Expensive optimizations (mainly, profile-guided optimizations) @@ -1595,6 +1595,9 @@ CheckPython optimized # ====================================================== %changelog +* Wed Dec 07 2022 Tomáš Hrnčiar - 3.11.1-1 +- Update to 3.11.1 + * Mon Oct 24 2022 Miro Hrončok - 3.11.0-1 - Update to 3.11.0 diff --git a/sources b/sources index 5763e8f..327dc94 100644 --- a/sources +++ b/sources @@ -1,2 +1,2 @@ -SHA512 (Python-3.11.0.tar.xz) = 314eef88ae0d68760f34d7a32f238fd2ecb27c50963baa7357c42ad8159026ec50229a0b31d83c39710a472904a06422afc082f9658a90a1dc83ccb74c08039d -SHA512 (Python-3.11.0.tar.xz.asc) = d20fb152c5b16cfef1f59af588f7576eb45c903d9e15fd4ad0e15fd32bef7ffd951b99a062d2944234ecffcf29eb9266544e92d2f6584710cbb20ba38f8ac224 +SHA512 (Python-3.11.1.tar.xz) = 5edd70c881e083c96199c60471f18f9ebc4c97a2d45dc66f89e16d7c3638d8a5d2cbf2e84b1be3d7f1178ce9f7fa4197884385c1ee3618ff66a538f872f318ed +SHA512 (Python-3.11.1.tar.xz.asc) = 81ed05c2adf38552bdc5ac761704f2720a646d56681a919a6bfa51f1a4b42cd14edb9c84d58664dbc8e7b561cd78d82ae6b10dda423e1fae543bc7fa4bf3f78e From 11c77ae3885da670bff924479a50228fe0951b64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Mon, 19 Dec 2022 14:51:17 +0000 Subject: [PATCH 051/118] No longer patch the default bytecode cache invalidation policy That is, drop patch 328. Fixes https://bugzilla.redhat.com/2133850 See also https://src.fedoraproject.org/rpms/python-rpm-macros/pull-request/154 This is part of https://fedoraproject.org/wiki/Changes/ReproducibleBuildsClampMtimes --- 00328-pyc-timestamp-invalidation-mode.patch | 54 --------------------- check-pyc-timestamps.py | 8 ++- python3.11.spec | 31 ++++++------ 3 files changed, 18 insertions(+), 75 deletions(-) delete mode 100644 00328-pyc-timestamp-invalidation-mode.patch diff --git a/00328-pyc-timestamp-invalidation-mode.patch b/00328-pyc-timestamp-invalidation-mode.patch deleted file mode 100644 index d04a267..0000000 --- a/00328-pyc-timestamp-invalidation-mode.patch +++ /dev/null @@ -1,54 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= -Date: Thu, 11 Jul 2019 13:44:13 +0200 -Subject: [PATCH] 00328: Restore pyc to TIMESTAMP invalidation mode as default - in rpmbuild - -Since Fedora 31, the $SOURCE_DATE_EPOCH is set in rpmbuild to the latest -%changelog date. This makes Python default to the CHECKED_HASH pyc -invalidation mode, bringing more reproducible builds traded for an import -performance decrease. To avoid that, we don't default to CHECKED_HASH -when $RPM_BUILD_ROOT is set (i.e. when we are building RPM packages). - -See https://src.fedoraproject.org/rpms/redhat-rpm-config/pull-request/57#comment-27426 -Downstream only: only used when building RPM packages -Ideally, we should talk to upstream and explain why we don't want this ---- - Lib/py_compile.py | 3 ++- - Lib/test/test_py_compile.py | 2 ++ - 2 files changed, 4 insertions(+), 1 deletion(-) - -diff --git a/Lib/py_compile.py b/Lib/py_compile.py -index 388614e51b..db52725016 100644 ---- a/Lib/py_compile.py -+++ b/Lib/py_compile.py -@@ -70,7 +70,8 @@ class PycInvalidationMode(enum.Enum): - - - def _get_default_invalidation_mode(): -- if os.environ.get('SOURCE_DATE_EPOCH'): -+ if (os.environ.get('SOURCE_DATE_EPOCH') and not -+ os.environ.get('RPM_BUILD_ROOT')): - return PycInvalidationMode.CHECKED_HASH - else: - return PycInvalidationMode.TIMESTAMP -diff --git a/Lib/test/test_py_compile.py b/Lib/test/test_py_compile.py -index a4a52b180d..e53f5d92aa 100644 ---- a/Lib/test/test_py_compile.py -+++ b/Lib/test/test_py_compile.py -@@ -19,6 +19,7 @@ def without_source_date_epoch(fxn): - def wrapper(*args, **kwargs): - with os_helper.EnvironmentVarGuard() as env: - env.unset('SOURCE_DATE_EPOCH') -+ env.unset('RPM_BUILD_ROOT') - return fxn(*args, **kwargs) - return wrapper - -@@ -29,6 +30,7 @@ def with_source_date_epoch(fxn): - def wrapper(*args, **kwargs): - with os_helper.EnvironmentVarGuard() as env: - env['SOURCE_DATE_EPOCH'] = '123456789' -+ env.unset('RPM_BUILD_ROOT') - return fxn(*args, **kwargs) - return wrapper - diff --git a/check-pyc-timestamps.py b/check-pyc-timestamps.py index 91af4fd..e421fca 100644 --- a/check-pyc-timestamps.py +++ b/check-pyc-timestamps.py @@ -19,11 +19,9 @@ not_compiled = [ '*/test/bad_coding.py', '*/test/bad_coding2.py', '*/test/badsyntax_*.py', - '*/lib2to3/tests/data/bom.py', - '*/lib2to3/tests/data/crlf.py', - '*/lib2to3/tests/data/different_encoding.py', - '*/lib2to3/tests/data/false_encoding.py', - '*/lib2to3/tests/data/py2_test_grammar.py', + '*/lib2to3/tests/data/*.py', + '*/lib2to3/tests/data/*/*.py', + '*/lib2to3/tests/data/*/*/*.py', '*.debug-gdb.py', ] diff --git a/python3.11.spec b/python3.11.spec index 8f48027..e870792 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 @@ -298,20 +298,6 @@ Patch1: 00001-rpath.patch # pypa/distutils integration: https://github.com/pypa/distutils/pull/70 Patch251: 00251-change-user-install-location.patch -# 00328 # 318e500c98f5e59eb1f23e0fcd32db69b9bd17e1 -# Restore pyc to TIMESTAMP invalidation mode as default in rpmbuild -# -# Since Fedora 31, the $SOURCE_DATE_EPOCH is set in rpmbuild to the latest -# %%changelog date. This makes Python default to the CHECKED_HASH pyc -# invalidation mode, bringing more reproducible builds traded for an import -# performance decrease. To avoid that, we don't default to CHECKED_HASH -# when $RPM_BUILD_ROOT is set (i.e. when we are building RPM packages). -# -# See https://src.fedoraproject.org/rpms/redhat-rpm-config/pull-request/57#comment-27426 -# Downstream only: only used when building RPM packages -# Ideally, we should talk to upstream and explain why we don't want this -Patch328: 00328-pyc-timestamp-invalidation-mode.patch - # 00371 # c1754d9c2750f89cb702e1b63a99201f5f7cff00 # Revert "bpo-1596321: Fix threading._shutdown() for the main thread (GH-28549) (GH-28589)" # @@ -945,15 +931,25 @@ find . -name "*~" -exec rm -f {} \; # Python CMD line options: # -s - don't add user site directory to sys.path # -B - don't write .pyc files on import +# Clamp the source mtime first, see https://fedoraproject.org/wiki/Changes/ReproducibleBuildsClampMtimes +# The clamp_source_mtime module is only guaranteed to exist on Fedoras that enabled this option: +%if 0%{?clamp_mtime_to_source_date_epoch} +LD_LIBRARY_PATH="%{buildroot}%{dynload_dir}/:%{buildroot}%{_libdir}" \ +PYTHONPATH="%{_rpmconfigdir}/redhat" \ +%{buildroot}%{_bindir}/python%{pybasever} -s -B -m clamp_source_mtime %{buildroot}%{pylibdir} +%endif # compileall CMD line options: # -f - force rebuild even if timestamps are up to date # -o - optimization levels to run compilation with # -s - part of path to left-strip from path to source file (buildroot) # -p - path to add as prefix to path to source file (/ to make it absolute) # --hardlink-dupes - hardlink different optimization level pycs together if identical (saves space) +# --invalidation-mode - we prefer the timestamp invalidation mode for performance reasons +# -x - skip test modules with SyntaxErrors (taken from the Makefile) LD_LIBRARY_PATH="%{buildroot}%{dynload_dir}/:%{buildroot}%{_libdir}" \ %{buildroot}%{_bindir}/python%{pybasever} -s -B -m compileall \ --f %{_smp_mflags} -o 0 -o 1 -o 2 -s %{buildroot} -p / %{buildroot} --hardlink-dupes || : +-f %{_smp_mflags} -o 0 -o 1 -o 2 -s %{buildroot} -p / %{buildroot} --hardlink-dupes --invalidation-mode=timestamp \ +-x 'bad_coding|badsyntax|site-packages|lib2to3/tests/data' # Turn this BRP off, it is done by compileall2 --hardlink-dupes above %global __brp_python_hardlink %{nil} @@ -1595,6 +1591,9 @@ CheckPython optimized # ====================================================== %changelog +* Mon Dec 19 2022 Miro Hrončok - 3.11.1-2 +- No longer patch the default bytecode cache invalidation policy + * Wed Dec 07 2022 Tomáš Hrnčiar - 3.11.1-1 - Update to 3.11.1 From ec7d75e3d1217d306fe2feda665fef3986c8ae78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Wed, 4 Jan 2023 12:24:50 +0100 Subject: [PATCH 052/118] Opt-out from https://fedoraproject.org/wiki/Changes/fno-omit-frame-pointer See https://lists.fedoraproject.org/archives/list/python-devel@lists.fedoraproject.org/thread/6TQYCHMX4FZLF27U5BCEC7IFV6XNBKJP/ for rationale, namely https://lists.fedoraproject.org/archives/list/python-devel@lists.fedoraproject.org/message/ZVDEXGPU6JQFXB3XHYZ4IXVQNNR3YM3V/ Summary: Python is currently slower with frame pointers due to a slowdown in _PyEval_EvalFrameDefault, but we expect this to be solved in Python 3.12. Tracking bugzilla: https://bugzilla.redhat.com/2158729 This change does not require a release bump. It is only needed to be here to prevent the next builds from including frame pointers. --- python3.11.spec | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/python3.11.spec b/python3.11.spec index e870792..5fac9d8 100644 --- a/python3.11.spec +++ b/python3.11.spec @@ -175,6 +175,12 @@ Obsoletes: python%{pybasever}%{?1:-%{1}}\ %define unversioned_obsoletes_of_python3_X_if_main() %{nil} %endif +# Opt-out from https://fedoraproject.org/wiki/Changes/fno-omit-frame-pointer +# Python is slower with frame pointers, but we expect to remove this in Python 3.12+ +# See https://lists.fedoraproject.org/archives/list/python-devel@lists.fedoraproject.org/thread/6TQYCHMX4FZLF27U5BCEC7IFV6XNBKJP/ +# Tracking bugzilla: https://bugzilla.redhat.com/2158729 +%undefine _include_frame_pointers + # ======================= # Build-time requirements # ======================= From 06ef941d951e5a25f6a4acbacee286a7e97c1af6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Fri, 6 Jan 2023 15:37:38 +0100 Subject: [PATCH 053/118] Fix `asyncio` subprocess losing `stderr` and `stdout` output Reported as a regression in https://bodhi.fedoraproject.org/updates/FEDORA-2022-dbb811d203 --- ...cess-losing-stderr-and-stdout-output.patch | 66 +++++++++++++++++++ python3.11.spec | 9 ++- 2 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 00395-gh-100133-fix-asyncio-subprocess-losing-stderr-and-stdout-output.patch diff --git a/00395-gh-100133-fix-asyncio-subprocess-losing-stderr-and-stdout-output.patch b/00395-gh-100133-fix-asyncio-subprocess-losing-stderr-and-stdout-output.patch new file mode 100644 index 0000000..c480127 --- /dev/null +++ b/00395-gh-100133-fix-asyncio-subprocess-losing-stderr-and-stdout-output.patch @@ -0,0 +1,66 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: "Miss Islington (bot)" + <31488909+miss-islington@users.noreply.github.com> +Date: Wed, 21 Dec 2022 02:24:19 -0800 +Subject: [PATCH] 00395: GH-100133: fix `asyncio` subprocess losing `stderr` + and `stdout` output + +(cherry picked from commit a7715ccfba5b86ab09f86ec56ac3755c93b46b48) + +Co-authored-by: Kumar Aditya <59607654+kumaraditya303@users.noreply.github.com> +--- + Lib/asyncio/base_subprocess.py | 3 --- + Lib/test/test_asyncio/test_subprocess.py | 17 +++++++++++++++++ + ...22-12-10-08-36-07.gh-issue-100133.g-zQlp.rst | 1 + + 3 files changed, 18 insertions(+), 3 deletions(-) + create mode 100644 Misc/NEWS.d/next/Library/2022-12-10-08-36-07.gh-issue-100133.g-zQlp.rst + +diff --git a/Lib/asyncio/base_subprocess.py b/Lib/asyncio/base_subprocess.py +index e15bb4141f..4c9b0dd565 100644 +--- a/Lib/asyncio/base_subprocess.py ++++ b/Lib/asyncio/base_subprocess.py +@@ -215,9 +215,6 @@ def _process_exited(self, returncode): + # object. On Python 3.6, it is required to avoid a ResourceWarning. + self._proc.returncode = returncode + self._call(self._protocol.process_exited) +- for p in self._pipes.values(): +- if p is not None: +- p.pipe.close() + + self._try_finish() + +diff --git a/Lib/test/test_asyncio/test_subprocess.py b/Lib/test/test_asyncio/test_subprocess.py +index f71ad72f99..bea2314a52 100644 +--- a/Lib/test/test_asyncio/test_subprocess.py ++++ b/Lib/test/test_asyncio/test_subprocess.py +@@ -684,6 +684,23 @@ async def execute(): + + self.assertIsNone(self.loop.run_until_complete(execute())) + ++ def test_subprocess_communicate_stdout(self): ++ # See https://github.com/python/cpython/issues/100133 ++ async def get_command_stdout(cmd, *args): ++ proc = await asyncio.create_subprocess_exec( ++ cmd, *args, stdout=asyncio.subprocess.PIPE, ++ ) ++ stdout, _ = await proc.communicate() ++ return stdout.decode().strip() ++ ++ async def main(): ++ outputs = [f'foo{i}' for i in range(10)] ++ res = await asyncio.gather(*[get_command_stdout(sys.executable, '-c', ++ f'print({out!r})') for out in outputs]) ++ self.assertEqual(res, outputs) ++ ++ self.loop.run_until_complete(main()) ++ + + if sys.platform != 'win32': + # Unix +diff --git a/Misc/NEWS.d/next/Library/2022-12-10-08-36-07.gh-issue-100133.g-zQlp.rst b/Misc/NEWS.d/next/Library/2022-12-10-08-36-07.gh-issue-100133.g-zQlp.rst +new file mode 100644 +index 0000000000..881e6ed80f +--- /dev/null ++++ b/Misc/NEWS.d/next/Library/2022-12-10-08-36-07.gh-issue-100133.g-zQlp.rst +@@ -0,0 +1 @@ ++Fix regression in :mod:`asyncio` where a subprocess would sometimes lose data received from pipe. diff --git a/python3.11.spec b/python3.11.spec index 5fac9d8..3c01a3b 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 @@ -315,6 +315,10 @@ 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 +# 00395 # 18ff37a92c507144edf32274b356dd1dd734cf07 +# GH-100133: fix `asyncio` subprocess losing `stderr` and `stdout` output +Patch395: 00395-gh-100133-fix-asyncio-subprocess-losing-stderr-and-stdout-output.patch + # (New patches go here ^^^) # # When adding new patches to "python" and "python3" in Fedora, EL, etc., @@ -1597,6 +1601,9 @@ CheckPython optimized # ====================================================== %changelog +* Fri Jan 06 2023 Miro Hrončok - 3.11.1-3 +- Fix `asyncio` subprocess losing `stderr` and `stdout` output + * Mon Dec 19 2022 Miro Hrončok - 3.11.1-2 - No longer patch the default bytecode cache invalidation policy From 01ddee3bb650edd1e5f94296568774aff0db0ac5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Wed, 11 Jan 2023 15:25:19 +0100 Subject: [PATCH 054/118] Remove any deprecation warnings in asyncio.get_event_loop() The warnings were added in 3.11.1 and will be reverted in 3.11.2. They make some Fedora packages fail to build, so we backport the revert. --- ...n-warnings-in-asyncio-get_event_loop.patch | 171 ++++++++++++++++++ python3.11.spec | 7 + 2 files changed, 178 insertions(+) create mode 100644 00396-gh-100160-remove-any-deprecation-warnings-in-asyncio-get_event_loop.patch diff --git a/00396-gh-100160-remove-any-deprecation-warnings-in-asyncio-get_event_loop.patch b/00396-gh-100160-remove-any-deprecation-warnings-in-asyncio-get_event_loop.patch new file mode 100644 index 0000000..bebae56 --- /dev/null +++ b/00396-gh-100160-remove-any-deprecation-warnings-in-asyncio-get_event_loop.patch @@ -0,0 +1,171 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Serhiy Storchaka +Date: Tue, 10 Jan 2023 22:20:09 +0200 +Subject: [PATCH] 00396: gh-100160: Remove any deprecation warnings in + asyncio.get_event_loop() + +Some deprecation warnings will reappear (in a slightly different form) in 3.12. + +Co-authored-by: Guido van Rossum +--- + Doc/library/asyncio-eventloop.rst | 14 +++++++------- + Doc/library/asyncio-policy.rst | 9 +++++---- + Doc/whatsnew/3.10.rst | 13 ------------- + Lib/asyncio/events.py | 15 --------------- + Lib/test/test_asyncio/test_events.py | 12 +++--------- + ...2022-12-21-18-29-24.gh-issue-100160.isBmL5.rst | 2 ++ + 6 files changed, 17 insertions(+), 48 deletions(-) + create mode 100644 Misc/NEWS.d/next/Library/2022-12-21-18-29-24.gh-issue-100160.isBmL5.rst + +diff --git a/Doc/library/asyncio-eventloop.rst b/Doc/library/asyncio-eventloop.rst +index 28b7a90058..886399e7ae 100644 +--- a/Doc/library/asyncio-eventloop.rst ++++ b/Doc/library/asyncio-eventloop.rst +@@ -48,7 +48,7 @@ an event loop: + running event loop. + + If there is no running event loop set, the function will return +- the result of ``get_event_loop_policy().get_event_loop()`` call. ++ the result of the ``get_event_loop_policy().get_event_loop()`` call. + + Because this function has rather complex behavior (especially + when custom event loop policies are in use), using the +@@ -59,15 +59,15 @@ an event loop: + instead of using these lower level functions to manually create and close an + event loop. + +- .. deprecated:: 3.10 +- Deprecation warning is emitted if there is no current event loop. +- In Python 3.12 it will be an error. +- + .. note:: + In Python versions 3.10.0--3.10.8 and 3.11.0 this function +- (and other functions which used it implicitly) emitted a ++ (and other functions which use it implicitly) emitted a + :exc:`DeprecationWarning` if there was no running event loop, even if +- the current loop was set. ++ the current loop was set on the policy. ++ In Python versions 3.10.9, 3.11.1 and 3.12 they emit a ++ :exc:`DeprecationWarning` if there is no running event loop and no ++ current loop is set. ++ In some future Python release this will become an error. + + .. function:: set_event_loop(loop) + +diff --git a/Doc/library/asyncio-policy.rst b/Doc/library/asyncio-policy.rst +index d0af45febd..eb043b3e5e 100644 +--- a/Doc/library/asyncio-policy.rst ++++ b/Doc/library/asyncio-policy.rst +@@ -112,10 +112,11 @@ asyncio ships with the following built-in policies: + + On Windows, :class:`ProactorEventLoop` is now used by default. + +- .. deprecated:: 3.11.1 +- :meth:`get_event_loop` now emits a :exc:`DeprecationWarning` if there +- is no current event loop set and a new event loop has been implicitly +- created. In Python 3.12 it will be an error. ++ .. note:: ++ In Python versions 3.10.9, 3.11.1 and 3.12 this function emits a ++ :exc:`DeprecationWarning` if there is no running event loop and no ++ current loop is set. ++ In some future Python release this will become an error. + + + .. class:: WindowsSelectorEventLoopPolicy +diff --git a/Doc/whatsnew/3.10.rst b/Doc/whatsnew/3.10.rst +index d0b436664a..38b30deff7 100644 +--- a/Doc/whatsnew/3.10.rst ++++ b/Doc/whatsnew/3.10.rst +@@ -1710,19 +1710,6 @@ Deprecated + scheduled for removal in Python 3.12. + (Contributed by Erlend E. Aasland in :issue:`42264`.) + +-* :func:`asyncio.get_event_loop` now emits a deprecation warning if there is +- no running event loop. In the future it will be an alias of +- :func:`~asyncio.get_running_loop`. +- :mod:`asyncio` functions which implicitly create :class:`~asyncio.Future` +- or :class:`~asyncio.Task` objects now emit +- a deprecation warning if there is no running event loop and no explicit +- *loop* argument is passed: :func:`~asyncio.ensure_future`, +- :func:`~asyncio.wrap_future`, :func:`~asyncio.gather`, +- :func:`~asyncio.shield`, :func:`~asyncio.as_completed` and constructors of +- :class:`~asyncio.Future`, :class:`~asyncio.Task`, +- :class:`~asyncio.StreamReader`, :class:`~asyncio.StreamReaderProtocol`. +- (Contributed by Serhiy Storchaka in :issue:`39529`.) +- + * The undocumented built-in function ``sqlite3.enable_shared_cache`` is now + deprecated, scheduled for removal in Python 3.12. Its use is strongly + discouraged by the SQLite3 documentation. See `the SQLite3 docs +diff --git a/Lib/asyncio/events.py b/Lib/asyncio/events.py +index af3f9e970b..b1799320ea 100644 +--- a/Lib/asyncio/events.py ++++ b/Lib/asyncio/events.py +@@ -671,21 +671,6 @@ def get_event_loop(self): + if (self._local._loop is None and + not self._local._set_called and + threading.current_thread() is threading.main_thread()): +- stacklevel = 2 +- try: +- f = sys._getframe(1) +- except AttributeError: +- pass +- else: +- while f: +- module = f.f_globals.get('__name__') +- if not (module == 'asyncio' or module.startswith('asyncio.')): +- break +- f = f.f_back +- stacklevel += 1 +- import warnings +- warnings.warn('There is no current event loop', +- DeprecationWarning, stacklevel=stacklevel) + self.set_event_loop(self.new_event_loop()) + + if self._local._loop is None: +diff --git a/Lib/test/test_asyncio/test_events.py b/Lib/test/test_asyncio/test_events.py +index c431fea401..18c4fd15d9 100644 +--- a/Lib/test/test_asyncio/test_events.py ++++ b/Lib/test/test_asyncio/test_events.py +@@ -2547,9 +2547,7 @@ def test_event_loop_policy(self): + def test_get_event_loop(self): + policy = asyncio.DefaultEventLoopPolicy() + self.assertIsNone(policy._local._loop) +- with self.assertWarns(DeprecationWarning) as cm: +- loop = policy.get_event_loop() +- self.assertEqual(cm.filename, __file__) ++ loop = policy.get_event_loop() + self.assertIsInstance(loop, asyncio.AbstractEventLoop) + + self.assertIs(policy._local._loop, loop) +@@ -2563,10 +2561,8 @@ def test_get_event_loop_calls_set_event_loop(self): + policy, "set_event_loop", + wraps=policy.set_event_loop) as m_set_event_loop: + +- with self.assertWarns(DeprecationWarning) as cm: +- loop = policy.get_event_loop() ++ loop = policy.get_event_loop() + self.addCleanup(loop.close) +- self.assertEqual(cm.filename, __file__) + + # policy._local._loop must be set through .set_event_loop() + # (the unix DefaultEventLoopPolicy needs this call to attach +@@ -2755,10 +2751,8 @@ def test_get_event_loop_returns_running_loop2(self): + loop = asyncio.new_event_loop() + self.addCleanup(loop.close) + +- with self.assertWarns(DeprecationWarning) as cm: +- loop2 = asyncio.get_event_loop() ++ loop2 = asyncio.get_event_loop() + self.addCleanup(loop2.close) +- self.assertEqual(cm.filename, __file__) + asyncio.set_event_loop(None) + with self.assertRaisesRegex(RuntimeError, 'no current'): + asyncio.get_event_loop() +diff --git a/Misc/NEWS.d/next/Library/2022-12-21-18-29-24.gh-issue-100160.isBmL5.rst b/Misc/NEWS.d/next/Library/2022-12-21-18-29-24.gh-issue-100160.isBmL5.rst +new file mode 100644 +index 0000000000..c3b518ca85 +--- /dev/null ++++ b/Misc/NEWS.d/next/Library/2022-12-21-18-29-24.gh-issue-100160.isBmL5.rst +@@ -0,0 +1,2 @@ ++Remove any deprecation warnings in :func:`asyncio.get_event_loop`. They are ++deferred to Python 3.12. diff --git a/python3.11.spec b/python3.11.spec index 3c01a3b..96dae6d 100644 --- a/python3.11.spec +++ b/python3.11.spec @@ -319,6 +319,12 @@ Patch371: 00371-revert-bpo-1596321-fix-threading-_shutdown-for-the-main-thread-g # GH-100133: fix `asyncio` subprocess losing `stderr` and `stdout` output Patch395: 00395-gh-100133-fix-asyncio-subprocess-losing-stderr-and-stdout-output.patch +# 00396 # 4c775fbed65016fec5dfd66316559024d2af9135 +# gh-100160: Remove any deprecation warnings in asyncio.get_event_loop() +# +# Some deprecation warnings will reappear (in a slightly different form) in 3.12. +Patch396: 00396-gh-100160-remove-any-deprecation-warnings-in-asyncio-get_event_loop.patch + # (New patches go here ^^^) # # When adding new patches to "python" and "python3" in Fedora, EL, etc., @@ -1603,6 +1609,7 @@ CheckPython optimized %changelog * Fri Jan 06 2023 Miro Hrončok - 3.11.1-3 - Fix `asyncio` subprocess losing `stderr` and `stdout` output +- Remove any deprecation warnings in asyncio.get_event_loop() * Mon Dec 19 2022 Miro Hrončok - 3.11.1-2 - No longer patch the default bytecode cache invalidation policy From 85c6584975cba261de7ea3c45f7ca3d48bff481b Mon Sep 17 00:00:00 2001 From: Fedora Release Engineering Date: Fri, 20 Jan 2023 18:45:09 +0000 Subject: [PATCH 055/118] Rebuilt for https://fedoraproject.org/wiki/Fedora_38_Mass_Rebuild Signed-off-by: Fedora Release Engineering --- python3.11.spec | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/python3.11.spec b/python3.11.spec index 96dae6d..5d59c3d 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 @@ -1607,6 +1607,9 @@ CheckPython optimized # ====================================================== %changelog +* Fri Jan 20 2023 Fedora Release Engineering - 3.11.1-4 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_38_Mass_Rebuild + * Fri Jan 06 2023 Miro Hrončok - 3.11.1-3 - Fix `asyncio` subprocess losing `stderr` and `stdout` output - Remove any deprecation warnings in asyncio.get_event_loop() From db4f00169267a208de762af949ff98fb33f34838 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Thu, 12 Jan 2023 16:39:34 +0000 Subject: [PATCH 056/118] Don't require pyproject-rpm-macros on RHEL See also https://src.fedoraproject.org/rpms/pyproject-rpm-macros/pull-request/345 --- python3.11.spec | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/python3.11.spec b/python3.11.spec index 5d59c3d..f9e3975 100644 --- a/python3.11.spec +++ b/python3.11.spec @@ -484,7 +484,11 @@ Requires: %{pkgname}-libs%{?_isa} = %{version}-%{release} # But we want them when packages BuildRequire python3-devel Requires: (python-rpm-macros if rpm-build) Requires: (python3-rpm-macros if rpm-build) -Requires: (pyproject-rpm-macros if rpm-build) +# We omit this dependency on RHEL to avoid pulling the macros to AppStream: +# RHEL users can use the minimal implementation of %%pyproject_buildrequires +# from pyproject-srpm-macros instead. +# On Fedora, we keep this to avoid one additional round of %%generate_buildrequires. +%{!?rhel:Requires: (pyproject-rpm-macros if rpm-build)} %unversioned_obsoletes_of_python3_X_if_main devel From 0331299c7d019060c2dab6ab56c82e5f60aa4d2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Hrn=C4=8Diar?= Date: Wed, 8 Feb 2023 16:08:24 +0100 Subject: [PATCH 057/118] Update to 3.11.2 --- ...cess-losing-stderr-and-stdout-output.patch | 66 ------- ...n-warnings-in-asyncio-get_event_loop.patch | 171 ------------------ python3.11.spec | 19 +- sources | 4 +- 4 files changed, 9 insertions(+), 251 deletions(-) delete mode 100644 00395-gh-100133-fix-asyncio-subprocess-losing-stderr-and-stdout-output.patch delete mode 100644 00396-gh-100160-remove-any-deprecation-warnings-in-asyncio-get_event_loop.patch diff --git a/00395-gh-100133-fix-asyncio-subprocess-losing-stderr-and-stdout-output.patch b/00395-gh-100133-fix-asyncio-subprocess-losing-stderr-and-stdout-output.patch deleted file mode 100644 index c480127..0000000 --- a/00395-gh-100133-fix-asyncio-subprocess-losing-stderr-and-stdout-output.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: Wed, 21 Dec 2022 02:24:19 -0800 -Subject: [PATCH] 00395: GH-100133: fix `asyncio` subprocess losing `stderr` - and `stdout` output - -(cherry picked from commit a7715ccfba5b86ab09f86ec56ac3755c93b46b48) - -Co-authored-by: Kumar Aditya <59607654+kumaraditya303@users.noreply.github.com> ---- - Lib/asyncio/base_subprocess.py | 3 --- - Lib/test/test_asyncio/test_subprocess.py | 17 +++++++++++++++++ - ...22-12-10-08-36-07.gh-issue-100133.g-zQlp.rst | 1 + - 3 files changed, 18 insertions(+), 3 deletions(-) - create mode 100644 Misc/NEWS.d/next/Library/2022-12-10-08-36-07.gh-issue-100133.g-zQlp.rst - -diff --git a/Lib/asyncio/base_subprocess.py b/Lib/asyncio/base_subprocess.py -index e15bb4141f..4c9b0dd565 100644 ---- a/Lib/asyncio/base_subprocess.py -+++ b/Lib/asyncio/base_subprocess.py -@@ -215,9 +215,6 @@ def _process_exited(self, returncode): - # object. On Python 3.6, it is required to avoid a ResourceWarning. - self._proc.returncode = returncode - self._call(self._protocol.process_exited) -- for p in self._pipes.values(): -- if p is not None: -- p.pipe.close() - - self._try_finish() - -diff --git a/Lib/test/test_asyncio/test_subprocess.py b/Lib/test/test_asyncio/test_subprocess.py -index f71ad72f99..bea2314a52 100644 ---- a/Lib/test/test_asyncio/test_subprocess.py -+++ b/Lib/test/test_asyncio/test_subprocess.py -@@ -684,6 +684,23 @@ async def execute(): - - self.assertIsNone(self.loop.run_until_complete(execute())) - -+ def test_subprocess_communicate_stdout(self): -+ # See https://github.com/python/cpython/issues/100133 -+ async def get_command_stdout(cmd, *args): -+ proc = await asyncio.create_subprocess_exec( -+ cmd, *args, stdout=asyncio.subprocess.PIPE, -+ ) -+ stdout, _ = await proc.communicate() -+ return stdout.decode().strip() -+ -+ async def main(): -+ outputs = [f'foo{i}' for i in range(10)] -+ res = await asyncio.gather(*[get_command_stdout(sys.executable, '-c', -+ f'print({out!r})') for out in outputs]) -+ self.assertEqual(res, outputs) -+ -+ self.loop.run_until_complete(main()) -+ - - if sys.platform != 'win32': - # Unix -diff --git a/Misc/NEWS.d/next/Library/2022-12-10-08-36-07.gh-issue-100133.g-zQlp.rst b/Misc/NEWS.d/next/Library/2022-12-10-08-36-07.gh-issue-100133.g-zQlp.rst -new file mode 100644 -index 0000000000..881e6ed80f ---- /dev/null -+++ b/Misc/NEWS.d/next/Library/2022-12-10-08-36-07.gh-issue-100133.g-zQlp.rst -@@ -0,0 +1 @@ -+Fix regression in :mod:`asyncio` where a subprocess would sometimes lose data received from pipe. diff --git a/00396-gh-100160-remove-any-deprecation-warnings-in-asyncio-get_event_loop.patch b/00396-gh-100160-remove-any-deprecation-warnings-in-asyncio-get_event_loop.patch deleted file mode 100644 index bebae56..0000000 --- a/00396-gh-100160-remove-any-deprecation-warnings-in-asyncio-get_event_loop.patch +++ /dev/null @@ -1,171 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Serhiy Storchaka -Date: Tue, 10 Jan 2023 22:20:09 +0200 -Subject: [PATCH] 00396: gh-100160: Remove any deprecation warnings in - asyncio.get_event_loop() - -Some deprecation warnings will reappear (in a slightly different form) in 3.12. - -Co-authored-by: Guido van Rossum ---- - Doc/library/asyncio-eventloop.rst | 14 +++++++------- - Doc/library/asyncio-policy.rst | 9 +++++---- - Doc/whatsnew/3.10.rst | 13 ------------- - Lib/asyncio/events.py | 15 --------------- - Lib/test/test_asyncio/test_events.py | 12 +++--------- - ...2022-12-21-18-29-24.gh-issue-100160.isBmL5.rst | 2 ++ - 6 files changed, 17 insertions(+), 48 deletions(-) - create mode 100644 Misc/NEWS.d/next/Library/2022-12-21-18-29-24.gh-issue-100160.isBmL5.rst - -diff --git a/Doc/library/asyncio-eventloop.rst b/Doc/library/asyncio-eventloop.rst -index 28b7a90058..886399e7ae 100644 ---- a/Doc/library/asyncio-eventloop.rst -+++ b/Doc/library/asyncio-eventloop.rst -@@ -48,7 +48,7 @@ an event loop: - running event loop. - - If there is no running event loop set, the function will return -- the result of ``get_event_loop_policy().get_event_loop()`` call. -+ the result of the ``get_event_loop_policy().get_event_loop()`` call. - - Because this function has rather complex behavior (especially - when custom event loop policies are in use), using the -@@ -59,15 +59,15 @@ an event loop: - instead of using these lower level functions to manually create and close an - event loop. - -- .. deprecated:: 3.10 -- Deprecation warning is emitted if there is no current event loop. -- In Python 3.12 it will be an error. -- - .. note:: - In Python versions 3.10.0--3.10.8 and 3.11.0 this function -- (and other functions which used it implicitly) emitted a -+ (and other functions which use it implicitly) emitted a - :exc:`DeprecationWarning` if there was no running event loop, even if -- the current loop was set. -+ the current loop was set on the policy. -+ In Python versions 3.10.9, 3.11.1 and 3.12 they emit a -+ :exc:`DeprecationWarning` if there is no running event loop and no -+ current loop is set. -+ In some future Python release this will become an error. - - .. function:: set_event_loop(loop) - -diff --git a/Doc/library/asyncio-policy.rst b/Doc/library/asyncio-policy.rst -index d0af45febd..eb043b3e5e 100644 ---- a/Doc/library/asyncio-policy.rst -+++ b/Doc/library/asyncio-policy.rst -@@ -112,10 +112,11 @@ asyncio ships with the following built-in policies: - - On Windows, :class:`ProactorEventLoop` is now used by default. - -- .. deprecated:: 3.11.1 -- :meth:`get_event_loop` now emits a :exc:`DeprecationWarning` if there -- is no current event loop set and a new event loop has been implicitly -- created. In Python 3.12 it will be an error. -+ .. note:: -+ In Python versions 3.10.9, 3.11.1 and 3.12 this function emits a -+ :exc:`DeprecationWarning` if there is no running event loop and no -+ current loop is set. -+ In some future Python release this will become an error. - - - .. class:: WindowsSelectorEventLoopPolicy -diff --git a/Doc/whatsnew/3.10.rst b/Doc/whatsnew/3.10.rst -index d0b436664a..38b30deff7 100644 ---- a/Doc/whatsnew/3.10.rst -+++ b/Doc/whatsnew/3.10.rst -@@ -1710,19 +1710,6 @@ Deprecated - scheduled for removal in Python 3.12. - (Contributed by Erlend E. Aasland in :issue:`42264`.) - --* :func:`asyncio.get_event_loop` now emits a deprecation warning if there is -- no running event loop. In the future it will be an alias of -- :func:`~asyncio.get_running_loop`. -- :mod:`asyncio` functions which implicitly create :class:`~asyncio.Future` -- or :class:`~asyncio.Task` objects now emit -- a deprecation warning if there is no running event loop and no explicit -- *loop* argument is passed: :func:`~asyncio.ensure_future`, -- :func:`~asyncio.wrap_future`, :func:`~asyncio.gather`, -- :func:`~asyncio.shield`, :func:`~asyncio.as_completed` and constructors of -- :class:`~asyncio.Future`, :class:`~asyncio.Task`, -- :class:`~asyncio.StreamReader`, :class:`~asyncio.StreamReaderProtocol`. -- (Contributed by Serhiy Storchaka in :issue:`39529`.) -- - * The undocumented built-in function ``sqlite3.enable_shared_cache`` is now - deprecated, scheduled for removal in Python 3.12. Its use is strongly - discouraged by the SQLite3 documentation. See `the SQLite3 docs -diff --git a/Lib/asyncio/events.py b/Lib/asyncio/events.py -index af3f9e970b..b1799320ea 100644 ---- a/Lib/asyncio/events.py -+++ b/Lib/asyncio/events.py -@@ -671,21 +671,6 @@ def get_event_loop(self): - if (self._local._loop is None and - not self._local._set_called and - threading.current_thread() is threading.main_thread()): -- stacklevel = 2 -- try: -- f = sys._getframe(1) -- except AttributeError: -- pass -- else: -- while f: -- module = f.f_globals.get('__name__') -- if not (module == 'asyncio' or module.startswith('asyncio.')): -- break -- f = f.f_back -- stacklevel += 1 -- import warnings -- warnings.warn('There is no current event loop', -- DeprecationWarning, stacklevel=stacklevel) - self.set_event_loop(self.new_event_loop()) - - if self._local._loop is None: -diff --git a/Lib/test/test_asyncio/test_events.py b/Lib/test/test_asyncio/test_events.py -index c431fea401..18c4fd15d9 100644 ---- a/Lib/test/test_asyncio/test_events.py -+++ b/Lib/test/test_asyncio/test_events.py -@@ -2547,9 +2547,7 @@ def test_event_loop_policy(self): - def test_get_event_loop(self): - policy = asyncio.DefaultEventLoopPolicy() - self.assertIsNone(policy._local._loop) -- with self.assertWarns(DeprecationWarning) as cm: -- loop = policy.get_event_loop() -- self.assertEqual(cm.filename, __file__) -+ loop = policy.get_event_loop() - self.assertIsInstance(loop, asyncio.AbstractEventLoop) - - self.assertIs(policy._local._loop, loop) -@@ -2563,10 +2561,8 @@ def test_get_event_loop_calls_set_event_loop(self): - policy, "set_event_loop", - wraps=policy.set_event_loop) as m_set_event_loop: - -- with self.assertWarns(DeprecationWarning) as cm: -- loop = policy.get_event_loop() -+ loop = policy.get_event_loop() - self.addCleanup(loop.close) -- self.assertEqual(cm.filename, __file__) - - # policy._local._loop must be set through .set_event_loop() - # (the unix DefaultEventLoopPolicy needs this call to attach -@@ -2755,10 +2751,8 @@ def test_get_event_loop_returns_running_loop2(self): - loop = asyncio.new_event_loop() - self.addCleanup(loop.close) - -- with self.assertWarns(DeprecationWarning) as cm: -- loop2 = asyncio.get_event_loop() -+ loop2 = asyncio.get_event_loop() - self.addCleanup(loop2.close) -- self.assertEqual(cm.filename, __file__) - asyncio.set_event_loop(None) - with self.assertRaisesRegex(RuntimeError, 'no current'): - asyncio.get_event_loop() -diff --git a/Misc/NEWS.d/next/Library/2022-12-21-18-29-24.gh-issue-100160.isBmL5.rst b/Misc/NEWS.d/next/Library/2022-12-21-18-29-24.gh-issue-100160.isBmL5.rst -new file mode 100644 -index 0000000000..c3b518ca85 ---- /dev/null -+++ b/Misc/NEWS.d/next/Library/2022-12-21-18-29-24.gh-issue-100160.isBmL5.rst -@@ -0,0 +1,2 @@ -+Remove any deprecation warnings in :func:`asyncio.get_event_loop`. They are -+deferred to Python 3.12. diff --git a/python3.11.spec b/python3.11.spec index f9e3975..b234c8b 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}.1 +%global general_version %{pybasever}.2 #global prerel ... %global upstream_version %{general_version}%{?prerel} Version: %{general_version}%{?prerel:~%{prerel}} -Release: 4%{?dist} +Release: 1%{?dist} License: Python-2.0.1 @@ -315,16 +315,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 -# 00395 # 18ff37a92c507144edf32274b356dd1dd734cf07 -# GH-100133: fix `asyncio` subprocess losing `stderr` and `stdout` output -Patch395: 00395-gh-100133-fix-asyncio-subprocess-losing-stderr-and-stdout-output.patch - -# 00396 # 4c775fbed65016fec5dfd66316559024d2af9135 -# gh-100160: Remove any deprecation warnings in asyncio.get_event_loop() -# -# Some deprecation warnings will reappear (in a slightly different form) in 3.12. -Patch396: 00396-gh-100160-remove-any-deprecation-warnings-in-asyncio-get_event_loop.patch - # (New patches go here ^^^) # # When adding new patches to "python" and "python3" in Fedora, EL, etc., @@ -1453,6 +1443,7 @@ CheckPython optimized %{dynload_dir}/_ctypes_test.%{SOABI_optimized}.so %{dynload_dir}/_testbuffer.%{SOABI_optimized}.so %{dynload_dir}/_testcapi.%{SOABI_optimized}.so +%{dynload_dir}/_testclinic.%{SOABI_optimized}.so %{dynload_dir}/_testimportmultiple.%{SOABI_optimized}.so %{dynload_dir}/_testinternalcapi.%{SOABI_optimized}.so %{dynload_dir}/_testmultiphase.%{SOABI_optimized}.so @@ -1581,6 +1572,7 @@ CheckPython optimized %{dynload_dir}/_ctypes_test.%{SOABI_debug}.so %{dynload_dir}/_testbuffer.%{SOABI_debug}.so %{dynload_dir}/_testcapi.%{SOABI_debug}.so +%{dynload_dir}/_testclinic.%{SOABI_debug}.so %{dynload_dir}/_testimportmultiple.%{SOABI_debug}.so %{dynload_dir}/_testinternalcapi.%{SOABI_debug}.so %{dynload_dir}/_testmultiphase.%{SOABI_debug}.so @@ -1611,6 +1603,9 @@ CheckPython optimized # ====================================================== %changelog +* Wed Feb 08 2023 Tomáš Hrnčiar - 3.11.2-1 +- Update to 3.11.2 + * Fri Jan 20 2023 Fedora Release Engineering - 3.11.1-4 - Rebuilt for https://fedoraproject.org/wiki/Fedora_38_Mass_Rebuild diff --git a/sources b/sources index 327dc94..4ed0e1f 100644 --- a/sources +++ b/sources @@ -1,2 +1,2 @@ -SHA512 (Python-3.11.1.tar.xz) = 5edd70c881e083c96199c60471f18f9ebc4c97a2d45dc66f89e16d7c3638d8a5d2cbf2e84b1be3d7f1178ce9f7fa4197884385c1ee3618ff66a538f872f318ed -SHA512 (Python-3.11.1.tar.xz.asc) = 81ed05c2adf38552bdc5ac761704f2720a646d56681a919a6bfa51f1a4b42cd14edb9c84d58664dbc8e7b561cd78d82ae6b10dda423e1fae543bc7fa4bf3f78e +SHA512 (Python-3.11.2.tar.xz) = 5684ec7eae2dce26facc54d448ccdb6901bbfa1cab03abbe8fd34e4268a2b701daa13df15903349492447035be78380d473389e8703b4e910a65b088d2462e8b +SHA512 (Python-3.11.2.tar.xz.asc) = 9d9d1c6dd6e56a916c6861cd0e7e623a165b0845bafe0acfcae27b4fe10a6b7015844e6b3f8deded26a763c935e32f565b2e12beb20c43fda16c11eba8d282a1 From 7b688dbf924e1bbbc154a79857de1040131a49da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Hrn=C4=8Diar?= Date: Wed, 5 Apr 2023 13:51:34 +0200 Subject: [PATCH 058/118] Update to 3.11.3 --- python3.11.spec | 5 ++++- sources | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/python3.11.spec b/python3.11.spec index b234c8b..367ccc4 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}.2 +%global general_version %{pybasever}.3 #global prerel ... %global upstream_version %{general_version}%{?prerel} Version: %{general_version}%{?prerel:~%{prerel}} @@ -1603,6 +1603,9 @@ CheckPython optimized # ====================================================== %changelog +* Wed Apr 05 2023 Tomáš Hrnčiar - 3.11.3-1 +- Update to 3.11.3 + * Wed Feb 08 2023 Tomáš Hrnčiar - 3.11.2-1 - Update to 3.11.2 diff --git a/sources b/sources index 4ed0e1f..ecff347 100644 --- a/sources +++ b/sources @@ -1,2 +1,2 @@ -SHA512 (Python-3.11.2.tar.xz) = 5684ec7eae2dce26facc54d448ccdb6901bbfa1cab03abbe8fd34e4268a2b701daa13df15903349492447035be78380d473389e8703b4e910a65b088d2462e8b -SHA512 (Python-3.11.2.tar.xz.asc) = 9d9d1c6dd6e56a916c6861cd0e7e623a165b0845bafe0acfcae27b4fe10a6b7015844e6b3f8deded26a763c935e32f565b2e12beb20c43fda16c11eba8d282a1 +SHA512 (Python-3.11.3.tar.xz) = a3bba4b69322a47bfeefe42ba0fd7331b5b67fd2ab41441e2219d16ef8c6f307f1a48977afd073c18cfd24ec6cb1bfe0c4bb4b273031eb524dc7e9fb5fbcc3b6 +SHA512 (Python-3.11.3.tar.xz.asc) = 34bfb6e74e2bbec15bf3f653e32a3d705961b5f724e3f4713cf9b6b530f9c9e7e94f5cf855798bdf9763235b97a60ec9ad554d24cdc793e21a0c39540b5818d8 From 68ad779a6cba886f9f92ebb8eb22e192710bbcb1 Mon Sep 17 00:00:00 2001 From: Lumir Balhar Date: Wed, 24 May 2023 13:58:20 +0200 Subject: [PATCH 059/118] Fix for CVE-2023-24329 --- ...e-chars-in-urlsplit-gh-102508-104575.patch | 230 ++++++++++++++++++ python3.11.spec | 17 +- 2 files changed, 246 insertions(+), 1 deletion(-) create mode 100644 00399-gh-102153-start-stripping-c0-control-and-space-chars-in-urlsplit-gh-102508-104575.patch diff --git a/00399-gh-102153-start-stripping-c0-control-and-space-chars-in-urlsplit-gh-102508-104575.patch b/00399-gh-102153-start-stripping-c0-control-and-space-chars-in-urlsplit-gh-102508-104575.patch new file mode 100644 index 0000000..3eb1d6d --- /dev/null +++ b/00399-gh-102153-start-stripping-c0-control-and-space-chars-in-urlsplit-gh-102508-104575.patch @@ -0,0 +1,230 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: "Miss Islington (bot)" + <31488909+miss-islington@users.noreply.github.com> +Date: Wed, 17 May 2023 14:41:25 -0700 +Subject: [PATCH] 00399: gh-102153: Start stripping C0 control and space chars + in `urlsplit` (GH-102508) (#104575) + +* gh-102153: Start stripping C0 control and space chars in `urlsplit` (GH-102508) + +`urllib.parse.urlsplit` has already been respecting the WHATWG spec a bit GH-25595. + +This adds more sanitizing to respect the "Remove any leading C0 control or space from input" [rule](https://url.spec.whatwg.org/GH-url-parsing:~:text=Remove%20any%20leading%20and%20trailing%20C0%20control%20or%20space%20from%20input.) in response to [CVE-2023-24329](https://nvd.nist.gov/vuln/detail/CVE-2023-24329). + +--------- + +(cherry picked from commit 2f630e1ce18ad2e07428296532a68b11dc66ad10) + +Co-authored-by: Illia Volochii +Co-authored-by: Gregory P. Smith [Google] +--- + Doc/library/urllib.parse.rst | 46 +++++++++++++- + Lib/test/test_urlparse.py | 61 ++++++++++++++++++- + Lib/urllib/parse.py | 12 ++++ + ...-03-07-20-59-17.gh-issue-102153.14CLSZ.rst | 3 + + 4 files changed, 119 insertions(+), 3 deletions(-) + create mode 100644 Misc/NEWS.d/next/Security/2023-03-07-20-59-17.gh-issue-102153.14CLSZ.rst + +diff --git a/Doc/library/urllib.parse.rst b/Doc/library/urllib.parse.rst +index 96b3965107..a326e82e30 100644 +--- a/Doc/library/urllib.parse.rst ++++ b/Doc/library/urllib.parse.rst +@@ -159,6 +159,10 @@ or on combining URL components into a URL string. + ParseResult(scheme='http', netloc='www.cwi.nl:80', path='/%7Eguido/Python.html', + params='', query='', fragment='') + ++ .. warning:: ++ ++ :func:`urlparse` does not perform validation. See :ref:`URL parsing ++ security ` for details. + + .. versionchanged:: 3.2 + Added IPv6 URL parsing capabilities. +@@ -324,8 +328,14 @@ or on combining URL components into a URL string. + ``#``, ``@``, or ``:`` will raise a :exc:`ValueError`. If the URL is + decomposed before parsing, no error will be raised. + +- Following the `WHATWG spec`_ that updates RFC 3986, ASCII newline +- ``\n``, ``\r`` and tab ``\t`` characters are stripped from the URL. ++ Following some of the `WHATWG spec`_ that updates RFC 3986, leading C0 ++ control and space characters are stripped from the URL. ``\n``, ++ ``\r`` and tab ``\t`` characters are removed from the URL at any position. ++ ++ .. warning:: ++ ++ :func:`urlsplit` does not perform validation. See :ref:`URL parsing ++ security ` for details. + + .. versionchanged:: 3.6 + Out-of-range port numbers now raise :exc:`ValueError`, instead of +@@ -338,6 +348,9 @@ or on combining URL components into a URL string. + .. versionchanged:: 3.10 + ASCII newline and tab characters are stripped from the URL. + ++ .. versionchanged:: 3.11.4 ++ Leading WHATWG C0 control and space characters are stripped from the URL. ++ + .. _WHATWG spec: https://url.spec.whatwg.org/#concept-basic-url-parser + + .. function:: urlunsplit(parts) +@@ -414,6 +427,35 @@ or on combining URL components into a URL string. + or ``scheme://host/path``). If *url* is not a wrapped URL, it is returned + without changes. + ++.. _url-parsing-security: ++ ++URL parsing security ++-------------------- ++ ++The :func:`urlsplit` and :func:`urlparse` APIs do not perform **validation** of ++inputs. They may not raise errors on inputs that other applications consider ++invalid. They may also succeed on some inputs that might not be considered ++URLs elsewhere. Their purpose is for practical functionality rather than ++purity. ++ ++Instead of raising an exception on unusual input, they may instead return some ++component parts as empty strings. Or components may contain more than perhaps ++they should. ++ ++We recommend that users of these APIs where the values may be used anywhere ++with security implications code defensively. Do some verification within your ++code before trusting a returned component part. Does that ``scheme`` make ++sense? Is that a sensible ``path``? Is there anything strange about that ++``hostname``? etc. ++ ++What constitutes a URL is not universally well defined. Different applications ++have different needs and desired constraints. For instance the living `WHATWG ++spec`_ describes what user facing web clients such as a web browser require. ++While :rfc:`3986` is more general. These functions incorporate some aspects of ++both, but cannot be claimed compliant with either. The APIs and existing user ++code with expectations on specific behaviors predate both standards leading us ++to be very cautious about making API behavior changes. ++ + .. _parsing-ascii-encoded-bytes: + + Parsing ASCII Encoded Bytes +diff --git a/Lib/test/test_urlparse.py b/Lib/test/test_urlparse.py +index b426110723..40f13d631c 100644 +--- a/Lib/test/test_urlparse.py ++++ b/Lib/test/test_urlparse.py +@@ -649,6 +649,65 @@ def test_urlsplit_remove_unsafe_bytes(self): + self.assertEqual(p.scheme, "http") + self.assertEqual(p.geturl(), "http://www.python.org/javascript:alert('msg')/?query=something#fragment") + ++ def test_urlsplit_strip_url(self): ++ noise = bytes(range(0, 0x20 + 1)) ++ base_url = "http://User:Pass@www.python.org:080/doc/?query=yes#frag" ++ ++ url = noise.decode("utf-8") + base_url ++ p = urllib.parse.urlsplit(url) ++ self.assertEqual(p.scheme, "http") ++ self.assertEqual(p.netloc, "User:Pass@www.python.org:080") ++ self.assertEqual(p.path, "/doc/") ++ self.assertEqual(p.query, "query=yes") ++ self.assertEqual(p.fragment, "frag") ++ self.assertEqual(p.username, "User") ++ self.assertEqual(p.password, "Pass") ++ self.assertEqual(p.hostname, "www.python.org") ++ self.assertEqual(p.port, 80) ++ self.assertEqual(p.geturl(), base_url) ++ ++ url = noise + base_url.encode("utf-8") ++ p = urllib.parse.urlsplit(url) ++ self.assertEqual(p.scheme, b"http") ++ self.assertEqual(p.netloc, b"User:Pass@www.python.org:080") ++ self.assertEqual(p.path, b"/doc/") ++ self.assertEqual(p.query, b"query=yes") ++ self.assertEqual(p.fragment, b"frag") ++ self.assertEqual(p.username, b"User") ++ self.assertEqual(p.password, b"Pass") ++ self.assertEqual(p.hostname, b"www.python.org") ++ self.assertEqual(p.port, 80) ++ self.assertEqual(p.geturl(), base_url.encode("utf-8")) ++ ++ # Test that trailing space is preserved as some applications rely on ++ # this within query strings. ++ query_spaces_url = "https://www.python.org:88/doc/?query= " ++ p = urllib.parse.urlsplit(noise.decode("utf-8") + query_spaces_url) ++ self.assertEqual(p.scheme, "https") ++ self.assertEqual(p.netloc, "www.python.org:88") ++ self.assertEqual(p.path, "/doc/") ++ self.assertEqual(p.query, "query= ") ++ self.assertEqual(p.port, 88) ++ self.assertEqual(p.geturl(), query_spaces_url) ++ ++ p = urllib.parse.urlsplit("www.pypi.org ") ++ # That "hostname" gets considered a "path" due to the ++ # trailing space and our existing logic... YUCK... ++ # and re-assembles via geturl aka unurlsplit into the original. ++ # django.core.validators.URLValidator (at least through v3.2) relies on ++ # this, for better or worse, to catch it in a ValidationError via its ++ # regular expressions. ++ # Here we test the basic round trip concept of such a trailing space. ++ self.assertEqual(urllib.parse.urlunsplit(p), "www.pypi.org ") ++ ++ # with scheme as cache-key ++ url = "//www.python.org/" ++ scheme = noise.decode("utf-8") + "https" + noise.decode("utf-8") ++ for _ in range(2): ++ p = urllib.parse.urlsplit(url, scheme=scheme) ++ self.assertEqual(p.scheme, "https") ++ self.assertEqual(p.geturl(), "https://www.python.org/") ++ + def test_attributes_bad_port(self): + """Check handling of invalid ports.""" + for bytes in (False, True): +@@ -656,7 +715,7 @@ def test_attributes_bad_port(self): + for port in ("foo", "1.5", "-1", "0x10", "-0", "1_1", " 1", "1 ", "६"): + with self.subTest(bytes=bytes, parse=parse, port=port): + netloc = "www.example.net:" + port +- url = "http://" + netloc ++ url = "http://" + netloc + "/" + if bytes: + if netloc.isascii() and port.isascii(): + netloc = netloc.encode("ascii") +diff --git a/Lib/urllib/parse.py b/Lib/urllib/parse.py +index 69631cbb81..4f06fd509e 100644 +--- a/Lib/urllib/parse.py ++++ b/Lib/urllib/parse.py +@@ -25,6 +25,10 @@ + scenarios for parsing, and for backward compatibility purposes, some + parsing quirks from older RFCs are retained. The testcases in + test_urlparse.py provides a good indicator of parsing behavior. ++ ++The WHATWG URL Parser spec should also be considered. We are not compliant with ++it either due to existing user code API behavior expectations (Hyrum's Law). ++It serves as a useful guide when making changes. + """ + + from collections import namedtuple +@@ -79,6 +83,10 @@ + '0123456789' + '+-.') + ++# Leading and trailing C0 control and space to be stripped per WHATWG spec. ++# == "".join([chr(i) for i in range(0, 0x20 + 1)]) ++_WHATWG_C0_CONTROL_OR_SPACE = '\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f ' ++ + # Unsafe bytes to be removed per WHATWG spec + _UNSAFE_URL_BYTES_TO_REMOVE = ['\t', '\r', '\n'] + +@@ -452,6 +460,10 @@ def urlsplit(url, scheme='', allow_fragments=True): + """ + + url, scheme, _coerce_result = _coerce_args(url, scheme) ++ # Only lstrip url as some applications rely on preserving trailing space. ++ # (https://url.spec.whatwg.org/#concept-basic-url-parser would strip both) ++ url = url.lstrip(_WHATWG_C0_CONTROL_OR_SPACE) ++ scheme = scheme.strip(_WHATWG_C0_CONTROL_OR_SPACE) + + for b in _UNSAFE_URL_BYTES_TO_REMOVE: + url = url.replace(b, "") +diff --git a/Misc/NEWS.d/next/Security/2023-03-07-20-59-17.gh-issue-102153.14CLSZ.rst b/Misc/NEWS.d/next/Security/2023-03-07-20-59-17.gh-issue-102153.14CLSZ.rst +new file mode 100644 +index 0000000000..e57ac4ed3a +--- /dev/null ++++ b/Misc/NEWS.d/next/Security/2023-03-07-20-59-17.gh-issue-102153.14CLSZ.rst +@@ -0,0 +1,3 @@ ++:func:`urllib.parse.urlsplit` now strips leading C0 control and space ++characters following the specification for URLs defined by WHATWG in ++response to CVE-2023-24329. Patch by Illia Volochii. diff --git a/python3.11.spec b/python3.11.spec index 367ccc4..357ce57 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 @@ -315,6 +315,18 @@ 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 +# 00399 # 62614243969f1c717a02a1c65e55ef173ad9a6dd +# gh-102153: Start stripping C0 control and space chars in `urlsplit` (GH-102508) (#104575) +# +# * gh-102153: Start stripping C0 control and space chars in `urlsplit` (GH-102508) +# +# `urllib.parse.urlsplit` has already been respecting the WHATWG spec a bit GH-25595. +# +# This adds more sanitizing to respect the "Remove any leading C0 control or space from input" [rule](https://url.spec.whatwg.org/GH-url-parsing:~:text=Remove%%20any%%20leading%%20and%%20trailing%%20C0%%20control%%20or%%20space%%20from%%20input.) in response to [CVE-2023-24329](https://nvd.nist.gov/vuln/detail/CVE-2023-24329). +# +# --------- +Patch399: 00399-gh-102153-start-stripping-c0-control-and-space-chars-in-urlsplit-gh-102508-104575.patch + # (New patches go here ^^^) # # When adding new patches to "python" and "python3" in Fedora, EL, etc., @@ -1603,6 +1615,9 @@ CheckPython optimized # ====================================================== %changelog +* Wed May 24 2023 Lumír Balhar - 3.11.3-2 +- Fix for CVE-2023-24329 + * Wed Apr 05 2023 Tomáš Hrnčiar - 3.11.3-1 - Update to 3.11.3 From 64d93401a313b91ae51de383313970835e388d8d Mon Sep 17 00:00:00 2001 From: Charalampos Stratakis Date: Sat, 27 May 2023 00:55:16 +0200 Subject: [PATCH 060/118] Fixup for CVE-2023-24329 patch name --- ...split-gh-102508-104575.patch => 00399-cve-2023-24329.patch | 3 +-- python3.11.spec | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) rename 00399-gh-102153-start-stripping-c0-control-and-space-chars-in-urlsplit-gh-102508-104575.patch => 00399-cve-2023-24329.patch (98%) diff --git a/00399-gh-102153-start-stripping-c0-control-and-space-chars-in-urlsplit-gh-102508-104575.patch b/00399-cve-2023-24329.patch similarity index 98% rename from 00399-gh-102153-start-stripping-c0-control-and-space-chars-in-urlsplit-gh-102508-104575.patch rename to 00399-cve-2023-24329.patch index 3eb1d6d..e7d5159 100644 --- a/00399-gh-102153-start-stripping-c0-control-and-space-chars-in-urlsplit-gh-102508-104575.patch +++ b/00399-cve-2023-24329.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: Wed, 17 May 2023 14:41:25 -0700 -Subject: [PATCH] 00399: gh-102153: Start stripping C0 control and space chars - in `urlsplit` (GH-102508) (#104575) +Subject: [PATCH] 00399: CVE-2023-24329 * gh-102153: Start stripping C0 control and space chars in `urlsplit` (GH-102508) diff --git a/python3.11.spec b/python3.11.spec index 357ce57..aa37a07 100644 --- a/python3.11.spec +++ b/python3.11.spec @@ -316,7 +316,7 @@ Patch251: 00251-change-user-install-location.patch Patch371: 00371-revert-bpo-1596321-fix-threading-_shutdown-for-the-main-thread-gh-28549-gh-28589.patch # 00399 # 62614243969f1c717a02a1c65e55ef173ad9a6dd -# gh-102153: Start stripping C0 control and space chars in `urlsplit` (GH-102508) (#104575) +# CVE-2023-24329 # # * gh-102153: Start stripping C0 control and space chars in `urlsplit` (GH-102508) # @@ -325,7 +325,7 @@ Patch371: 00371-revert-bpo-1596321-fix-threading-_shutdown-for-the-main-thread-g # This adds more sanitizing to respect the "Remove any leading C0 control or space from input" [rule](https://url.spec.whatwg.org/GH-url-parsing:~:text=Remove%%20any%%20leading%%20and%%20trailing%%20C0%%20control%%20or%%20space%%20from%%20input.) in response to [CVE-2023-24329](https://nvd.nist.gov/vuln/detail/CVE-2023-24329). # # --------- -Patch399: 00399-gh-102153-start-stripping-c0-control-and-space-chars-in-urlsplit-gh-102508-104575.patch +Patch399: 00399-cve-2023-24329.patch # (New patches go here ^^^) # From 8ca0a0a2d8cf70fc2d644aea41030c8dc3d81035 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Hrn=C4=8Diar?= Date: Wed, 7 Jun 2023 22:32:30 +0200 Subject: [PATCH 061/118] Update to 3.11.4 --- 00399-cve-2023-24329.patch | 229 ------------------------------------- python3.11.spec | 21 +--- sources | 4 +- 3 files changed, 8 insertions(+), 246 deletions(-) delete mode 100644 00399-cve-2023-24329.patch diff --git a/00399-cve-2023-24329.patch b/00399-cve-2023-24329.patch deleted file mode 100644 index e7d5159..0000000 --- a/00399-cve-2023-24329.patch +++ /dev/null @@ -1,229 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: "Miss Islington (bot)" - <31488909+miss-islington@users.noreply.github.com> -Date: Wed, 17 May 2023 14:41:25 -0700 -Subject: [PATCH] 00399: CVE-2023-24329 - -* gh-102153: Start stripping C0 control and space chars in `urlsplit` (GH-102508) - -`urllib.parse.urlsplit` has already been respecting the WHATWG spec a bit GH-25595. - -This adds more sanitizing to respect the "Remove any leading C0 control or space from input" [rule](https://url.spec.whatwg.org/GH-url-parsing:~:text=Remove%20any%20leading%20and%20trailing%20C0%20control%20or%20space%20from%20input.) in response to [CVE-2023-24329](https://nvd.nist.gov/vuln/detail/CVE-2023-24329). - ---------- - -(cherry picked from commit 2f630e1ce18ad2e07428296532a68b11dc66ad10) - -Co-authored-by: Illia Volochii -Co-authored-by: Gregory P. Smith [Google] ---- - Doc/library/urllib.parse.rst | 46 +++++++++++++- - Lib/test/test_urlparse.py | 61 ++++++++++++++++++- - Lib/urllib/parse.py | 12 ++++ - ...-03-07-20-59-17.gh-issue-102153.14CLSZ.rst | 3 + - 4 files changed, 119 insertions(+), 3 deletions(-) - create mode 100644 Misc/NEWS.d/next/Security/2023-03-07-20-59-17.gh-issue-102153.14CLSZ.rst - -diff --git a/Doc/library/urllib.parse.rst b/Doc/library/urllib.parse.rst -index 96b3965107..a326e82e30 100644 ---- a/Doc/library/urllib.parse.rst -+++ b/Doc/library/urllib.parse.rst -@@ -159,6 +159,10 @@ or on combining URL components into a URL string. - ParseResult(scheme='http', netloc='www.cwi.nl:80', path='/%7Eguido/Python.html', - params='', query='', fragment='') - -+ .. warning:: -+ -+ :func:`urlparse` does not perform validation. See :ref:`URL parsing -+ security ` for details. - - .. versionchanged:: 3.2 - Added IPv6 URL parsing capabilities. -@@ -324,8 +328,14 @@ or on combining URL components into a URL string. - ``#``, ``@``, or ``:`` will raise a :exc:`ValueError`. If the URL is - decomposed before parsing, no error will be raised. - -- Following the `WHATWG spec`_ that updates RFC 3986, ASCII newline -- ``\n``, ``\r`` and tab ``\t`` characters are stripped from the URL. -+ Following some of the `WHATWG spec`_ that updates RFC 3986, leading C0 -+ control and space characters are stripped from the URL. ``\n``, -+ ``\r`` and tab ``\t`` characters are removed from the URL at any position. -+ -+ .. warning:: -+ -+ :func:`urlsplit` does not perform validation. See :ref:`URL parsing -+ security ` for details. - - .. versionchanged:: 3.6 - Out-of-range port numbers now raise :exc:`ValueError`, instead of -@@ -338,6 +348,9 @@ or on combining URL components into a URL string. - .. versionchanged:: 3.10 - ASCII newline and tab characters are stripped from the URL. - -+ .. versionchanged:: 3.11.4 -+ Leading WHATWG C0 control and space characters are stripped from the URL. -+ - .. _WHATWG spec: https://url.spec.whatwg.org/#concept-basic-url-parser - - .. function:: urlunsplit(parts) -@@ -414,6 +427,35 @@ or on combining URL components into a URL string. - or ``scheme://host/path``). If *url* is not a wrapped URL, it is returned - without changes. - -+.. _url-parsing-security: -+ -+URL parsing security -+-------------------- -+ -+The :func:`urlsplit` and :func:`urlparse` APIs do not perform **validation** of -+inputs. They may not raise errors on inputs that other applications consider -+invalid. They may also succeed on some inputs that might not be considered -+URLs elsewhere. Their purpose is for practical functionality rather than -+purity. -+ -+Instead of raising an exception on unusual input, they may instead return some -+component parts as empty strings. Or components may contain more than perhaps -+they should. -+ -+We recommend that users of these APIs where the values may be used anywhere -+with security implications code defensively. Do some verification within your -+code before trusting a returned component part. Does that ``scheme`` make -+sense? Is that a sensible ``path``? Is there anything strange about that -+``hostname``? etc. -+ -+What constitutes a URL is not universally well defined. Different applications -+have different needs and desired constraints. For instance the living `WHATWG -+spec`_ describes what user facing web clients such as a web browser require. -+While :rfc:`3986` is more general. These functions incorporate some aspects of -+both, but cannot be claimed compliant with either. The APIs and existing user -+code with expectations on specific behaviors predate both standards leading us -+to be very cautious about making API behavior changes. -+ - .. _parsing-ascii-encoded-bytes: - - Parsing ASCII Encoded Bytes -diff --git a/Lib/test/test_urlparse.py b/Lib/test/test_urlparse.py -index b426110723..40f13d631c 100644 ---- a/Lib/test/test_urlparse.py -+++ b/Lib/test/test_urlparse.py -@@ -649,6 +649,65 @@ def test_urlsplit_remove_unsafe_bytes(self): - self.assertEqual(p.scheme, "http") - self.assertEqual(p.geturl(), "http://www.python.org/javascript:alert('msg')/?query=something#fragment") - -+ def test_urlsplit_strip_url(self): -+ noise = bytes(range(0, 0x20 + 1)) -+ base_url = "http://User:Pass@www.python.org:080/doc/?query=yes#frag" -+ -+ url = noise.decode("utf-8") + base_url -+ p = urllib.parse.urlsplit(url) -+ self.assertEqual(p.scheme, "http") -+ self.assertEqual(p.netloc, "User:Pass@www.python.org:080") -+ self.assertEqual(p.path, "/doc/") -+ self.assertEqual(p.query, "query=yes") -+ self.assertEqual(p.fragment, "frag") -+ self.assertEqual(p.username, "User") -+ self.assertEqual(p.password, "Pass") -+ self.assertEqual(p.hostname, "www.python.org") -+ self.assertEqual(p.port, 80) -+ self.assertEqual(p.geturl(), base_url) -+ -+ url = noise + base_url.encode("utf-8") -+ p = urllib.parse.urlsplit(url) -+ self.assertEqual(p.scheme, b"http") -+ self.assertEqual(p.netloc, b"User:Pass@www.python.org:080") -+ self.assertEqual(p.path, b"/doc/") -+ self.assertEqual(p.query, b"query=yes") -+ self.assertEqual(p.fragment, b"frag") -+ self.assertEqual(p.username, b"User") -+ self.assertEqual(p.password, b"Pass") -+ self.assertEqual(p.hostname, b"www.python.org") -+ self.assertEqual(p.port, 80) -+ self.assertEqual(p.geturl(), base_url.encode("utf-8")) -+ -+ # Test that trailing space is preserved as some applications rely on -+ # this within query strings. -+ query_spaces_url = "https://www.python.org:88/doc/?query= " -+ p = urllib.parse.urlsplit(noise.decode("utf-8") + query_spaces_url) -+ self.assertEqual(p.scheme, "https") -+ self.assertEqual(p.netloc, "www.python.org:88") -+ self.assertEqual(p.path, "/doc/") -+ self.assertEqual(p.query, "query= ") -+ self.assertEqual(p.port, 88) -+ self.assertEqual(p.geturl(), query_spaces_url) -+ -+ p = urllib.parse.urlsplit("www.pypi.org ") -+ # That "hostname" gets considered a "path" due to the -+ # trailing space and our existing logic... YUCK... -+ # and re-assembles via geturl aka unurlsplit into the original. -+ # django.core.validators.URLValidator (at least through v3.2) relies on -+ # this, for better or worse, to catch it in a ValidationError via its -+ # regular expressions. -+ # Here we test the basic round trip concept of such a trailing space. -+ self.assertEqual(urllib.parse.urlunsplit(p), "www.pypi.org ") -+ -+ # with scheme as cache-key -+ url = "//www.python.org/" -+ scheme = noise.decode("utf-8") + "https" + noise.decode("utf-8") -+ for _ in range(2): -+ p = urllib.parse.urlsplit(url, scheme=scheme) -+ self.assertEqual(p.scheme, "https") -+ self.assertEqual(p.geturl(), "https://www.python.org/") -+ - def test_attributes_bad_port(self): - """Check handling of invalid ports.""" - for bytes in (False, True): -@@ -656,7 +715,7 @@ def test_attributes_bad_port(self): - for port in ("foo", "1.5", "-1", "0x10", "-0", "1_1", " 1", "1 ", "६"): - with self.subTest(bytes=bytes, parse=parse, port=port): - netloc = "www.example.net:" + port -- url = "http://" + netloc -+ url = "http://" + netloc + "/" - if bytes: - if netloc.isascii() and port.isascii(): - netloc = netloc.encode("ascii") -diff --git a/Lib/urllib/parse.py b/Lib/urllib/parse.py -index 69631cbb81..4f06fd509e 100644 ---- a/Lib/urllib/parse.py -+++ b/Lib/urllib/parse.py -@@ -25,6 +25,10 @@ - scenarios for parsing, and for backward compatibility purposes, some - parsing quirks from older RFCs are retained. The testcases in - test_urlparse.py provides a good indicator of parsing behavior. -+ -+The WHATWG URL Parser spec should also be considered. We are not compliant with -+it either due to existing user code API behavior expectations (Hyrum's Law). -+It serves as a useful guide when making changes. - """ - - from collections import namedtuple -@@ -79,6 +83,10 @@ - '0123456789' - '+-.') - -+# Leading and trailing C0 control and space to be stripped per WHATWG spec. -+# == "".join([chr(i) for i in range(0, 0x20 + 1)]) -+_WHATWG_C0_CONTROL_OR_SPACE = '\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f ' -+ - # Unsafe bytes to be removed per WHATWG spec - _UNSAFE_URL_BYTES_TO_REMOVE = ['\t', '\r', '\n'] - -@@ -452,6 +460,10 @@ def urlsplit(url, scheme='', allow_fragments=True): - """ - - url, scheme, _coerce_result = _coerce_args(url, scheme) -+ # Only lstrip url as some applications rely on preserving trailing space. -+ # (https://url.spec.whatwg.org/#concept-basic-url-parser would strip both) -+ url = url.lstrip(_WHATWG_C0_CONTROL_OR_SPACE) -+ scheme = scheme.strip(_WHATWG_C0_CONTROL_OR_SPACE) - - for b in _UNSAFE_URL_BYTES_TO_REMOVE: - url = url.replace(b, "") -diff --git a/Misc/NEWS.d/next/Security/2023-03-07-20-59-17.gh-issue-102153.14CLSZ.rst b/Misc/NEWS.d/next/Security/2023-03-07-20-59-17.gh-issue-102153.14CLSZ.rst -new file mode 100644 -index 0000000000..e57ac4ed3a ---- /dev/null -+++ b/Misc/NEWS.d/next/Security/2023-03-07-20-59-17.gh-issue-102153.14CLSZ.rst -@@ -0,0 +1,3 @@ -+:func:`urllib.parse.urlsplit` now strips leading C0 control and space -+characters following the specification for URLs defined by WHATWG in -+response to CVE-2023-24329. Patch by Illia Volochii. diff --git a/python3.11.spec b/python3.11.spec index aa37a07..83123a7 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}.3 +%global general_version %{pybasever}.4 #global prerel ... %global upstream_version %{general_version}%{?prerel} Version: %{general_version}%{?prerel:~%{prerel}} -Release: 2%{?dist} +Release: 1%{?dist} License: Python-2.0.1 @@ -67,7 +67,7 @@ License: Python-2.0.1 # If the rpmwheels condition is disabled, we use the bundled wheel packages # from Python with the versions below. # This needs to be manually updated when we update Python. -%global pip_version 22.3.1 +%global pip_version 23.1.2 %global setuptools_version 65.5.0 # Expensive optimizations (mainly, profile-guided optimizations) @@ -315,18 +315,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 -# 00399 # 62614243969f1c717a02a1c65e55ef173ad9a6dd -# CVE-2023-24329 -# -# * gh-102153: Start stripping C0 control and space chars in `urlsplit` (GH-102508) -# -# `urllib.parse.urlsplit` has already been respecting the WHATWG spec a bit GH-25595. -# -# This adds more sanitizing to respect the "Remove any leading C0 control or space from input" [rule](https://url.spec.whatwg.org/GH-url-parsing:~:text=Remove%%20any%%20leading%%20and%%20trailing%%20C0%%20control%%20or%%20space%%20from%%20input.) in response to [CVE-2023-24329](https://nvd.nist.gov/vuln/detail/CVE-2023-24329). -# -# --------- -Patch399: 00399-cve-2023-24329.patch - # (New patches go here ^^^) # # When adding new patches to "python" and "python3" in Fedora, EL, etc., @@ -1615,6 +1603,9 @@ CheckPython optimized # ====================================================== %changelog +* Wed Jun 07 2023 Tomáš Hrnčiar - 3.11.4-1 +- Update to 3.11.4 + * Wed May 24 2023 Lumír Balhar - 3.11.3-2 - Fix for CVE-2023-24329 diff --git a/sources b/sources index ecff347..6b8930e 100644 --- a/sources +++ b/sources @@ -1,2 +1,2 @@ -SHA512 (Python-3.11.3.tar.xz) = a3bba4b69322a47bfeefe42ba0fd7331b5b67fd2ab41441e2219d16ef8c6f307f1a48977afd073c18cfd24ec6cb1bfe0c4bb4b273031eb524dc7e9fb5fbcc3b6 -SHA512 (Python-3.11.3.tar.xz.asc) = 34bfb6e74e2bbec15bf3f653e32a3d705961b5f724e3f4713cf9b6b530f9c9e7e94f5cf855798bdf9763235b97a60ec9ad554d24cdc793e21a0c39540b5818d8 +SHA512 (Python-3.11.4.tar.xz) = 7eb14fecbf60824d10c22a9057584c3a142c2866f4af6caa2525c10c8bcb24e6e7afb32a44a0e118df0a2b2543d578c3b422ffd4a5fa317dfe6ea371cc7ee1ee +SHA512 (Python-3.11.4.tar.xz.asc) = 8ee82bf116b2cc7407e260eccf53e7fee4d7497165d0b9c3e59931c73f3b419bc0299b459eee9544a6e51e323ff0a6aa07827efd89f9c320b54556feeea04a78 From 5f98fe006c626e18849c6243ac1648caafe6004e Mon Sep 17 00:00:00 2001 From: Python Maint Date: Tue, 13 Jun 2023 15:09:02 +0200 Subject: [PATCH 062/118] Rebuilt for Python 3.12 --- python3.11.spec | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/python3.11.spec b/python3.11.spec index 83123a7..cf60fab 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 @@ -1603,6 +1603,9 @@ CheckPython optimized # ====================================================== %changelog +* Tue Jun 13 2023 Python Maint - 3.11.4-2 +- Rebuilt for Python 3.12 + * Wed Jun 07 2023 Tomáš Hrnčiar - 3.11.4-1 - Update to 3.11.4 From 458f7d2d2438abe3e438e4735e5943a3aa2a326f Mon Sep 17 00:00:00 2001 From: Fedora Release Engineering Date: Fri, 21 Jul 2023 15:42:14 +0000 Subject: [PATCH 063/118] Rebuilt for https://fedoraproject.org/wiki/Fedora_39_Mass_Rebuild Signed-off-by: Fedora Release Engineering --- python3.11.spec | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/python3.11.spec b/python3.11.spec index cf60fab..5488d13 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 @@ -1603,6 +1603,9 @@ CheckPython optimized # ====================================================== %changelog +* Fri Jul 21 2023 Fedora Release Engineering - 3.11.4-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_39_Mass_Rebuild + * Tue Jun 13 2023 Python Maint - 3.11.4-2 - Rebuilt for Python 3.12 From ee27ca470f1db077c387c62671469d83df13e23d Mon Sep 17 00:00:00 2001 From: Charalampos Stratakis Date: Thu, 3 Aug 2023 04:49:35 +0200 Subject: [PATCH 064/118] Remove extra distro-applied CFLAGS passed to user-built C extensions Only -fexceptions and -fcf-protection are preserved for binary compatibility with user-built python C extension. https://fedoraproject.org/wiki/Changes/Python_Extension_Flags_Reduction --- python3.11.spec | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/python3.11.spec b/python3.11.spec index 5488d13..b071fef 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 @@ -670,14 +670,15 @@ topdir=$(pwd) # Standard library built here will still use the %%build_...flags, # Fedora packages utilizing %%py3_build will use them as well # https://fedoraproject.org/wiki/Changes/Python_Extension_Flags -export CFLAGS="%{extension_cflags} -D_GNU_SOURCE -fPIC -fwrapv" +# https://fedoraproject.org/wiki/Changes/Python_Extension_Flags_Reduction +export CFLAGS="%{extension_cflags}" export CFLAGS_NODIST="%{build_cflags} -D_GNU_SOURCE -fPIC -fwrapv" -export CXXFLAGS="%{extension_cxxflags} -D_GNU_SOURCE -fPIC -fwrapv" +export CXXFLAGS="%{extension_cxxflags}" export CPPFLAGS="$(pkg-config --cflags-only-I libffi)" -export OPT="%{extension_cflags} -D_GNU_SOURCE -fPIC -fwrapv" +export OPT="%{extension_cflags}" export LINKCC="gcc" export CFLAGS="$CFLAGS $(pkg-config --cflags openssl)" -export LDFLAGS="%{extension_ldflags} -g $(pkg-config --libs-only-L openssl)" +export LDFLAGS="%{extension_ldflags} $(pkg-config --libs-only-L openssl)" export LDFLAGS_NODIST="%{build_ldflags} -g $(pkg-config --libs-only-L openssl)" # We can build several different configurations of Python: regular and debug. @@ -1603,6 +1604,10 @@ CheckPython optimized # ====================================================== %changelog +* Wed Aug 02 2023 Charalampos Stratakis - 3.11.4-4 +- Remove extra distro-applied CFLAGS passed to user built C extensions +- https://fedoraproject.org/wiki/Changes/Python_Extension_Flags_Reduction + * Fri Jul 21 2023 Fedora Release Engineering - 3.11.4-3 - Rebuilt for https://fedoraproject.org/wiki/Fedora_39_Mass_Rebuild From 32c38941f9bdcd5e89c207444b20ab568bbd48cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Hrn=C4=8Diar?= Date: Tue, 29 Aug 2023 15:50:12 +0200 Subject: [PATCH 065/118] Update to 3.11.5 --- python3.11.spec | 13 ++++++++++--- sources | 4 ++-- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/python3.11.spec b/python3.11.spec index b071fef..d4a9fb8 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}.4 +%global general_version %{pybasever}.5 #global prerel ... %global upstream_version %{general_version}%{?prerel} Version: %{general_version}%{?prerel:~%{prerel}} -Release: 4%{?dist} +Release: 1%{?dist} License: Python-2.0.1 @@ -67,7 +67,7 @@ License: Python-2.0.1 # If the rpmwheels condition is disabled, we use the bundled wheel packages # from Python with the versions below. # This needs to be manually updated when we update Python. -%global pip_version 23.1.2 +%global pip_version 23.2.1 %global setuptools_version 65.5.0 # Expensive optimizations (mainly, profile-guided optimizations) @@ -1079,10 +1079,14 @@ CheckPython() { # test_freeze_simple_script is skipped, because it fails when bundled wheels # are removed in Fedora. # upstream report: https://bugs.python.org/issue45783 + # test_check_probes is failing since it was introduced in 3.12.0rc1, + # the test is skipped until it is fixed in upstream. + # see: https://github.com/python/cpython/issues/104280#issuecomment-1669249980 LD_LIBRARY_PATH=$ConfDir $ConfDir/python -m test.regrtest \ -wW --slowest -j0 --timeout=1800 \ -i test_freeze_simple_script \ + -i test_check_probes \ %if %{with bootstrap} -x test_distutils \ %endif @@ -1604,6 +1608,9 @@ CheckPython optimized # ====================================================== %changelog +* Mon Aug 28 2023 Tomáš Hrnčiar - 3.11.5-1 +- Update to 3.11.5 + * Wed Aug 02 2023 Charalampos Stratakis - 3.11.4-4 - Remove extra distro-applied CFLAGS passed to user built C extensions - https://fedoraproject.org/wiki/Changes/Python_Extension_Flags_Reduction diff --git a/sources b/sources index 6b8930e..be0708a 100644 --- a/sources +++ b/sources @@ -1,2 +1,2 @@ -SHA512 (Python-3.11.4.tar.xz) = 7eb14fecbf60824d10c22a9057584c3a142c2866f4af6caa2525c10c8bcb24e6e7afb32a44a0e118df0a2b2543d578c3b422ffd4a5fa317dfe6ea371cc7ee1ee -SHA512 (Python-3.11.4.tar.xz.asc) = 8ee82bf116b2cc7407e260eccf53e7fee4d7497165d0b9c3e59931c73f3b419bc0299b459eee9544a6e51e323ff0a6aa07827efd89f9c320b54556feeea04a78 +SHA512 (Python-3.11.5.tar.xz) = 93fa640bedcea449060caac8aa691aa315a19f172fd9f0422183d17749c3512d4ecac60e7599f9ef14e3cdb3c8b4b060e484c9061b1e7ee8d958200d6041e408 +SHA512 (Python-3.11.5.tar.xz.asc) = 5a8e1b1cabe89de03c050d581bbd3ec917d93ec943b2e8241db05c245809cf80294022c4cfc1bea3b90aa0570176109aac90455057256c025e2596aa136375fc From 7d571986dc19437d37bae51f4b32c44b320fd9d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Hrn=C4=8Diar?= Date: Tue, 29 Aug 2023 15:54:05 +0200 Subject: [PATCH 066/118] Temporarily skip test_check_probes in CI tests See: https://github.com/python/cpython/issues/104280#issuecomment-1669249980 --- tests/tests.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/tests.yml b/tests/tests.yml index 3f9165b..07e31cb 100644 --- a/tests/tests.yml +++ b/tests/tests.yml @@ -30,10 +30,10 @@ run: "PYTHON=python{{ pybasever }}d TOX=false VERSION={{ pybasever }} ./venv.sh" - selftest: dir: python/selftest - run: "VERSION={{ pybasever }} X='' ./parallel.sh" + run: "VERSION={{ pybasever }} X='-i test_check_probes' ./parallel.sh" - debugtest: dir: python/selftest - run: "VERSION={{ pybasever }} PYTHON=python{{ pybasever }}d X='' ./parallel.sh" + 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" From 3254311fe9359731bd5c6721852d0043dfe1be6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Hrn=C4=8Diar?= Date: Tue, 3 Oct 2023 10:14:10 +0200 Subject: [PATCH 067/118] Update to 3.11.6 --- check-pyc-timestamps.py | 6 +++--- python3.11.spec | 5 ++++- sources | 4 ++-- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/check-pyc-timestamps.py b/check-pyc-timestamps.py index e421fca..0497eca 100644 --- a/check-pyc-timestamps.py +++ b/check-pyc-timestamps.py @@ -16,9 +16,9 @@ LEVELS = (None, 1, 2) # list of globs of test and other files that we expect not to have bytecode not_compiled = [ '/usr/bin/*', - '*/test/bad_coding.py', - '*/test/bad_coding2.py', - '*/test/badsyntax_*.py', + '*/test/*/bad_coding.py', + '*/test/*/bad_coding2.py', + '*/test/*/badsyntax_*.py', '*/lib2to3/tests/data/*.py', '*/lib2to3/tests/data/*/*.py', '*/lib2to3/tests/data/*/*/*.py', diff --git a/python3.11.spec b/python3.11.spec index d4a9fb8..baea8dc 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}.5 +%global general_version %{pybasever}.6 #global prerel ... %global upstream_version %{general_version}%{?prerel} Version: %{general_version}%{?prerel:~%{prerel}} @@ -1608,6 +1608,9 @@ CheckPython optimized # ====================================================== %changelog +* Tue Oct 03 2023 Tomáš Hrnčiar - 3.11.6-1 +- Update to 3.11.6 + * Mon Aug 28 2023 Tomáš Hrnčiar - 3.11.5-1 - Update to 3.11.5 diff --git a/sources b/sources index be0708a..05a350f 100644 --- a/sources +++ b/sources @@ -1,2 +1,2 @@ -SHA512 (Python-3.11.5.tar.xz) = 93fa640bedcea449060caac8aa691aa315a19f172fd9f0422183d17749c3512d4ecac60e7599f9ef14e3cdb3c8b4b060e484c9061b1e7ee8d958200d6041e408 -SHA512 (Python-3.11.5.tar.xz.asc) = 5a8e1b1cabe89de03c050d581bbd3ec917d93ec943b2e8241db05c245809cf80294022c4cfc1bea3b90aa0570176109aac90455057256c025e2596aa136375fc +SHA512 (Python-3.11.6.tar.xz) = 94b1038f6f53de0c44f99f72ed0f2e0791fd9d2a325ae00ba145b2b2c332c27b300b3ea3473017518089478f15e01867b1bb203c16610039cce36f8366de341a +SHA512 (Python-3.11.6.tar.xz.asc) = 510f0b1393948c1490f81fbd90987e6f6b048b9f4d9df5814168097f5d9ac96e3682ff9bdc82d35b351eff5a4cc75015c28253b1dbbb2d94780411157c8beb25 From 1b480eac01d93d0383eeb6a79fcc18048d34b950 Mon Sep 17 00:00:00 2001 From: Yaakov Selkowitz Date: Thu, 7 Sep 2023 22:54:51 -0400 Subject: [PATCH 068/118] Use bundled libb2 in RHEL builds Standalone libb2 is unwanted in RHEL. --- python3.11.spec | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/python3.11.spec b/python3.11.spec index baea8dc..0ea7d64 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 @@ -205,7 +205,9 @@ BuildRequires: glibc-devel BuildRequires: gmp-devel BuildRequires: gnupg2 BuildRequires: libappstream-glib +%if %{undefined rhel} BuildRequires: libb2-devel +%endif BuildRequires: libffi-devel BuildRequires: libnsl2-devel BuildRequires: libtirpc-devel @@ -434,6 +436,8 @@ This package contains /usr/bin/python - the "python" command that runs Python 3. %package -n %{pkgname}-libs Summary: Python runtime libraries +# Bundled libb2 is CC0, covered by grandfathering exception +License: Python-2.0.1 AND CC0-1.0 %if %{with rpmwheels} Requires: %{python_wheel_pkg_prefix}-setuptools-wheel @@ -445,6 +449,10 @@ Provides: bundled(python3dist(setuptools)) = %{setuptools_version} %unversioned_obsoletes_of_python3_X_if_main libs +# Bundled internal headers are used even when building with system libb2 +# last updated by https://github.com/python/cpython/pull/6286 +Provides: bundled(libb2) = 0.98.1 + # There are files in the standard library that have python shebang. # We've filtered the automatic requirement out so libs are installable without # the main package. This however makes it pulled in by default. @@ -1608,6 +1616,9 @@ CheckPython optimized # ====================================================== %changelog +* Tue Oct 03 2023 Yaakov Selkowitz - 3.11.6-2 +- Use bundled libb2 in RHEL builds + * Tue Oct 03 2023 Tomáš Hrnčiar - 3.11.6-1 - Update to 3.11.6 From 955993c3ec6b30f5627e3511e3e01cf6fff23539 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Hrn=C4=8Diar?= Date: Wed, 6 Dec 2023 14:20:12 +0100 Subject: [PATCH 069/118] Update to 3.11.7 --- ...or-the-main-thread-gh-28549-gh-28589.patch | 8 +++--- ...the-installation-gh-112765-gh-112784.patch | 27 +++++++++++++++++++ python3.11.spec | 11 ++++++-- sources | 4 +-- 4 files changed, 42 insertions(+), 8 deletions(-) create mode 100644 00412-include-new-dir-test-regrtestdata-in-the-installation-gh-112765-gh-112784.patch 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 1d39233..b5c2fa1 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 @@ -16,10 +16,10 @@ https://github.com/GrahamDumpleton/mod_wsgi/issues/730 2 files changed, 8 insertions(+), 50 deletions(-) diff --git a/Lib/test/test_threading.py b/Lib/test/test_threading.py -index 9c6561c099..84714c03fe 100644 +index 17319c366a..6a46d5b76c 100644 --- a/Lib/test/test_threading.py +++ b/Lib/test/test_threading.py -@@ -956,39 +956,6 @@ def test_debug_deprecation(self): +@@ -965,39 +965,6 @@ def test_debug_deprecation(self): b'is deprecated and will be removed in Python 3.12') self.assertIn(msg, err) @@ -60,10 +60,10 @@ index 9c6561c099..84714c03fe 100644 class ThreadJoinOnShutdown(BaseTestCase): diff --git a/Lib/threading.py b/Lib/threading.py -index 4f72938551..18c10e6489 100644 +index 70601fc0d5..b7af6da432 100644 --- a/Lib/threading.py +++ b/Lib/threading.py -@@ -1546,29 +1546,20 @@ def _shutdown(): +@@ -1553,29 +1553,20 @@ def _shutdown(): global _SHUTTING_DOWN _SHUTTING_DOWN = True diff --git a/00412-include-new-dir-test-regrtestdata-in-the-installation-gh-112765-gh-112784.patch b/00412-include-new-dir-test-regrtestdata-in-the-installation-gh-112765-gh-112784.patch new file mode 100644 index 0000000..a855f1b --- /dev/null +++ b/00412-include-new-dir-test-regrtestdata-in-the-installation-gh-112765-gh-112784.patch @@ -0,0 +1,27 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Serhiy Storchaka +Date: Wed, 6 Dec 2023 10:12:08 +0200 +Subject: [PATCH] 00412: Include new dir test/regrtestdata in the installation + (GH-112765) (GH-112784) + +(cherry picked from commit f8c0198e3bfa2f6f65e426765a5efddd8ece78b0) + +Co-authored-by: Victor Stinner +--- + Makefile.pre.in | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/Makefile.pre.in b/Makefile.pre.in +index c61b093fc9..41d3f330b3 100644 +--- a/Makefile.pre.in ++++ b/Makefile.pre.in +@@ -1959,6 +1959,9 @@ TESTSUBDIRS= ctypes/test \ + test/imghdrdata \ + test/leakers \ + test/libregrtest \ ++ test/regrtestdata \ ++ test/regrtestdata/import_from_tests \ ++ test/regrtestdata/import_from_tests/test_regrtest_b \ + test/sndhdrdata \ + test/subprocessdata \ + test/support \ diff --git a/python3.11.spec b/python3.11.spec index 0ea7d64..8735c2e 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}.6 +%global general_version %{pybasever}.7 #global prerel ... %global upstream_version %{general_version}%{?prerel} Version: %{general_version}%{?prerel:~%{prerel}} -Release: 2%{?dist} +Release: 1%{?dist} License: Python-2.0.1 @@ -317,6 +317,10 @@ 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 +# 00412 # cf7ebcc048985d04e2b253b7d1de81829ed267c9 +# Include new dir test/regrtestdata in the installation (GH-112765) (GH-112784) +Patch412: 00412-include-new-dir-test-regrtestdata-in-the-installation-gh-112765-gh-112784.patch + # (New patches go here ^^^) # # When adding new patches to "python" and "python3" in Fedora, EL, etc., @@ -1616,6 +1620,9 @@ CheckPython optimized # ====================================================== %changelog +* Wed Dec 06 2023 Tomáš Hrnčiar - 3.11.7-1 +- Update to 3.11.7 + * Tue Oct 03 2023 Yaakov Selkowitz - 3.11.6-2 - Use bundled libb2 in RHEL builds diff --git a/sources b/sources index 05a350f..fd14935 100644 --- a/sources +++ b/sources @@ -1,2 +1,2 @@ -SHA512 (Python-3.11.6.tar.xz) = 94b1038f6f53de0c44f99f72ed0f2e0791fd9d2a325ae00ba145b2b2c332c27b300b3ea3473017518089478f15e01867b1bb203c16610039cce36f8366de341a -SHA512 (Python-3.11.6.tar.xz.asc) = 510f0b1393948c1490f81fbd90987e6f6b048b9f4d9df5814168097f5d9ac96e3682ff9bdc82d35b351eff5a4cc75015c28253b1dbbb2d94780411157c8beb25 +SHA512 (Python-3.11.7.tar.xz) = 11e06f2ffe1f66888cb5b4e9f607de815294d6863a77eda6ec6d7c724ef158df9f51881f4a956d4a6fa973c2fb6fd031d495e3496e9b0bb53793fb1cc8434c63 +SHA512 (Python-3.11.7.tar.xz.asc) = 7b342990c6e32897047f8ba33c4d264f1be987b73843b61bd7db08bfa1a7280c616e9dcd96225f37602f876549d011ff82a4d79f1e32a5ab7d7cc22651bba44f From 5c1f70d712f0e09355ab9ea359a25f5285f0ecb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Fri, 8 Dec 2023 19:15:03 +0000 Subject: [PATCH 070/118] Own stray directories in /usr/lib64/python3.11 Fixes https://bugzilla.redhat.com/2252144 --- python3.11.spec | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/python3.11.spec b/python3.11.spec index 8735c2e..ff494ca 100644 --- a/python3.11.spec +++ b/python3.11.spec @@ -1344,6 +1344,7 @@ CheckPython optimized %{pylibdir}/multiprocessing %dir %{pylibdir}/re/ +%dir %{pylibdir}/re/__pycache__/ %{pylibdir}/re/*.py %{pylibdir}/re/__pycache__/*%{bytecode_suffixes} @@ -1353,6 +1354,7 @@ CheckPython optimized %{pylibdir}/sqlite3/__pycache__/*%{bytecode_suffixes} %dir %{pylibdir}/tomllib/ +%dir %{pylibdir}/tomllib/__pycache__/ %{pylibdir}/tomllib/*.py %{pylibdir}/tomllib/__pycache__/*%{bytecode_suffixes} %exclude %{pylibdir}/turtle.py @@ -1362,7 +1364,8 @@ CheckPython optimized %{pylibdir}/xml %{pylibdir}/zoneinfo -%dir %{pylibdir}/__phello__ +%dir %{pylibdir}/__phello__/ +%dir %{pylibdir}/__phello__/__pycache__/ %{pylibdir}/__phello__/__init__.py %{pylibdir}/__phello__/spam.py %{pylibdir}/__phello__/__pycache__/*%{bytecode_suffixes} @@ -1622,6 +1625,8 @@ CheckPython optimized %changelog * Wed Dec 06 2023 Tomáš Hrnčiar - 3.11.7-1 - Update to 3.11.7 +- Own stray directories in /usr/lib64/python3.11 +- Fixes: rhbz#2252144 * Tue Oct 03 2023 Yaakov Selkowitz - 3.11.6-2 - Use bundled libb2 in RHEL builds From 7434c7a69a4493b00898fabf631b78f8a79a0a6b Mon Sep 17 00:00:00 2001 From: Lumir Balhar Date: Mon, 18 Dec 2023 13:15:07 +0100 Subject: [PATCH 071/118] Security fix for CVE-2023-27043 (rhbz#2196188) --- ...-addresses-in-email-parseaddr-111116.patch | 500 ++++++++++++++++++ python3.11.spec | 14 +- 2 files changed, 513 insertions(+), 1 deletion(-) create mode 100644 00415-cve-2023-27043-gh-102988-reject-malformed-addresses-in-email-parseaddr-111116.patch diff --git a/00415-cve-2023-27043-gh-102988-reject-malformed-addresses-in-email-parseaddr-111116.patch b/00415-cve-2023-27043-gh-102988-reject-malformed-addresses-in-email-parseaddr-111116.patch new file mode 100644 index 0000000..61aebe3 --- /dev/null +++ b/00415-cve-2023-27043-gh-102988-reject-malformed-addresses-in-email-parseaddr-111116.patch @@ -0,0 +1,500 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Victor Stinner +Date: Fri, 15 Dec 2023 16:10:40 +0100 +Subject: [PATCH] 00415: [CVE-2023-27043] gh-102988: Reject malformed addresses + in email.parseaddr() (#111116) + +Detect email address parsing errors and return empty tuple to +indicate the parsing error (old API). Add an optional 'strict' +parameter to getaddresses() and parseaddr() functions. Patch by +Thomas Dwyer. + +Co-Authored-By: Thomas Dwyer +--- + Doc/library/email.utils.rst | 19 +- + Lib/email/utils.py | 151 ++++++++++++- + Lib/test/test_email/test_email.py | 204 +++++++++++++++++- + ...-10-20-15-28-08.gh-issue-102988.dStNO7.rst | 8 + + 4 files changed, 361 insertions(+), 21 deletions(-) + create mode 100644 Misc/NEWS.d/next/Library/2023-10-20-15-28-08.gh-issue-102988.dStNO7.rst + +diff --git a/Doc/library/email.utils.rst b/Doc/library/email.utils.rst +index 0e266b6a45..6723dc4f13 100644 +--- a/Doc/library/email.utils.rst ++++ b/Doc/library/email.utils.rst +@@ -60,13 +60,18 @@ of the new API. + begins with angle brackets, they are stripped off. + + +-.. function:: parseaddr(address) ++.. function:: parseaddr(address, *, strict=True) + + Parse address -- which should be the value of some address-containing field such + as :mailheader:`To` or :mailheader:`Cc` -- into its constituent *realname* and + *email address* parts. Returns a tuple of that information, unless the parse + fails, in which case a 2-tuple of ``('', '')`` is returned. + ++ If *strict* is true, use a strict parser which rejects malformed inputs. ++ ++ .. versionchanged:: 3.13 ++ Add *strict* optional parameter and reject malformed inputs by default. ++ + + .. function:: formataddr(pair, charset='utf-8') + +@@ -84,12 +89,15 @@ of the new API. + Added the *charset* option. + + +-.. function:: getaddresses(fieldvalues) ++.. function:: getaddresses(fieldvalues, *, strict=True) + + This method returns a list of 2-tuples of the form returned by ``parseaddr()``. + *fieldvalues* is a sequence of header field values as might be returned by +- :meth:`Message.get_all `. Here's a simple +- example that gets all the recipients of a message:: ++ :meth:`Message.get_all `. ++ ++ If *strict* is true, use a strict parser which rejects malformed inputs. ++ ++ Here's a simple example that gets all the recipients of a message:: + + from email.utils import getaddresses + +@@ -99,6 +107,9 @@ of the new API. + resent_ccs = msg.get_all('resent-cc', []) + all_recipients = getaddresses(tos + ccs + resent_tos + resent_ccs) + ++ .. versionchanged:: 3.13 ++ Add *strict* optional parameter and reject malformed inputs by default. ++ + + .. function:: parsedate(date) + +diff --git a/Lib/email/utils.py b/Lib/email/utils.py +index cfdfeb3f1a..9522341fab 100644 +--- a/Lib/email/utils.py ++++ b/Lib/email/utils.py +@@ -48,6 +48,7 @@ + specialsre = re.compile(r'[][\\()<>@,:;".]') + escapesre = re.compile(r'[\\"]') + ++ + def _has_surrogates(s): + """Return True if s contains surrogate-escaped binary data.""" + # This check is based on the fact that unless there are surrogates, utf8 +@@ -106,12 +107,127 @@ def formataddr(pair, charset='utf-8'): + return address + + ++def _iter_escaped_chars(addr): ++ pos = 0 ++ escape = False ++ for pos, ch in enumerate(addr): ++ if escape: ++ yield (pos, '\\' + ch) ++ escape = False ++ elif ch == '\\': ++ escape = True ++ else: ++ yield (pos, ch) ++ if escape: ++ yield (pos, '\\') + +-def getaddresses(fieldvalues): +- """Return a list of (REALNAME, EMAIL) for each fieldvalue.""" +- all = COMMASPACE.join(str(v) for v in fieldvalues) +- a = _AddressList(all) +- return a.addresslist ++ ++def _strip_quoted_realnames(addr): ++ """Strip real names between quotes.""" ++ if '"' not in addr: ++ # Fast path ++ return addr ++ ++ start = 0 ++ open_pos = None ++ result = [] ++ for pos, ch in _iter_escaped_chars(addr): ++ if ch == '"': ++ if open_pos is None: ++ open_pos = pos ++ else: ++ if start != open_pos: ++ result.append(addr[start:open_pos]) ++ start = pos + 1 ++ open_pos = None ++ ++ if start < len(addr): ++ result.append(addr[start:]) ++ ++ return ''.join(result) ++ ++ ++supports_strict_parsing = True ++ ++def getaddresses(fieldvalues, *, strict=True): ++ """Return a list of (REALNAME, EMAIL) or ('','') for each fieldvalue. ++ ++ When parsing fails for a fieldvalue, a 2-tuple of ('', '') is returned in ++ its place. ++ ++ If strict is true, use a strict parser which rejects malformed inputs. ++ """ ++ ++ # If strict is true, if the resulting list of parsed addresses is greater ++ # than the number of fieldvalues in the input list, a parsing error has ++ # occurred and consequently a list containing a single empty 2-tuple [('', ++ # '')] is returned in its place. This is done to avoid invalid output. ++ # ++ # Malformed input: getaddresses(['alice@example.com ']) ++ # Invalid output: [('', 'alice@example.com'), ('', 'bob@example.com')] ++ # Safe output: [('', '')] ++ ++ if not strict: ++ all = COMMASPACE.join(str(v) for v in fieldvalues) ++ a = _AddressList(all) ++ return a.addresslist ++ ++ fieldvalues = [str(v) for v in fieldvalues] ++ fieldvalues = _pre_parse_validation(fieldvalues) ++ addr = COMMASPACE.join(fieldvalues) ++ a = _AddressList(addr) ++ result = _post_parse_validation(a.addresslist) ++ ++ # Treat output as invalid if the number of addresses is not equal to the ++ # expected number of addresses. ++ n = 0 ++ for v in fieldvalues: ++ # When a comma is used in the Real Name part it is not a deliminator. ++ # So strip those out before counting the commas. ++ v = _strip_quoted_realnames(v) ++ # Expected number of addresses: 1 + number of commas ++ n += 1 + v.count(',') ++ if len(result) != n: ++ return [('', '')] ++ ++ return result ++ ++ ++def _check_parenthesis(addr): ++ # Ignore parenthesis in quoted real names. ++ addr = _strip_quoted_realnames(addr) ++ ++ opens = 0 ++ for pos, ch in _iter_escaped_chars(addr): ++ if ch == '(': ++ opens += 1 ++ elif ch == ')': ++ opens -= 1 ++ if opens < 0: ++ return False ++ return (opens == 0) ++ ++ ++def _pre_parse_validation(email_header_fields): ++ accepted_values = [] ++ for v in email_header_fields: ++ if not _check_parenthesis(v): ++ v = "('', '')" ++ accepted_values.append(v) ++ ++ return accepted_values ++ ++ ++def _post_parse_validation(parsed_email_header_tuples): ++ accepted_values = [] ++ # The parser would have parsed a correctly formatted domain-literal ++ # The existence of an [ after parsing indicates a parsing failure ++ for v in parsed_email_header_tuples: ++ if '[' in v[1]: ++ v = ('', '') ++ accepted_values.append(v) ++ ++ return accepted_values + + + def _format_timetuple_and_zone(timetuple, zone): +@@ -205,16 +321,33 @@ def parsedate_to_datetime(data): + tzinfo=datetime.timezone(datetime.timedelta(seconds=tz))) + + +-def parseaddr(addr): ++def parseaddr(addr, *, strict=True): + """ + Parse addr into its constituent realname and email address parts. + + Return a tuple of realname and email address, unless the parse fails, in + which case return a 2-tuple of ('', ''). ++ ++ If strict is True, use a strict parser which rejects malformed inputs. + """ +- addrs = _AddressList(addr).addresslist +- if not addrs: +- return '', '' ++ if not strict: ++ addrs = _AddressList(addr).addresslist ++ if not addrs: ++ return ('', '') ++ return addrs[0] ++ ++ if isinstance(addr, list): ++ addr = addr[0] ++ ++ if not isinstance(addr, str): ++ return ('', '') ++ ++ addr = _pre_parse_validation([addr])[0] ++ addrs = _post_parse_validation(_AddressList(addr).addresslist) ++ ++ if not addrs or len(addrs) > 1: ++ return ('', '') ++ + return addrs[0] + + +diff --git a/Lib/test/test_email/test_email.py b/Lib/test/test_email/test_email.py +index 677f2094b8..20b67792ea 100644 +--- a/Lib/test/test_email/test_email.py ++++ b/Lib/test/test_email/test_email.py +@@ -17,6 +17,7 @@ + + import email + import email.policy ++import email.utils + + from email.charset import Charset + from email.generator import Generator, DecodedGenerator, BytesGenerator +@@ -3321,15 +3322,154 @@ def test_getaddresses(self): + [('Al Person', 'aperson@dom.ain'), + ('Bud Person', 'bperson@dom.ain')]) + ++ def test_getaddresses_comma_in_name(self): ++ """GH-106669 regression test.""" ++ self.assertEqual( ++ utils.getaddresses( ++ [ ++ '"Bud, Person" ', ++ 'aperson@dom.ain (Al Person)', ++ '"Mariusz Felisiak" ', ++ ] ++ ), ++ [ ++ ('Bud, Person', 'bperson@dom.ain'), ++ ('Al Person', 'aperson@dom.ain'), ++ ('Mariusz Felisiak', 'to@example.com'), ++ ], ++ ) ++ ++ def test_parsing_errors(self): ++ """Test for parsing errors from CVE-2023-27043 and CVE-2019-16056""" ++ alice = 'alice@example.org' ++ bob = 'bob@example.com' ++ empty = ('', '') ++ ++ # Test utils.getaddresses() and utils.parseaddr() on malformed email ++ # addresses: default behavior (strict=True) rejects malformed address, ++ # and strict=False which tolerates malformed address. ++ for invalid_separator, expected_non_strict in ( ++ ('(', [(f'<{bob}>', alice)]), ++ (')', [('', alice), empty, ('', bob)]), ++ ('<', [('', alice), empty, ('', bob), empty]), ++ ('>', [('', alice), empty, ('', bob)]), ++ ('[', [('', f'{alice}[<{bob}>]')]), ++ (']', [('', alice), empty, ('', bob)]), ++ ('@', [empty, empty, ('', bob)]), ++ (';', [('', alice), empty, ('', bob)]), ++ (':', [('', alice), ('', bob)]), ++ ('.', [('', alice + '.'), ('', bob)]), ++ ('"', [('', alice), ('', f'<{bob}>')]), ++ ): ++ address = f'{alice}{invalid_separator}<{bob}>' ++ with self.subTest(address=address): ++ self.assertEqual(utils.getaddresses([address]), ++ [empty]) ++ self.assertEqual(utils.getaddresses([address], strict=False), ++ expected_non_strict) ++ ++ self.assertEqual(utils.parseaddr([address]), ++ empty) ++ self.assertEqual(utils.parseaddr([address], strict=False), ++ ('', address)) ++ ++ # Comma (',') is treated differently depending on strict parameter. ++ # Comma without quotes. ++ address = f'{alice},<{bob}>' ++ self.assertEqual(utils.getaddresses([address]), ++ [('', alice), ('', bob)]) ++ self.assertEqual(utils.getaddresses([address], strict=False), ++ [('', alice), ('', bob)]) ++ self.assertEqual(utils.parseaddr([address]), ++ empty) ++ self.assertEqual(utils.parseaddr([address], strict=False), ++ ('', address)) ++ ++ # Real name between quotes containing comma. ++ address = '"Alice, alice@example.org" ' ++ expected_strict = ('Alice, alice@example.org', 'bob@example.com') ++ self.assertEqual(utils.getaddresses([address]), [expected_strict]) ++ self.assertEqual(utils.getaddresses([address], strict=False), [expected_strict]) ++ self.assertEqual(utils.parseaddr([address]), expected_strict) ++ self.assertEqual(utils.parseaddr([address], strict=False), ++ ('', address)) ++ ++ # Valid parenthesis in comments. ++ address = 'alice@example.org (Alice)' ++ expected_strict = ('Alice', 'alice@example.org') ++ self.assertEqual(utils.getaddresses([address]), [expected_strict]) ++ self.assertEqual(utils.getaddresses([address], strict=False), [expected_strict]) ++ self.assertEqual(utils.parseaddr([address]), expected_strict) ++ self.assertEqual(utils.parseaddr([address], strict=False), ++ ('', address)) ++ ++ # Invalid parenthesis in comments. ++ address = 'alice@example.org )Alice(' ++ self.assertEqual(utils.getaddresses([address]), [empty]) ++ self.assertEqual(utils.getaddresses([address], strict=False), ++ [('', 'alice@example.org'), ('', ''), ('', 'Alice')]) ++ self.assertEqual(utils.parseaddr([address]), empty) ++ self.assertEqual(utils.parseaddr([address], strict=False), ++ ('', address)) ++ ++ # Two addresses with quotes separated by comma. ++ address = '"Jane Doe" , "John Doe" ' ++ self.assertEqual(utils.getaddresses([address]), ++ [('Jane Doe', 'jane@example.net'), ++ ('John Doe', 'john@example.net')]) ++ self.assertEqual(utils.getaddresses([address], strict=False), ++ [('Jane Doe', 'jane@example.net'), ++ ('John Doe', 'john@example.net')]) ++ self.assertEqual(utils.parseaddr([address]), empty) ++ self.assertEqual(utils.parseaddr([address], strict=False), ++ ('', address)) ++ ++ # Test email.utils.supports_strict_parsing attribute ++ self.assertEqual(email.utils.supports_strict_parsing, True) ++ + def test_getaddresses_nasty(self): +- eq = self.assertEqual +- eq(utils.getaddresses(['foo: ;']), [('', '')]) +- eq(utils.getaddresses( +- ['[]*-- =~$']), +- [('', ''), ('', ''), ('', '*--')]) +- eq(utils.getaddresses( +- ['foo: ;', '"Jason R. Mastaler" ']), +- [('', ''), ('Jason R. Mastaler', 'jason@dom.ain')]) ++ for addresses, expected in ( ++ (['"Sürname, Firstname" '], ++ [('Sürname, Firstname', 'to@example.com')]), ++ ++ (['foo: ;'], ++ [('', '')]), ++ ++ (['foo: ;', '"Jason R. Mastaler" '], ++ [('', ''), ('Jason R. Mastaler', 'jason@dom.ain')]), ++ ++ ([r'Pete(A nice \) chap) '], ++ [('Pete (A nice ) chap his account his host)', 'pete@silly.test')]), ++ ++ (['(Empty list)(start)Undisclosed recipients :(nobody(I know))'], ++ [('', '')]), ++ ++ (['Mary <@machine.tld:mary@example.net>, , jdoe@test . example'], ++ [('Mary', 'mary@example.net'), ('', ''), ('', 'jdoe@test.example')]), ++ ++ (['John Doe '], ++ [('John Doe (comment)', 'jdoe@machine.example')]), ++ ++ (['"Mary Smith: Personal Account" '], ++ [('Mary Smith: Personal Account', 'smith@home.example')]), ++ ++ (['Undisclosed recipients:;'], ++ [('', '')]), ++ ++ ([r', "Giant; \"Big\" Box" '], ++ [('', 'boss@nil.test'), ('Giant; "Big" Box', 'bob@example.net')]), ++ ): ++ with self.subTest(addresses=addresses): ++ self.assertEqual(utils.getaddresses(addresses), ++ expected) ++ self.assertEqual(utils.getaddresses(addresses, strict=False), ++ expected) ++ ++ addresses = ['[]*-- =~$'] ++ self.assertEqual(utils.getaddresses(addresses), ++ [('', '')]) ++ self.assertEqual(utils.getaddresses(addresses, strict=False), ++ [('', ''), ('', ''), ('', '*--')]) + + def test_getaddresses_embedded_comment(self): + """Test proper handling of a nested comment""" +@@ -3520,6 +3660,54 @@ def test_mime_classes_policy_argument(self): + m = cls(*constructor, policy=email.policy.default) + self.assertIs(m.policy, email.policy.default) + ++ def test_iter_escaped_chars(self): ++ self.assertEqual(list(utils._iter_escaped_chars(r'a\\b\"c\\"d')), ++ [(0, 'a'), ++ (2, '\\\\'), ++ (3, 'b'), ++ (5, '\\"'), ++ (6, 'c'), ++ (8, '\\\\'), ++ (9, '"'), ++ (10, 'd')]) ++ self.assertEqual(list(utils._iter_escaped_chars('a\\')), ++ [(0, 'a'), (1, '\\')]) ++ ++ def test_strip_quoted_realnames(self): ++ def check(addr, expected): ++ self.assertEqual(utils._strip_quoted_realnames(addr), expected) ++ ++ check('"Jane Doe" , "John Doe" ', ++ ' , ') ++ check(r'"Jane \"Doe\"." ', ++ ' ') ++ ++ # special cases ++ check(r'before"name"after', 'beforeafter') ++ check(r'before"name"', 'before') ++ check(r'b"name"', 'b') # single char ++ check(r'"name"after', 'after') ++ check(r'"name"a', 'a') # single char ++ check(r'"name"', '') ++ ++ # no change ++ for addr in ( ++ 'Jane Doe , John Doe ', ++ 'lone " quote', ++ ): ++ self.assertEqual(utils._strip_quoted_realnames(addr), addr) ++ ++ ++ def test_check_parenthesis(self): ++ addr = 'alice@example.net' ++ self.assertTrue(utils._check_parenthesis(f'{addr} (Alice)')) ++ self.assertFalse(utils._check_parenthesis(f'{addr} )Alice(')) ++ self.assertFalse(utils._check_parenthesis(f'{addr} (Alice))')) ++ self.assertFalse(utils._check_parenthesis(f'{addr} ((Alice)')) ++ ++ # Ignore real name between quotes ++ self.assertTrue(utils._check_parenthesis(f'")Alice((" {addr}')) ++ + + # Test the iterator/generators + class TestIterators(TestEmailBase): +diff --git a/Misc/NEWS.d/next/Library/2023-10-20-15-28-08.gh-issue-102988.dStNO7.rst b/Misc/NEWS.d/next/Library/2023-10-20-15-28-08.gh-issue-102988.dStNO7.rst +new file mode 100644 +index 0000000000..3d0e9e4078 +--- /dev/null ++++ b/Misc/NEWS.d/next/Library/2023-10-20-15-28-08.gh-issue-102988.dStNO7.rst +@@ -0,0 +1,8 @@ ++:func:`email.utils.getaddresses` and :func:`email.utils.parseaddr` now ++return ``('', '')`` 2-tuples in more situations where invalid email ++addresses are encountered instead of potentially inaccurate values. Add ++optional *strict* parameter to these two functions: use ``strict=False`` to ++get the old behavior, accept malformed inputs. ++``getattr(email.utils, 'supports_strict_parsing', False)`` can be use to check ++if the *strict* paramater is available. Patch by Thomas Dwyer and Victor ++Stinner to improve the CVE-2023-27043 fix. diff --git a/python3.11.spec b/python3.11.spec index ff494ca..b1cbff4 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 @@ -321,6 +321,15 @@ Patch371: 00371-revert-bpo-1596321-fix-threading-_shutdown-for-the-main-thread-g # Include new dir test/regrtestdata in the installation (GH-112765) (GH-112784) Patch412: 00412-include-new-dir-test-regrtestdata-in-the-installation-gh-112765-gh-112784.patch +# 00415 # 9ca4533e0b4a03d919953017026f66c6a060756e +# [CVE-2023-27043] gh-102988: Reject malformed addresses in email.parseaddr() (#111116) +# +# Detect email address parsing errors and return empty tuple to +# indicate the parsing error (old API). Add an optional 'strict' +# parameter to getaddresses() and parseaddr() functions. Patch by +# Thomas Dwyer. +Patch415: 00415-cve-2023-27043-gh-102988-reject-malformed-addresses-in-email-parseaddr-111116.patch + # (New patches go here ^^^) # # When adding new patches to "python" and "python3" in Fedora, EL, etc., @@ -1623,6 +1632,9 @@ CheckPython optimized # ====================================================== %changelog +* Mon Dec 18 2023 Lumír Balhar - 3.11.7-2 +- Security fix for CVE-2023-27043 (rhbz#2196188) + * Wed Dec 06 2023 Tomáš Hrnčiar - 3.11.7-1 - Update to 3.11.7 - Own stray directories in /usr/lib64/python3.11 From 48128460587adbb82d3cbc9fbb409b041217b838 Mon Sep 17 00:00:00 2001 From: Fedora Release Engineering Date: Mon, 22 Jan 2024 09:21:45 +0000 Subject: [PATCH 072/118] Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild --- python3.11.spec | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/python3.11.spec b/python3.11.spec index b1cbff4..7a6dbb3 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 @@ -1632,6 +1632,9 @@ CheckPython optimized # ====================================================== %changelog +* Mon Jan 22 2024 Fedora Release Engineering - 3.11.7-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild + * Mon Dec 18 2023 Lumír Balhar - 3.11.7-2 - Security fix for CVE-2023-27043 (rhbz#2196188) From 402c54cf0af8d58e73da7a37506511d4bba1495e Mon Sep 17 00:00:00 2001 From: Fedora Release Engineering Date: Fri, 26 Jan 2024 13:31:36 +0000 Subject: [PATCH 073/118] Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild --- python3.11.spec | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/python3.11.spec b/python3.11.spec index 7a6dbb3..30ec625 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 @@ -1632,6 +1632,9 @@ CheckPython optimized # ====================================================== %changelog +* Fri Jan 26 2024 Fedora Release Engineering - 3.11.7-4 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild + * Mon Jan 22 2024 Fedora Release Engineering - 3.11.7-3 - Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild From 19c104a138a4c6813fb825c273bac1967d1e29f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Hrn=C4=8Diar?= Date: Wed, 7 Feb 2024 15:08:14 +0100 Subject: [PATCH 074/118] Update to 3.11.8 --- 00251-change-user-install-location.patch | 4 +-- ...or-the-main-thread-gh-28549-gh-28589.patch | 6 ++--- ...the-installation-gh-112765-gh-112784.patch | 27 ------------------- ...-addresses-in-email-parseaddr-111116.patch | 4 +-- python3.11.spec | 15 +++++------ sources | 4 +-- 6 files changed, 16 insertions(+), 44 deletions(-) delete mode 100644 00412-include-new-dir-test-regrtestdata-in-the-installation-gh-112765-gh-112784.patch diff --git a/00251-change-user-install-location.patch b/00251-change-user-install-location.patch index 53096ec..791caea 100644 --- a/00251-change-user-install-location.patch +++ b/00251-change-user-install-location.patch @@ -61,10 +61,10 @@ index 01d5331a63..79f70f0de4 100644 else: if self.exec_prefix is None: diff --git a/Lib/site.py b/Lib/site.py -index 69670d9d7f..104cb93899 100644 +index 2904e44cff..1c9bfa7713 100644 --- a/Lib/site.py +++ b/Lib/site.py -@@ -377,8 +377,15 @@ def getsitepackages(prefixes=None): +@@ -387,8 +387,15 @@ def getsitepackages(prefixes=None): return sitepackages def addsitepackages(known_paths, prefixes=None): 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 b5c2fa1..28ac750 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 @@ -16,10 +16,10 @@ https://github.com/GrahamDumpleton/mod_wsgi/issues/730 2 files changed, 8 insertions(+), 50 deletions(-) diff --git a/Lib/test/test_threading.py b/Lib/test/test_threading.py -index 17319c366a..6a46d5b76c 100644 +index ec6a319486..1dbb9d0baa 100644 --- a/Lib/test/test_threading.py +++ b/Lib/test/test_threading.py -@@ -965,39 +965,6 @@ def test_debug_deprecation(self): +@@ -1045,39 +1045,6 @@ def test_debug_deprecation(self): b'is deprecated and will be removed in Python 3.12') self.assertIn(msg, err) @@ -60,7 +60,7 @@ index 17319c366a..6a46d5b76c 100644 class ThreadJoinOnShutdown(BaseTestCase): diff --git a/Lib/threading.py b/Lib/threading.py -index 70601fc0d5..b7af6da432 100644 +index 29b8ec7465..2145f5a6dc 100644 --- a/Lib/threading.py +++ b/Lib/threading.py @@ -1553,29 +1553,20 @@ def _shutdown(): diff --git a/00412-include-new-dir-test-regrtestdata-in-the-installation-gh-112765-gh-112784.patch b/00412-include-new-dir-test-regrtestdata-in-the-installation-gh-112765-gh-112784.patch deleted file mode 100644 index a855f1b..0000000 --- a/00412-include-new-dir-test-regrtestdata-in-the-installation-gh-112765-gh-112784.patch +++ /dev/null @@ -1,27 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Serhiy Storchaka -Date: Wed, 6 Dec 2023 10:12:08 +0200 -Subject: [PATCH] 00412: Include new dir test/regrtestdata in the installation - (GH-112765) (GH-112784) - -(cherry picked from commit f8c0198e3bfa2f6f65e426765a5efddd8ece78b0) - -Co-authored-by: Victor Stinner ---- - Makefile.pre.in | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/Makefile.pre.in b/Makefile.pre.in -index c61b093fc9..41d3f330b3 100644 ---- a/Makefile.pre.in -+++ b/Makefile.pre.in -@@ -1959,6 +1959,9 @@ TESTSUBDIRS= ctypes/test \ - test/imghdrdata \ - test/leakers \ - test/libregrtest \ -+ test/regrtestdata \ -+ test/regrtestdata/import_from_tests \ -+ test/regrtestdata/import_from_tests/test_regrtest_b \ - test/sndhdrdata \ - test/subprocessdata \ - test/support \ diff --git a/00415-cve-2023-27043-gh-102988-reject-malformed-addresses-in-email-parseaddr-111116.patch b/00415-cve-2023-27043-gh-102988-reject-malformed-addresses-in-email-parseaddr-111116.patch index 61aebe3..5c89c43 100644 --- a/00415-cve-2023-27043-gh-102988-reject-malformed-addresses-in-email-parseaddr-111116.patch +++ b/00415-cve-2023-27043-gh-102988-reject-malformed-addresses-in-email-parseaddr-111116.patch @@ -72,7 +72,7 @@ index 0e266b6a45..6723dc4f13 100644 .. function:: parsedate(date) diff --git a/Lib/email/utils.py b/Lib/email/utils.py -index cfdfeb3f1a..9522341fab 100644 +index 8993858ab4..94ead0e91f 100644 --- a/Lib/email/utils.py +++ b/Lib/email/utils.py @@ -48,6 +48,7 @@ @@ -81,7 +81,7 @@ index cfdfeb3f1a..9522341fab 100644 + def _has_surrogates(s): - """Return True if s contains surrogate-escaped binary data.""" + """Return True if s may contain surrogate-escaped binary data.""" # This check is based on the fact that unless there are surrogates, utf8 @@ -106,12 +107,127 @@ def formataddr(pair, charset='utf-8'): return address diff --git a/python3.11.spec b/python3.11.spec index 30ec625..86bc307 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}.7 +%global general_version %{pybasever}.8 #global prerel ... %global upstream_version %{general_version}%{?prerel} Version: %{general_version}%{?prerel:~%{prerel}} -Release: 4%{?dist} +Release: 1%{?dist} License: Python-2.0.1 @@ -67,7 +67,7 @@ License: Python-2.0.1 # If the rpmwheels condition is disabled, we use the bundled wheel packages # from Python with the versions below. # This needs to be manually updated when we update Python. -%global pip_version 23.2.1 +%global pip_version 24.0 %global setuptools_version 65.5.0 # Expensive optimizations (mainly, profile-guided optimizations) @@ -317,11 +317,7 @@ 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 -# 00412 # cf7ebcc048985d04e2b253b7d1de81829ed267c9 -# Include new dir test/regrtestdata in the installation (GH-112765) (GH-112784) -Patch412: 00412-include-new-dir-test-regrtestdata-in-the-installation-gh-112765-gh-112784.patch - -# 00415 # 9ca4533e0b4a03d919953017026f66c6a060756e +# 00415 # 744762808f7303a55fa941f65cacb94fd7099e5e # [CVE-2023-27043] gh-102988: Reject malformed addresses in email.parseaddr() (#111116) # # Detect email address parsing errors and return empty tuple to @@ -1632,6 +1628,9 @@ CheckPython optimized # ====================================================== %changelog +* Wed Feb 07 2024 Tomáš Hrnčiar - 3.11.8-1 +- Update to 3.11.8 + * Fri Jan 26 2024 Fedora Release Engineering - 3.11.7-4 - Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild diff --git a/sources b/sources index fd14935..73bdfe7 100644 --- a/sources +++ b/sources @@ -1,2 +1,2 @@ -SHA512 (Python-3.11.7.tar.xz) = 11e06f2ffe1f66888cb5b4e9f607de815294d6863a77eda6ec6d7c724ef158df9f51881f4a956d4a6fa973c2fb6fd031d495e3496e9b0bb53793fb1cc8434c63 -SHA512 (Python-3.11.7.tar.xz.asc) = 7b342990c6e32897047f8ba33c4d264f1be987b73843b61bd7db08bfa1a7280c616e9dcd96225f37602f876549d011ff82a4d79f1e32a5ab7d7cc22651bba44f +SHA512 (Python-3.11.8.tar.xz) = 434e727fa370def348838fd84acb69b4d309cfb03f61bf5069150164e9ca005637ac01dfbf997f445607d4e28d02c8bed0858b36589240ccadaa4c14c19f2320 +SHA512 (Python-3.11.8.tar.xz.asc) = aebec01f84e96a76f6c5949004df2bb51c817bac3fc8d925ee26ded1ff2d80bec1b579dd0fc129004bc9cd81cbdcdcdf7c1f0471c3d26b70bd6dac11b97187e0 From 2c45c73ad3b0dcefbf1f185053a832df02d135a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Wed, 21 Feb 2024 10:58:17 +0000 Subject: [PATCH 075/118] Fix tests for XMLPullParser with Expat 2.6.0 See also: https://bugzilla.redhat.com/2264859 --- ...s-for-xmlpullparser-with-expat-2-6-0.patch | 107 ++++++++++++++++++ python3.11.spec | 12 +- 2 files changed, 118 insertions(+), 1 deletion(-) create mode 100644 00422-gh-115133-fix-tests-for-xmlpullparser-with-expat-2-6-0.patch diff --git a/00422-gh-115133-fix-tests-for-xmlpullparser-with-expat-2-6-0.patch b/00422-gh-115133-fix-tests-for-xmlpullparser-with-expat-2-6-0.patch new file mode 100644 index 0000000..060dbee --- /dev/null +++ b/00422-gh-115133-fix-tests-for-xmlpullparser-with-expat-2-6-0.patch @@ -0,0 +1,107 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Serhiy Storchaka +Date: Sun, 11 Feb 2024 12:08:39 +0200 +Subject: [PATCH] 00422: gh-115133: Fix tests for XMLPullParser with Expat + 2.6.0 + +Feeding the parser by too small chunks defers parsing to prevent +CVE-2023-52425. Future versions of Expat may be more reactive. + +(cherry picked from commit 4a08e7b3431cd32a0daf22a33421cd3035343dc4) +--- + Lib/test/test_xml_etree.py | 58 ++++++++++++------- + ...-02-08-14-21-28.gh-issue-115133.ycl4ko.rst | 2 + + 2 files changed, 38 insertions(+), 22 deletions(-) + create mode 100644 Misc/NEWS.d/next/Library/2024-02-08-14-21-28.gh-issue-115133.ycl4ko.rst + +diff --git a/Lib/test/test_xml_etree.py b/Lib/test/test_xml_etree.py +index 267982a823..fa03f381fa 100644 +--- a/Lib/test/test_xml_etree.py ++++ b/Lib/test/test_xml_etree.py +@@ -13,6 +13,7 @@ + import operator + import os + import pickle ++import pyexpat + import sys + import textwrap + import types +@@ -120,6 +121,10 @@ + + """ + ++fails_with_expat_2_6_0 = (unittest.expectedFailure ++ if pyexpat.version_info >= (2, 6, 0) else ++ lambda test: test) ++ + def checkwarnings(*filters, quiet=False): + def decorator(test): + def newtest(*args, **kwargs): +@@ -1400,28 +1405,37 @@ def assert_event_tags(self, parser, expected, max_events=None): + self.assertEqual([(action, elem.tag) for action, elem in events], + expected) + +- def test_simple_xml(self): +- for chunk_size in (None, 1, 5): +- with self.subTest(chunk_size=chunk_size): +- parser = ET.XMLPullParser() +- self.assert_event_tags(parser, []) +- self._feed(parser, "\n", chunk_size) +- self.assert_event_tags(parser, []) +- self._feed(parser, +- "\n text\n", chunk_size) +- self.assert_event_tags(parser, [('end', 'element')]) +- self._feed(parser, "texttail\n", chunk_size) +- self._feed(parser, "\n", chunk_size) +- self.assert_event_tags(parser, [ +- ('end', 'element'), +- ('end', 'empty-element'), +- ]) +- self._feed(parser, "\n", chunk_size) +- self.assert_event_tags(parser, [('end', 'root')]) +- self.assertIsNone(parser.close()) ++ def test_simple_xml(self, chunk_size=None): ++ parser = ET.XMLPullParser() ++ self.assert_event_tags(parser, []) ++ self._feed(parser, "\n", chunk_size) ++ self.assert_event_tags(parser, []) ++ self._feed(parser, ++ "\n text\n", chunk_size) ++ self.assert_event_tags(parser, [('end', 'element')]) ++ self._feed(parser, "texttail\n", chunk_size) ++ self._feed(parser, "\n", chunk_size) ++ self.assert_event_tags(parser, [ ++ ('end', 'element'), ++ ('end', 'empty-element'), ++ ]) ++ self._feed(parser, "\n", chunk_size) ++ self.assert_event_tags(parser, [('end', 'root')]) ++ self.assertIsNone(parser.close()) ++ ++ @fails_with_expat_2_6_0 ++ def test_simple_xml_chunk_1(self): ++ self.test_simple_xml(chunk_size=1) ++ ++ @fails_with_expat_2_6_0 ++ def test_simple_xml_chunk_5(self): ++ self.test_simple_xml(chunk_size=5) ++ ++ def test_simple_xml_chunk_22(self): ++ self.test_simple_xml(chunk_size=22) + + def test_feed_while_iterating(self): + parser = ET.XMLPullParser() +diff --git a/Misc/NEWS.d/next/Library/2024-02-08-14-21-28.gh-issue-115133.ycl4ko.rst b/Misc/NEWS.d/next/Library/2024-02-08-14-21-28.gh-issue-115133.ycl4ko.rst +new file mode 100644 +index 0000000000..6f1015235c +--- /dev/null ++++ b/Misc/NEWS.d/next/Library/2024-02-08-14-21-28.gh-issue-115133.ycl4ko.rst +@@ -0,0 +1,2 @@ ++Fix tests for :class:`~xml.etree.ElementTree.XMLPullParser` with Expat ++2.6.0. diff --git a/python3.11.spec b/python3.11.spec index 86bc307..2204ec1 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 @@ -326,6 +326,13 @@ Patch371: 00371-revert-bpo-1596321-fix-threading-_shutdown-for-the-main-thread-g # Thomas Dwyer. Patch415: 00415-cve-2023-27043-gh-102988-reject-malformed-addresses-in-email-parseaddr-111116.patch +# 00422 # a353cebef737c41420dc7ae2469dd657371b8881 +# gh-115133: Fix tests for XMLPullParser with Expat 2.6.0 +# +# Feeding the parser by too small chunks defers parsing to prevent +# CVE-2023-52425. Future versions of Expat may be more reactive. +Patch422: 00422-gh-115133-fix-tests-for-xmlpullparser-with-expat-2-6-0.patch + # (New patches go here ^^^) # # When adding new patches to "python" and "python3" in Fedora, EL, etc., @@ -1628,6 +1635,9 @@ CheckPython optimized # ====================================================== %changelog +* Wed Feb 28 2024 Charalampos Stratakis - 3.11.8-2 +- Fix tests for XMLPullParser with Expat 2.6.0 + * Wed Feb 07 2024 Tomáš Hrnčiar - 3.11.8-1 - Update to 3.11.8 From 75e1fc6869cc33828643138401e4c725244864da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Hrn=C4=8Diar?= Date: Tue, 9 Apr 2024 13:59:22 +0200 Subject: [PATCH 076/118] Update to 3.11.9 --- 00251-change-user-install-location.patch | 6 +- ...-addresses-in-email-parseaddr-111116.patch | 6 +- ...s-for-xmlpullparser-with-expat-2-6-0.patch | 107 ------------------ python3.11.spec | 14 +-- sources | 4 +- 5 files changed, 13 insertions(+), 124 deletions(-) delete mode 100644 00422-gh-115133-fix-tests-for-xmlpullparser-with-expat-2-6-0.patch diff --git a/00251-change-user-install-location.patch b/00251-change-user-install-location.patch index 791caea..549d139 100644 --- a/00251-change-user-install-location.patch +++ b/00251-change-user-install-location.patch @@ -160,7 +160,7 @@ index ebe3711827..55af57b335 100644 # On Windows we want to substitute 'lib' for schemes rather # than the native value (without modifying vars, in case it diff --git a/Lib/test/test_sysconfig.py b/Lib/test/test_sysconfig.py -index d96371d242..72b028435f 100644 +index d3bb0d25ca..f39bbf67ea 100644 --- a/Lib/test/test_sysconfig.py +++ b/Lib/test/test_sysconfig.py @@ -111,8 +111,19 @@ def test_get_path(self): @@ -184,7 +184,7 @@ index d96371d242..72b028435f 100644 os.path.normpath(expected), ) -@@ -336,7 +347,7 @@ def test_get_config_h_filename(self): +@@ -345,7 +356,7 @@ def test_get_config_h_filename(self): self.assertTrue(os.path.isfile(config_h), config_h) def test_get_scheme_names(self): @@ -193,7 +193,7 @@ index d96371d242..72b028435f 100644 if HAS_USER_BASE: wanted.extend(['nt_user', 'osx_framework_user', 'posix_user']) self.assertEqual(get_scheme_names(), tuple(sorted(wanted))) -@@ -348,6 +359,8 @@ def test_symlink(self): # Issue 7880 +@@ -357,6 +368,8 @@ def test_symlink(self): # Issue 7880 cmd = "-c", "import sysconfig; print(sysconfig.get_platform())" self.assertEqual(py.call_real(*cmd), py.call_link(*cmd)) diff --git a/00415-cve-2023-27043-gh-102988-reject-malformed-addresses-in-email-parseaddr-111116.patch b/00415-cve-2023-27043-gh-102988-reject-malformed-addresses-in-email-parseaddr-111116.patch index 5c89c43..2a5f74b 100644 --- a/00415-cve-2023-27043-gh-102988-reject-malformed-addresses-in-email-parseaddr-111116.patch +++ b/00415-cve-2023-27043-gh-102988-reject-malformed-addresses-in-email-parseaddr-111116.patch @@ -255,7 +255,7 @@ index 8993858ab4..94ead0e91f 100644 diff --git a/Lib/test/test_email/test_email.py b/Lib/test/test_email/test_email.py -index 677f2094b8..20b67792ea 100644 +index 785696e5c5..ad60ed3a75 100644 --- a/Lib/test/test_email/test_email.py +++ b/Lib/test/test_email/test_email.py @@ -17,6 +17,7 @@ @@ -266,7 +266,7 @@ index 677f2094b8..20b67792ea 100644 from email.charset import Charset from email.generator import Generator, DecodedGenerator, BytesGenerator -@@ -3321,15 +3322,154 @@ def test_getaddresses(self): +@@ -3336,15 +3337,154 @@ def test_getaddresses(self): [('Al Person', 'aperson@dom.ain'), ('Bud Person', 'bperson@dom.ain')]) @@ -429,7 +429,7 @@ index 677f2094b8..20b67792ea 100644 def test_getaddresses_embedded_comment(self): """Test proper handling of a nested comment""" -@@ -3520,6 +3660,54 @@ def test_mime_classes_policy_argument(self): +@@ -3535,6 +3675,54 @@ def test_mime_classes_policy_argument(self): m = cls(*constructor, policy=email.policy.default) self.assertIs(m.policy, email.policy.default) diff --git a/00422-gh-115133-fix-tests-for-xmlpullparser-with-expat-2-6-0.patch b/00422-gh-115133-fix-tests-for-xmlpullparser-with-expat-2-6-0.patch deleted file mode 100644 index 060dbee..0000000 --- a/00422-gh-115133-fix-tests-for-xmlpullparser-with-expat-2-6-0.patch +++ /dev/null @@ -1,107 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Serhiy Storchaka -Date: Sun, 11 Feb 2024 12:08:39 +0200 -Subject: [PATCH] 00422: gh-115133: Fix tests for XMLPullParser with Expat - 2.6.0 - -Feeding the parser by too small chunks defers parsing to prevent -CVE-2023-52425. Future versions of Expat may be more reactive. - -(cherry picked from commit 4a08e7b3431cd32a0daf22a33421cd3035343dc4) ---- - Lib/test/test_xml_etree.py | 58 ++++++++++++------- - ...-02-08-14-21-28.gh-issue-115133.ycl4ko.rst | 2 + - 2 files changed, 38 insertions(+), 22 deletions(-) - create mode 100644 Misc/NEWS.d/next/Library/2024-02-08-14-21-28.gh-issue-115133.ycl4ko.rst - -diff --git a/Lib/test/test_xml_etree.py b/Lib/test/test_xml_etree.py -index 267982a823..fa03f381fa 100644 ---- a/Lib/test/test_xml_etree.py -+++ b/Lib/test/test_xml_etree.py -@@ -13,6 +13,7 @@ - import operator - import os - import pickle -+import pyexpat - import sys - import textwrap - import types -@@ -120,6 +121,10 @@ - - """ - -+fails_with_expat_2_6_0 = (unittest.expectedFailure -+ if pyexpat.version_info >= (2, 6, 0) else -+ lambda test: test) -+ - def checkwarnings(*filters, quiet=False): - def decorator(test): - def newtest(*args, **kwargs): -@@ -1400,28 +1405,37 @@ def assert_event_tags(self, parser, expected, max_events=None): - self.assertEqual([(action, elem.tag) for action, elem in events], - expected) - -- def test_simple_xml(self): -- for chunk_size in (None, 1, 5): -- with self.subTest(chunk_size=chunk_size): -- parser = ET.XMLPullParser() -- self.assert_event_tags(parser, []) -- self._feed(parser, "\n", chunk_size) -- self.assert_event_tags(parser, []) -- self._feed(parser, -- "\n text\n", chunk_size) -- self.assert_event_tags(parser, [('end', 'element')]) -- self._feed(parser, "texttail\n", chunk_size) -- self._feed(parser, "\n", chunk_size) -- self.assert_event_tags(parser, [ -- ('end', 'element'), -- ('end', 'empty-element'), -- ]) -- self._feed(parser, "\n", chunk_size) -- self.assert_event_tags(parser, [('end', 'root')]) -- self.assertIsNone(parser.close()) -+ def test_simple_xml(self, chunk_size=None): -+ parser = ET.XMLPullParser() -+ self.assert_event_tags(parser, []) -+ self._feed(parser, "\n", chunk_size) -+ self.assert_event_tags(parser, []) -+ self._feed(parser, -+ "\n text\n", chunk_size) -+ self.assert_event_tags(parser, [('end', 'element')]) -+ self._feed(parser, "texttail\n", chunk_size) -+ self._feed(parser, "\n", chunk_size) -+ self.assert_event_tags(parser, [ -+ ('end', 'element'), -+ ('end', 'empty-element'), -+ ]) -+ self._feed(parser, "\n", chunk_size) -+ self.assert_event_tags(parser, [('end', 'root')]) -+ self.assertIsNone(parser.close()) -+ -+ @fails_with_expat_2_6_0 -+ def test_simple_xml_chunk_1(self): -+ self.test_simple_xml(chunk_size=1) -+ -+ @fails_with_expat_2_6_0 -+ def test_simple_xml_chunk_5(self): -+ self.test_simple_xml(chunk_size=5) -+ -+ def test_simple_xml_chunk_22(self): -+ self.test_simple_xml(chunk_size=22) - - def test_feed_while_iterating(self): - parser = ET.XMLPullParser() -diff --git a/Misc/NEWS.d/next/Library/2024-02-08-14-21-28.gh-issue-115133.ycl4ko.rst b/Misc/NEWS.d/next/Library/2024-02-08-14-21-28.gh-issue-115133.ycl4ko.rst -new file mode 100644 -index 0000000000..6f1015235c ---- /dev/null -+++ b/Misc/NEWS.d/next/Library/2024-02-08-14-21-28.gh-issue-115133.ycl4ko.rst -@@ -0,0 +1,2 @@ -+Fix tests for :class:`~xml.etree.ElementTree.XMLPullParser` with Expat -+2.6.0. diff --git a/python3.11.spec b/python3.11.spec index 2204ec1..fcfbc0c 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}.8 +%global general_version %{pybasever}.9 #global prerel ... %global upstream_version %{general_version}%{?prerel} Version: %{general_version}%{?prerel:~%{prerel}} -Release: 2%{?dist} +Release: 1%{?dist} License: Python-2.0.1 @@ -326,13 +326,6 @@ Patch371: 00371-revert-bpo-1596321-fix-threading-_shutdown-for-the-main-thread-g # Thomas Dwyer. Patch415: 00415-cve-2023-27043-gh-102988-reject-malformed-addresses-in-email-parseaddr-111116.patch -# 00422 # a353cebef737c41420dc7ae2469dd657371b8881 -# gh-115133: Fix tests for XMLPullParser with Expat 2.6.0 -# -# Feeding the parser by too small chunks defers parsing to prevent -# CVE-2023-52425. Future versions of Expat may be more reactive. -Patch422: 00422-gh-115133-fix-tests-for-xmlpullparser-with-expat-2-6-0.patch - # (New patches go here ^^^) # # When adding new patches to "python" and "python3" in Fedora, EL, etc., @@ -1635,6 +1628,9 @@ CheckPython optimized # ====================================================== %changelog +* Tue Apr 09 2024 Tomáš Hrnčiar - 3.11.9-1 +- Update to 3.11.9 + * Wed Feb 28 2024 Charalampos Stratakis - 3.11.8-2 - Fix tests for XMLPullParser with Expat 2.6.0 diff --git a/sources b/sources index 73bdfe7..86a3b52 100644 --- a/sources +++ b/sources @@ -1,2 +1,2 @@ -SHA512 (Python-3.11.8.tar.xz) = 434e727fa370def348838fd84acb69b4d309cfb03f61bf5069150164e9ca005637ac01dfbf997f445607d4e28d02c8bed0858b36589240ccadaa4c14c19f2320 -SHA512 (Python-3.11.8.tar.xz.asc) = aebec01f84e96a76f6c5949004df2bb51c817bac3fc8d925ee26ded1ff2d80bec1b579dd0fc129004bc9cd81cbdcdcdf7c1f0471c3d26b70bd6dac11b97187e0 +SHA512 (Python-3.11.9.tar.xz) = 2b0a1d936b4ef8376f9655797aece8ffdff75031ad7bfa840f330cac2aed189aecc80c163edc12ea772851d7a011f3fc1960470a73d9d4290cf3ab8ad6ed7e6a +SHA512 (Python-3.11.9.tar.xz.asc) = b18b50e7168b2ca5376a1fa75e50e8baae2026d4f11d4cf613d758f3f17df4610fe4653fb2ac0c5c4ec0f6e630dc6490ad1ff32a2fd0ebd60f9f3bd136207ffc From f5eb1e0bd19b72f4bd1c4e4e9863dc6e10fb8a0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Wed, 17 Apr 2024 22:58:28 +0000 Subject: [PATCH 077/118] Require expat >= 2.6 to prevent errors when creating venvs with older expat The code in CPython uses XML_SetReparseDeferralEnabled when expat is >= 2.6 during the build. However, when users upgrade Python independently on the expat package, they may have expat 2.5 installed and see errors like: $ python3.1X -m venv venv Error: Command '['venv/bin/python3.1X', '-m', 'ensurepip', '--upgrade', '--default-pip']' returned non-zero exit status 1. $ venv/bin/python3.1X -m ensurepip --upgrade --default-pip Traceback (most recent call last): ... File "/tmp/.../pip-24.0-py3-none-any.whl/pip/_internal/commands/install.py", line 15, in from pip._internal.cli.req_command import ( ...<3 lines>... ) File "/tmp/.../pip-24.0-py3-none-any.whl/pip/_internal/cli/req_command.py", line 21, in from pip._internal.index.package_finder import PackageFinder File "/tmp/.../pip-24.0-py3-none-any.whl/pip/_internal/index/package_finder.py", line 30, in from pip._internal.req import InstallRequirement File "/tmp/.../pip-24.0-py3-none-any.whl/pip/_internal/req/__init__.py", line 8, in from .req_install import InstallRequirement File "/tmp/.../pip-24.0-py3-none-any.whl/pip/_internal/req/req_install.py", line 40, in from pip._internal.operations.install.wheel import install_wheel File "/tmp/.../pip-24.0-py3-none-any.whl/pip/_internal/operations/install/wheel.py", line 39, in from pip._vendor.distlib.scripts import ScriptMaker File "/tmp/.../pip-24.0-py3-none-any.whl/pip/_vendor/distlib/scripts.py", line 16, in from .compat import sysconfig, detect_encoding, ZipFile File "/tmp/.../pip-24.0-py3-none-any.whl/pip/_vendor/distlib/compat.py", line 81, in import xmlrpc.client as xmlrpclib File "/usr/lib64/python3.1X/xmlrpc/client.py", line 138, in from xml.parsers import expat File "/usr/lib64/python3.1X/xml/parsers/expat.py", line 4, in from pyexpat import * ImportError: /usr/lib64/python3.1X/lib-dynload/pyexpat.cpython-31X-x86_64-linux-gnu.so: undefined symbol: XML_SetReparseDeferralEnabled Traceback (most recent call last): ... subprocess.CalledProcessError: Command '['venv/bin/python3.1X', '-W', 'ignore::DeprecationWarning', '-c', '\nimport runpy\nimport sys\nsys.path = [\'/tmp/.../pip-24.0-py3-none-any.whl\'] + sys.path\nsys.argv[1:] = [\'install\', \'--no-cache-dir\', \'--no-index\', \'--find-links\', \'/tmp/...\', \'--upgrade\', \'pip\']\nrunpy.run_module("pip", run_name="__main__", alter_sys=True)\n']' returned non-zero exit status 1. Thanks to Markus Falb for discovering this problem. https://lists.fedoraproject.org/archives/list/python-devel@lists.fedoraproject.org/thread/7XHGWHBQDNFKNGSZTP44SSD6PQKZPG6C/ --- python3.11.spec | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/python3.11.spec b/python3.11.spec index fcfbc0c..1d780b6 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,7 +192,8 @@ BuildRequires: bluez-libs-devel BuildRequires: bzip2 BuildRequires: bzip2-devel BuildRequires: desktop-file-utils -BuildRequires: expat-devel +# See the runtime requirement in the -libs subpackage +BuildRequires: expat-devel >= 2.6 BuildRequires: findutils BuildRequires: gcc-c++ @@ -476,6 +477,14 @@ Recommends: (%{pkgname}-tkinter%{?_isa} = %{version}-%{release} if tk%{?_isa}) # The zoneinfo module needs tzdata 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: +# ImportError: /usr/lib64/python3.X/lib-dynload/pyexpat.cpython-....so: +# undefined symbol: XML_SetReparseDeferralEnabled +# This breaks many things, including python -m venv. +# Other subpackages (like -debug) also need this, but they all depend on -libs. +Requires: expat >= 2.6 + %description -n %{pkgname}-libs This package contains runtime libraries for use by Python: - the majority of the Python standard library @@ -1628,6 +1637,9 @@ CheckPython optimized # ====================================================== %changelog +* Wed Apr 17 2024 Miro Hrončok - 3.11.9-2 +- Require expat >= 2.6 to prevent errors when creating venvs with older expat + * Tue Apr 09 2024 Tomáš Hrnčiar - 3.11.9-1 - Update to 3.11.9 From 2a371279367f9448b3dcb5a3032265eb87beed6a Mon Sep 17 00:00:00 2001 From: Fedora Release Engineering Date: Fri, 19 Jul 2024 17:26:12 +0000 Subject: [PATCH 078/118] Rebuilt for https://fedoraproject.org/wiki/Fedora_41_Mass_Rebuild --- python3.11.spec | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/python3.11.spec b/python3.11.spec index 1d780b6..ca76d88 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 @@ -1637,6 +1637,9 @@ CheckPython optimized # ====================================================== %changelog +* Fri Jul 19 2024 Fedora Release Engineering - 3.11.9-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_41_Mass_Rebuild + * Wed Apr 17 2024 Miro Hrončok - 3.11.9-2 - Require expat >= 2.6 to prevent errors when creating venvs with older expat From 5c3351913be19cba86806a06dab10e141707d750 Mon Sep 17 00:00:00 2001 From: Lumir Balhar Date: Tue, 23 Jul 2024 13:24:37 +0200 Subject: [PATCH 079/118] Require systemtap-sdt-devel for sys/sdt.h --- python3.11.spec | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/python3.11.spec b/python3.11.spec index ca76d88..22be75b 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 @@ -239,6 +239,7 @@ BuildRequires: valgrind-devel BuildRequires: xz-devel BuildRequires: zlib-devel +BuildRequires: systemtap-sdt-devel BuildRequires: /usr/bin/dtrace # workaround http://bugs.python.org/issue19804 (test_uuid requires ifconfig) @@ -1637,6 +1638,9 @@ CheckPython optimized # ====================================================== %changelog +* Tue Jul 23 2024 Lumír Balhar - 3.11.9-4 +- Require systemtap-sdt-devel for sys/sdt.h + * Fri Jul 19 2024 Fedora Release Engineering - 3.11.9-3 - Rebuilt for https://fedoraproject.org/wiki/Fedora_41_Mass_Rebuild From 8ff163b3f28cac3f8a81f883e63b319b967d5f5b Mon Sep 17 00:00:00 2001 From: Charalampos Stratakis Date: Fri, 16 Aug 2024 01:50:57 +0200 Subject: [PATCH 080/118] Security fix for CVE-2024-4032 (rhbz#2293391) --- ...113179-gh-113186-gh-118177-gh-118472.patch | 366 ++++++++++++++++++ python3.11.spec | 33 +- 2 files changed, 398 insertions(+), 1 deletion(-) create mode 100644 00431-gh-113171-gh-65056-fix-private-non-global-ip-address-ranges-gh-113179-gh-113186-gh-118177-gh-118472.patch diff --git a/00431-gh-113171-gh-65056-fix-private-non-global-ip-address-ranges-gh-113179-gh-113186-gh-118177-gh-118472.patch b/00431-gh-113171-gh-65056-fix-private-non-global-ip-address-ranges-gh-113179-gh-113186-gh-118177-gh-118472.patch new file mode 100644 index 0000000..d2a19ab --- /dev/null +++ b/00431-gh-113171-gh-65056-fix-private-non-global-ip-address-ranges-gh-113179-gh-113186-gh-118177-gh-118472.patch @@ -0,0 +1,366 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Petr Viktorin +Date: Thu, 25 Apr 2024 14:45:48 +0200 +Subject: [PATCH] 00431: gh-113171: gh-65056: Fix "private" (non-global) IP + address ranges (GH-113179) (GH-113186) (GH-118177) (GH-118472) + +The _private_networks variables, used by various is_private +implementations, were missing some ranges and at the same time had +overly strict ranges (where there are more specific ranges considered +globally reachable by the IANA registries). + +This patch updates the ranges with what was missing or otherwise +incorrect. + +100.64.0.0/10 is left alone, for now, as it's been made special in [1]. + +The _address_exclude_many() call returns 8 networks for IPv4, 121 +networks for IPv6. + +[1] https://github.com/python/cpython/issues/61602 + +In 3.10 and below, is_private checks whether the network and broadcast +address are both private. +In later versions (where the test wss backported from), it checks +whether they both are in the same private network. + +For 0.0.0.0/0, both 0.0.0.0 and 255.225.255.255 are private, +but one is in 0.0.0.0/8 ("This network") and the other in +255.255.255.255/32 ("Limited broadcast"). +--- + Doc/library/ipaddress.rst | 43 +++++++- + Doc/whatsnew/3.11.rst | 9 ++ + Lib/ipaddress.py | 99 +++++++++++++++---- + Lib/test/test_ipaddress.py | 21 +++- + ...-03-14-01-38-44.gh-issue-113171.VFnObz.rst | 9 ++ + 5 files changed, 157 insertions(+), 24 deletions(-) + create mode 100644 Misc/NEWS.d/next/Library/2024-03-14-01-38-44.gh-issue-113171.VFnObz.rst + +diff --git a/Doc/library/ipaddress.rst b/Doc/library/ipaddress.rst +index 03dc956cd1..f57fa15aa5 100644 +--- a/Doc/library/ipaddress.rst ++++ b/Doc/library/ipaddress.rst +@@ -178,18 +178,53 @@ write code that handles both IP versions correctly. Address objects are + + .. attribute:: is_private + +- ``True`` if the address is allocated for private networks. See ++ ``True`` if the address is defined as not globally reachable by + iana-ipv4-special-registry_ (for IPv4) or iana-ipv6-special-registry_ +- (for IPv6). ++ (for IPv6) with the following exceptions: ++ ++ * ``is_private`` is ``False`` for the shared address space (``100.64.0.0/10``) ++ * For IPv4-mapped IPv6-addresses the ``is_private`` value is determined by the ++ semantics of the underlying IPv4 addresses and the following condition holds ++ (see :attr:`IPv6Address.ipv4_mapped`):: ++ ++ address.is_private == address.ipv4_mapped.is_private ++ ++ ``is_private`` has value opposite to :attr:`is_global`, except for the shared address space ++ (``100.64.0.0/10`` range) where they are both ``False``. ++ ++ .. versionchanged:: 3.11.10 ++ ++ Fixed some false positives and false negatives. ++ ++ * ``192.0.0.0/24`` is considered private with the exception of ``192.0.0.9/32`` and ++ ``192.0.0.10/32`` (previously: only the ``192.0.0.0/29`` sub-range was considered private). ++ * ``64:ff9b:1::/48`` is considered private. ++ * ``2002::/16`` is considered private. ++ * There are exceptions within ``2001::/23`` (otherwise considered private): ``2001:1::1/128``, ++ ``2001:1::2/128``, ``2001:3::/32``, ``2001:4:112::/48``, ``2001:20::/28``, ``2001:30::/28``. ++ The exceptions are not considered private. + + .. attribute:: is_global + +- ``True`` if the address is allocated for public networks. See ++ ``True`` if the address is defined as globally reachable by + iana-ipv4-special-registry_ (for IPv4) or iana-ipv6-special-registry_ +- (for IPv6). ++ (for IPv6) with the following exception: ++ ++ For IPv4-mapped IPv6-addresses the ``is_private`` value is determined by the ++ semantics of the underlying IPv4 addresses and the following condition holds ++ (see :attr:`IPv6Address.ipv4_mapped`):: ++ ++ address.is_global == address.ipv4_mapped.is_global ++ ++ ``is_global`` has value opposite to :attr:`is_private`, except for the shared address space ++ (``100.64.0.0/10`` range) where they are both ``False``. + + .. versionadded:: 3.4 + ++ .. versionchanged:: 3.11.10 ++ ++ Fixed some false positives and false negatives, see :attr:`is_private` for details. ++ + .. attribute:: is_unspecified + + ``True`` if the address is unspecified. See :RFC:`5735` (for IPv4) +diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst +index f670fa1f09..42b61c75c7 100644 +--- a/Doc/whatsnew/3.11.rst ++++ b/Doc/whatsnew/3.11.rst +@@ -2727,3 +2727,12 @@ OpenSSL + * Windows builds and macOS installers from python.org now use OpenSSL 3.0. + + .. _libb2: https://www.blake2.net/ ++ ++Notable changes in 3.11.10 ++========================== ++ ++ipaddress ++--------- ++ ++* Fixed ``is_global`` and ``is_private`` behavior in ``IPv4Address``, ++ ``IPv6Address``, ``IPv4Network`` and ``IPv6Network``. +diff --git a/Lib/ipaddress.py b/Lib/ipaddress.py +index 16ba16cd7d..567beb37e0 100644 +--- a/Lib/ipaddress.py ++++ b/Lib/ipaddress.py +@@ -1086,7 +1086,11 @@ def is_private(self): + """ + return any(self.network_address in priv_network and + self.broadcast_address in priv_network +- for priv_network in self._constants._private_networks) ++ for priv_network in self._constants._private_networks) and all( ++ self.network_address not in network and ++ self.broadcast_address not in network ++ for network in self._constants._private_networks_exceptions ++ ) + + @property + def is_global(self): +@@ -1333,18 +1337,41 @@ def is_reserved(self): + @property + @functools.lru_cache() + def is_private(self): +- """Test if this address is allocated for private networks. ++ """``True`` if the address is defined as not globally reachable by ++ iana-ipv4-special-registry_ (for IPv4) or iana-ipv6-special-registry_ ++ (for IPv6) with the following exceptions: + +- Returns: +- A boolean, True if the address is reserved per +- iana-ipv4-special-registry. ++ * ``is_private`` is ``False`` for ``100.64.0.0/10`` ++ * For IPv4-mapped IPv6-addresses the ``is_private`` value is determined by the ++ semantics of the underlying IPv4 addresses and the following condition holds ++ (see :attr:`IPv6Address.ipv4_mapped`):: + ++ address.is_private == address.ipv4_mapped.is_private ++ ++ ``is_private`` has value opposite to :attr:`is_global`, except for the ``100.64.0.0/10`` ++ IPv4 range where they are both ``False``. + """ +- return any(self in net for net in self._constants._private_networks) ++ return ( ++ any(self in net for net in self._constants._private_networks) ++ and all(self not in net for net in self._constants._private_networks_exceptions) ++ ) + + @property + @functools.lru_cache() + def is_global(self): ++ """``True`` if the address is defined as globally reachable by ++ iana-ipv4-special-registry_ (for IPv4) or iana-ipv6-special-registry_ ++ (for IPv6) with the following exception: ++ ++ For IPv4-mapped IPv6-addresses the ``is_private`` value is determined by the ++ semantics of the underlying IPv4 addresses and the following condition holds ++ (see :attr:`IPv6Address.ipv4_mapped`):: ++ ++ address.is_global == address.ipv4_mapped.is_global ++ ++ ``is_global`` has value opposite to :attr:`is_private`, except for the ``100.64.0.0/10`` ++ IPv4 range where they are both ``False``. ++ """ + return self not in self._constants._public_network and not self.is_private + + @property +@@ -1548,13 +1575,15 @@ class _IPv4Constants: + + _public_network = IPv4Network('100.64.0.0/10') + ++ # Not globally reachable address blocks listed on ++ # https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml + _private_networks = [ + IPv4Network('0.0.0.0/8'), + IPv4Network('10.0.0.0/8'), + IPv4Network('127.0.0.0/8'), + IPv4Network('169.254.0.0/16'), + IPv4Network('172.16.0.0/12'), +- IPv4Network('192.0.0.0/29'), ++ IPv4Network('192.0.0.0/24'), + IPv4Network('192.0.0.170/31'), + IPv4Network('192.0.2.0/24'), + IPv4Network('192.168.0.0/16'), +@@ -1565,6 +1594,11 @@ class _IPv4Constants: + IPv4Network('255.255.255.255/32'), + ] + ++ _private_networks_exceptions = [ ++ IPv4Network('192.0.0.9/32'), ++ IPv4Network('192.0.0.10/32'), ++ ] ++ + _reserved_network = IPv4Network('240.0.0.0/4') + + _unspecified_address = IPv4Address('0.0.0.0') +@@ -2010,27 +2044,42 @@ def is_site_local(self): + @property + @functools.lru_cache() + def is_private(self): +- """Test if this address is allocated for private networks. ++ """``True`` if the address is defined as not globally reachable by ++ iana-ipv4-special-registry_ (for IPv4) or iana-ipv6-special-registry_ ++ (for IPv6) with the following exceptions: + +- Returns: +- A boolean, True if the address is reserved per +- iana-ipv6-special-registry, or is ipv4_mapped and is +- reserved in the iana-ipv4-special-registry. ++ * ``is_private`` is ``False`` for ``100.64.0.0/10`` ++ * For IPv4-mapped IPv6-addresses the ``is_private`` value is determined by the ++ semantics of the underlying IPv4 addresses and the following condition holds ++ (see :attr:`IPv6Address.ipv4_mapped`):: + ++ address.is_private == address.ipv4_mapped.is_private ++ ++ ``is_private`` has value opposite to :attr:`is_global`, except for the ``100.64.0.0/10`` ++ IPv4 range where they are both ``False``. + """ + ipv4_mapped = self.ipv4_mapped + if ipv4_mapped is not None: + return ipv4_mapped.is_private +- return any(self in net for net in self._constants._private_networks) ++ return ( ++ any(self in net for net in self._constants._private_networks) ++ and all(self not in net for net in self._constants._private_networks_exceptions) ++ ) + + @property + def is_global(self): +- """Test if this address is allocated for public networks. ++ """``True`` if the address is defined as globally reachable by ++ iana-ipv4-special-registry_ (for IPv4) or iana-ipv6-special-registry_ ++ (for IPv6) with the following exception: + +- Returns: +- A boolean, true if the address is not reserved per +- iana-ipv6-special-registry. ++ For IPv4-mapped IPv6-addresses the ``is_private`` value is determined by the ++ semantics of the underlying IPv4 addresses and the following condition holds ++ (see :attr:`IPv6Address.ipv4_mapped`):: + ++ address.is_global == address.ipv4_mapped.is_global ++ ++ ``is_global`` has value opposite to :attr:`is_private`, except for the ``100.64.0.0/10`` ++ IPv4 range where they are both ``False``. + """ + return not self.is_private + +@@ -2271,19 +2320,31 @@ class _IPv6Constants: + + _multicast_network = IPv6Network('ff00::/8') + ++ # Not globally reachable address blocks listed on ++ # https://www.iana.org/assignments/iana-ipv6-special-registry/iana-ipv6-special-registry.xhtml + _private_networks = [ + IPv6Network('::1/128'), + IPv6Network('::/128'), + IPv6Network('::ffff:0:0/96'), ++ IPv6Network('64:ff9b:1::/48'), + IPv6Network('100::/64'), + IPv6Network('2001::/23'), +- IPv6Network('2001:2::/48'), + IPv6Network('2001:db8::/32'), +- IPv6Network('2001:10::/28'), ++ # IANA says N/A, let's consider it not globally reachable to be safe ++ IPv6Network('2002::/16'), + IPv6Network('fc00::/7'), + IPv6Network('fe80::/10'), + ] + ++ _private_networks_exceptions = [ ++ IPv6Network('2001:1::1/128'), ++ IPv6Network('2001:1::2/128'), ++ IPv6Network('2001:3::/32'), ++ IPv6Network('2001:4:112::/48'), ++ IPv6Network('2001:20::/28'), ++ IPv6Network('2001:30::/28'), ++ ] ++ + _reserved_networks = [ + IPv6Network('::/8'), IPv6Network('100::/8'), + IPv6Network('200::/7'), IPv6Network('400::/6'), +diff --git a/Lib/test/test_ipaddress.py b/Lib/test/test_ipaddress.py +index fc27628af1..16c34163a0 100644 +--- a/Lib/test/test_ipaddress.py ++++ b/Lib/test/test_ipaddress.py +@@ -2269,6 +2269,10 @@ def testReservedIpv4(self): + self.assertEqual(True, ipaddress.ip_address( + '172.31.255.255').is_private) + self.assertEqual(False, ipaddress.ip_address('172.32.0.0').is_private) ++ self.assertFalse(ipaddress.ip_address('192.0.0.0').is_global) ++ self.assertTrue(ipaddress.ip_address('192.0.0.9').is_global) ++ self.assertTrue(ipaddress.ip_address('192.0.0.10').is_global) ++ self.assertFalse(ipaddress.ip_address('192.0.0.255').is_global) + + self.assertEqual(True, + ipaddress.ip_address('169.254.100.200').is_link_local) +@@ -2294,6 +2298,7 @@ def testPrivateNetworks(self): + self.assertEqual(True, ipaddress.ip_network("169.254.0.0/16").is_private) + self.assertEqual(True, ipaddress.ip_network("172.16.0.0/12").is_private) + self.assertEqual(True, ipaddress.ip_network("192.0.0.0/29").is_private) ++ self.assertEqual(False, ipaddress.ip_network("192.0.0.9/32").is_private) + self.assertEqual(True, ipaddress.ip_network("192.0.0.170/31").is_private) + self.assertEqual(True, ipaddress.ip_network("192.0.2.0/24").is_private) + self.assertEqual(True, ipaddress.ip_network("192.168.0.0/16").is_private) +@@ -2310,8 +2315,8 @@ def testPrivateNetworks(self): + self.assertEqual(True, ipaddress.ip_network("::/128").is_private) + self.assertEqual(True, ipaddress.ip_network("::ffff:0:0/96").is_private) + self.assertEqual(True, ipaddress.ip_network("100::/64").is_private) +- self.assertEqual(True, ipaddress.ip_network("2001::/23").is_private) + self.assertEqual(True, ipaddress.ip_network("2001:2::/48").is_private) ++ self.assertEqual(False, ipaddress.ip_network("2001:3::/48").is_private) + self.assertEqual(True, ipaddress.ip_network("2001:db8::/32").is_private) + self.assertEqual(True, ipaddress.ip_network("2001:10::/28").is_private) + self.assertEqual(True, ipaddress.ip_network("fc00::/7").is_private) +@@ -2390,6 +2395,20 @@ def testReservedIpv6(self): + self.assertEqual(True, ipaddress.ip_address('0::0').is_unspecified) + self.assertEqual(False, ipaddress.ip_address('::1').is_unspecified) + ++ self.assertFalse(ipaddress.ip_address('64:ff9b:1::').is_global) ++ self.assertFalse(ipaddress.ip_address('2001::').is_global) ++ self.assertTrue(ipaddress.ip_address('2001:1::1').is_global) ++ self.assertTrue(ipaddress.ip_address('2001:1::2').is_global) ++ self.assertFalse(ipaddress.ip_address('2001:2::').is_global) ++ self.assertTrue(ipaddress.ip_address('2001:3::').is_global) ++ self.assertFalse(ipaddress.ip_address('2001:4::').is_global) ++ self.assertTrue(ipaddress.ip_address('2001:4:112::').is_global) ++ self.assertFalse(ipaddress.ip_address('2001:10::').is_global) ++ self.assertTrue(ipaddress.ip_address('2001:20::').is_global) ++ self.assertTrue(ipaddress.ip_address('2001:30::').is_global) ++ self.assertFalse(ipaddress.ip_address('2001:40::').is_global) ++ self.assertFalse(ipaddress.ip_address('2002::').is_global) ++ + # some generic IETF reserved addresses + self.assertEqual(True, ipaddress.ip_address('100::').is_reserved) + self.assertEqual(True, ipaddress.ip_network('4000::1/128').is_reserved) +diff --git a/Misc/NEWS.d/next/Library/2024-03-14-01-38-44.gh-issue-113171.VFnObz.rst b/Misc/NEWS.d/next/Library/2024-03-14-01-38-44.gh-issue-113171.VFnObz.rst +new file mode 100644 +index 0000000000..f9a72473be +--- /dev/null ++++ b/Misc/NEWS.d/next/Library/2024-03-14-01-38-44.gh-issue-113171.VFnObz.rst +@@ -0,0 +1,9 @@ ++Fixed various false positives and false negatives in ++ ++* :attr:`ipaddress.IPv4Address.is_private` (see these docs for details) ++* :attr:`ipaddress.IPv4Address.is_global` ++* :attr:`ipaddress.IPv6Address.is_private` ++* :attr:`ipaddress.IPv6Address.is_global` ++ ++Also in the corresponding :class:`ipaddress.IPv4Network` and :class:`ipaddress.IPv6Network` ++attributes. diff --git a/python3.11.spec b/python3.11.spec index 22be75b..75de8f8 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 @@ -328,6 +328,34 @@ Patch371: 00371-revert-bpo-1596321-fix-threading-_shutdown-for-the-main-thread-g # Thomas Dwyer. Patch415: 00415-cve-2023-27043-gh-102988-reject-malformed-addresses-in-email-parseaddr-111116.patch +# 00431 # 4e176bf669bb71e518ee3e79a492ae02ec6397bc +# gh-113171: gh-65056: Fix "private" (non-global) IP address ranges (GH-113179) (GH-113186) (GH-118177) (GH-118472) +# +# The _private_networks variables, used by various is_private +# implementations, were missing some ranges and at the same time had +# overly strict ranges (where there are more specific ranges considered +# globally reachable by the IANA registries). +# +# This patch updates the ranges with what was missing or otherwise +# incorrect. +# +# 100.64.0.0/10 is left alone, for now, as it's been made special in [1]. +# +# The _address_exclude_many() call returns 8 networks for IPv4, 121 +# networks for IPv6. +# +# [1] https://github.com/python/cpython/issues/61602 +# +# In 3.10 and below, is_private checks whether the network and broadcast +# address are both private. +# In later versions (where the test wss backported from), it checks +# whether they both are in the same private network. +# +# For 0.0.0.0/0, both 0.0.0.0 and 255.225.255.255 are private, +# but one is in 0.0.0.0/8 ("This network") and the other in +# 255.255.255.255/32 ("Limited broadcast"). +Patch431: 00431-gh-113171-gh-65056-fix-private-non-global-ip-address-ranges-gh-113179-gh-113186-gh-118177-gh-118472.patch + # (New patches go here ^^^) # # When adding new patches to "python" and "python3" in Fedora, EL, etc., @@ -1638,6 +1666,9 @@ CheckPython optimized # ====================================================== %changelog +* Thu Aug 15 2024 Charalampos Stratakis - 3.11.9-5 +- Security fix for CVE-2024-4032 (rhbz#2293391) + * Tue Jul 23 2024 Lumír Balhar - 3.11.9-4 - Require systemtap-sdt-devel for sys/sdt.h From 0ba33378139ba657236286e46ed218d09da0e033 Mon Sep 17 00:00:00 2001 From: Charalampos Stratakis Date: Fri, 16 Aug 2024 01:52:30 +0200 Subject: [PATCH 081/118] Security fix for CVE-2024-6923 (rhbz#2303158) --- ...d-verify-headers-are-sound-gh-122233.patch | 365 ++++++++++++++++++ python3.11.spec | 20 + 2 files changed, 385 insertions(+) create mode 100644 00435-gh-121650-encode-newlines-in-headers-and-verify-headers-are-sound-gh-122233.patch diff --git a/00435-gh-121650-encode-newlines-in-headers-and-verify-headers-are-sound-gh-122233.patch b/00435-gh-121650-encode-newlines-in-headers-and-verify-headers-are-sound-gh-122233.patch new file mode 100644 index 0000000..5d0fd3d --- /dev/null +++ b/00435-gh-121650-encode-newlines-in-headers-and-verify-headers-are-sound-gh-122233.patch @@ -0,0 +1,365 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Petr Viktorin +Date: Wed, 31 Jul 2024 00:19:48 +0200 +Subject: [PATCH] 00435: gh-121650: Encode newlines in headers, and verify + headers are sound (GH-122233) + +Per RFC 2047: + +> [...] these encoding schemes allow the +> encoding of arbitrary octet values, mail readers that implement this +> decoding should also ensure that display of the decoded data on the +> recipient's terminal will not cause unwanted side-effects + +It seems that the "quoted-word" scheme is a valid way to include +a newline character in a header value, just like we already allow +undecodable bytes or control characters. +They do need to be properly quoted when serialized to text, though. + +This should fail for custom fold() implementations that aren't careful +about newlines. + +(cherry picked from commit 097633981879b3c9de9a1dd120d3aa585ecc2384) + +Co-authored-by: Petr Viktorin +Co-authored-by: Bas Bloemsaat +Co-authored-by: Serhiy Storchaka +--- + Doc/library/email.errors.rst | 7 +++ + Doc/library/email.policy.rst | 18 ++++++ + Doc/whatsnew/3.11.rst | 13 ++++ + Lib/email/_header_value_parser.py | 12 +++- + Lib/email/_policybase.py | 8 +++ + Lib/email/errors.py | 4 ++ + Lib/email/generator.py | 13 +++- + Lib/test/test_email/test_generator.py | 62 +++++++++++++++++++ + Lib/test/test_email/test_policy.py | 26 ++++++++ + ...-07-27-16-10-41.gh-issue-121650.nf6oc9.rst | 5 ++ + 10 files changed, 164 insertions(+), 4 deletions(-) + create mode 100644 Misc/NEWS.d/next/Library/2024-07-27-16-10-41.gh-issue-121650.nf6oc9.rst + +diff --git a/Doc/library/email.errors.rst b/Doc/library/email.errors.rst +index 56aea6598b..27b0481a85 100644 +--- a/Doc/library/email.errors.rst ++++ b/Doc/library/email.errors.rst +@@ -58,6 +58,13 @@ The following exception classes are defined in the :mod:`email.errors` module: + :class:`~email.mime.nonmultipart.MIMENonMultipart` (e.g. + :class:`~email.mime.image.MIMEImage`). + ++ ++.. exception:: HeaderWriteError() ++ ++ Raised when an error occurs when the :mod:`~email.generator` outputs ++ headers. ++ ++ + .. exception:: MessageDefect() + + This is the base class for all defects found when parsing email messages. +diff --git a/Doc/library/email.policy.rst b/Doc/library/email.policy.rst +index bb406c5a56..3edba4028b 100644 +--- a/Doc/library/email.policy.rst ++++ b/Doc/library/email.policy.rst +@@ -228,6 +228,24 @@ added matters. To illustrate:: + + .. versionadded:: 3.6 + ++ ++ .. attribute:: verify_generated_headers ++ ++ If ``True`` (the default), the generator will raise ++ :exc:`~email.errors.HeaderWriteError` instead of writing a header ++ that is improperly folded or delimited, such that it would ++ be parsed as multiple headers or joined with adjacent data. ++ Such headers can be generated by custom header classes or bugs ++ in the ``email`` module. ++ ++ As it's a security feature, this defaults to ``True`` even in the ++ :class:`~email.policy.Compat32` policy. ++ For backwards compatible, but unsafe, behavior, it must be set to ++ ``False`` explicitly. ++ ++ .. versionadded:: 3.11.10 ++ ++ + The following :class:`Policy` method is intended to be called by code using + the email library to create policy instances with custom settings: + +diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst +index 42b61c75c7..f12c871998 100644 +--- a/Doc/whatsnew/3.11.rst ++++ b/Doc/whatsnew/3.11.rst +@@ -2728,6 +2728,7 @@ OpenSSL + + .. _libb2: https://www.blake2.net/ + ++ + Notable changes in 3.11.10 + ========================== + +@@ -2736,3 +2737,15 @@ ipaddress + + * Fixed ``is_global`` and ``is_private`` behavior in ``IPv4Address``, + ``IPv6Address``, ``IPv4Network`` and ``IPv6Network``. ++ ++email ++----- ++ ++* Headers with embedded newlines are now quoted on output. ++ ++ The :mod:`~email.generator` will now refuse to serialize (write) headers ++ that are improperly folded or delimited, such that they would be parsed as ++ multiple headers or joined with adjacent data. ++ If you need to turn this safety feature off, ++ set :attr:`~email.policy.Policy.verify_generated_headers`. ++ (Contributed by Bas Bloemsaat and Petr Viktorin in :gh:`121650`.) +diff --git a/Lib/email/_header_value_parser.py b/Lib/email/_header_value_parser.py +index 8cb8852cf0..255a953092 100644 +--- a/Lib/email/_header_value_parser.py ++++ b/Lib/email/_header_value_parser.py +@@ -92,6 +92,8 @@ + ASPECIALS = TSPECIALS | set("*'%") + ATTRIBUTE_ENDS = ASPECIALS | WSP + EXTENDED_ATTRIBUTE_ENDS = ATTRIBUTE_ENDS - set('%') ++NLSET = {'\n', '\r'} ++SPECIALSNL = SPECIALS | NLSET + + def quote_string(value): + return '"'+str(value).replace('\\', '\\\\').replace('"', r'\"')+'"' +@@ -2780,9 +2782,13 @@ def _refold_parse_tree(parse_tree, *, policy): + wrap_as_ew_blocked -= 1 + continue + tstr = str(part) +- if part.token_type == 'ptext' and set(tstr) & SPECIALS: +- # Encode if tstr contains special characters. +- want_encoding = True ++ if not want_encoding: ++ if part.token_type == 'ptext': ++ # Encode if tstr contains special characters. ++ want_encoding = not SPECIALSNL.isdisjoint(tstr) ++ else: ++ # Encode if tstr contains newlines. ++ want_encoding = not NLSET.isdisjoint(tstr) + try: + tstr.encode(encoding) + charset = encoding +diff --git a/Lib/email/_policybase.py b/Lib/email/_policybase.py +index c9cbadd2a8..d1f48211f9 100644 +--- a/Lib/email/_policybase.py ++++ b/Lib/email/_policybase.py +@@ -157,6 +157,13 @@ class Policy(_PolicyBase, metaclass=abc.ABCMeta): + message_factory -- the class to use to create new message objects. + If the value is None, the default is Message. + ++ verify_generated_headers ++ -- if true, the generator verifies that each header ++ they are properly folded, so that a parser won't ++ treat it as multiple headers, start-of-body, or ++ part of another header. ++ This is a check against custom Header & fold() ++ implementations. + """ + + raise_on_defect = False +@@ -165,6 +172,7 @@ class Policy(_PolicyBase, metaclass=abc.ABCMeta): + max_line_length = 78 + mangle_from_ = False + message_factory = None ++ verify_generated_headers = True + + def handle_defect(self, obj, defect): + """Based on policy, either raise defect or call register_defect. +diff --git a/Lib/email/errors.py b/Lib/email/errors.py +index 3ad0056554..02aa5eced6 100644 +--- a/Lib/email/errors.py ++++ b/Lib/email/errors.py +@@ -29,6 +29,10 @@ class CharsetError(MessageError): + """An illegal charset was given.""" + + ++class HeaderWriteError(MessageError): ++ """Error while writing headers.""" ++ ++ + # These are parsing defects which the parser was able to work around. + class MessageDefect(ValueError): + """Base class for a message defect.""" +diff --git a/Lib/email/generator.py b/Lib/email/generator.py +index eb597de76d..563ca17072 100644 +--- a/Lib/email/generator.py ++++ b/Lib/email/generator.py +@@ -14,12 +14,14 @@ + from copy import deepcopy + from io import StringIO, BytesIO + from email.utils import _has_surrogates ++from email.errors import HeaderWriteError + + UNDERSCORE = '_' + NL = '\n' # XXX: no longer used by the code below. + + NLCRE = re.compile(r'\r\n|\r|\n') + fcre = re.compile(r'^From ', re.MULTILINE) ++NEWLINE_WITHOUT_FWSP = re.compile(r'\r\n[^ \t]|\r[^ \n\t]|\n[^ \t]') + + + class Generator: +@@ -222,7 +224,16 @@ def _dispatch(self, msg): + + def _write_headers(self, msg): + for h, v in msg.raw_items(): +- self.write(self.policy.fold(h, v)) ++ folded = self.policy.fold(h, v) ++ if self.policy.verify_generated_headers: ++ linesep = self.policy.linesep ++ if not folded.endswith(self.policy.linesep): ++ raise HeaderWriteError( ++ f'folded header does not end with {linesep!r}: {folded!r}') ++ if NEWLINE_WITHOUT_FWSP.search(folded.removesuffix(linesep)): ++ raise HeaderWriteError( ++ f'folded header contains newline: {folded!r}') ++ self.write(folded) + # A blank line always separates headers from body + self.write(self._NL) + +diff --git a/Lib/test/test_email/test_generator.py b/Lib/test/test_email/test_generator.py +index 89e7edeb63..d29400f0ed 100644 +--- a/Lib/test/test_email/test_generator.py ++++ b/Lib/test/test_email/test_generator.py +@@ -6,6 +6,7 @@ + from email.generator import Generator, BytesGenerator + from email.headerregistry import Address + from email import policy ++import email.errors + from test.test_email import TestEmailBase, parameterize + + +@@ -216,6 +217,44 @@ def test_rfc2231_wrapping_switches_to_default_len_if_too_narrow(self): + g.flatten(msg) + self.assertEqual(s.getvalue(), self.typ(expected)) + ++ def test_keep_encoded_newlines(self): ++ msg = self.msgmaker(self.typ(textwrap.dedent("""\ ++ To: nobody ++ Subject: Bad subject=?UTF-8?Q?=0A?=Bcc: injection@example.com ++ ++ None ++ """))) ++ expected = textwrap.dedent("""\ ++ To: nobody ++ Subject: Bad subject=?UTF-8?Q?=0A?=Bcc: injection@example.com ++ ++ None ++ """) ++ s = self.ioclass() ++ g = self.genclass(s, policy=self.policy.clone(max_line_length=80)) ++ g.flatten(msg) ++ self.assertEqual(s.getvalue(), self.typ(expected)) ++ ++ def test_keep_long_encoded_newlines(self): ++ msg = self.msgmaker(self.typ(textwrap.dedent("""\ ++ To: nobody ++ Subject: Bad subject=?UTF-8?Q?=0A?=Bcc: injection@example.com ++ ++ None ++ """))) ++ expected = textwrap.dedent("""\ ++ To: nobody ++ Subject: Bad subject ++ =?utf-8?q?=0A?=Bcc: ++ injection@example.com ++ ++ None ++ """) ++ s = self.ioclass() ++ g = self.genclass(s, policy=self.policy.clone(max_line_length=30)) ++ g.flatten(msg) ++ self.assertEqual(s.getvalue(), self.typ(expected)) ++ + + class TestGenerator(TestGeneratorBase, TestEmailBase): + +@@ -224,6 +263,29 @@ class TestGenerator(TestGeneratorBase, TestEmailBase): + ioclass = io.StringIO + typ = str + ++ def test_verify_generated_headers(self): ++ """gh-121650: by default the generator prevents header injection""" ++ class LiteralHeader(str): ++ name = 'Header' ++ def fold(self, **kwargs): ++ return self ++ ++ for text in ( ++ 'Value\r\nBad Injection\r\n', ++ 'NoNewLine' ++ ): ++ with self.subTest(text=text): ++ message = message_from_string( ++ "Header: Value\r\n\r\nBody", ++ policy=self.policy, ++ ) ++ ++ del message['Header'] ++ message['Header'] = LiteralHeader(text) ++ ++ with self.assertRaises(email.errors.HeaderWriteError): ++ message.as_string() ++ + + class TestBytesGenerator(TestGeneratorBase, TestEmailBase): + +diff --git a/Lib/test/test_email/test_policy.py b/Lib/test/test_email/test_policy.py +index c6b9c80efe..baa35fd68e 100644 +--- a/Lib/test/test_email/test_policy.py ++++ b/Lib/test/test_email/test_policy.py +@@ -26,6 +26,7 @@ class PolicyAPITests(unittest.TestCase): + 'raise_on_defect': False, + 'mangle_from_': True, + 'message_factory': None, ++ 'verify_generated_headers': True, + } + # These default values are the ones set on email.policy.default. + # If any of these defaults change, the docs must be updated. +@@ -294,6 +295,31 @@ def test_short_maxlen_error(self): + with self.assertRaises(email.errors.HeaderParseError): + policy.fold("Subject", subject) + ++ def test_verify_generated_headers(self): ++ """Turning protection off allows header injection""" ++ policy = email.policy.default.clone(verify_generated_headers=False) ++ for text in ( ++ 'Header: Value\r\nBad: Injection\r\n', ++ 'Header: NoNewLine' ++ ): ++ with self.subTest(text=text): ++ message = email.message_from_string( ++ "Header: Value\r\n\r\nBody", ++ policy=policy, ++ ) ++ class LiteralHeader(str): ++ name = 'Header' ++ def fold(self, **kwargs): ++ return self ++ ++ del message['Header'] ++ message['Header'] = LiteralHeader(text) ++ ++ self.assertEqual( ++ message.as_string(), ++ f"{text}\nBody", ++ ) ++ + # XXX: Need subclassing tests. + # For adding subclassed objects, make sure the usual rules apply (subclass + # wins), but that the order still works (right overrides left). +diff --git a/Misc/NEWS.d/next/Library/2024-07-27-16-10-41.gh-issue-121650.nf6oc9.rst b/Misc/NEWS.d/next/Library/2024-07-27-16-10-41.gh-issue-121650.nf6oc9.rst +new file mode 100644 +index 0000000000..83dd28d4ac +--- /dev/null ++++ b/Misc/NEWS.d/next/Library/2024-07-27-16-10-41.gh-issue-121650.nf6oc9.rst +@@ -0,0 +1,5 @@ ++:mod:`email` headers with embedded newlines are now quoted on output. The ++:mod:`~email.generator` will now refuse to serialize (write) headers that ++are unsafely folded or delimited; see ++:attr:`~email.policy.Policy.verify_generated_headers`. (Contributed by Bas ++Bloemsaat and Petr Viktorin in :gh:`121650`.) diff --git a/python3.11.spec b/python3.11.spec index 75de8f8..9486683 100644 --- a/python3.11.spec +++ b/python3.11.spec @@ -356,6 +356,25 @@ Patch415: 00415-cve-2023-27043-gh-102988-reject-malformed-addresses-in-email-par # 255.255.255.255/32 ("Limited broadcast"). Patch431: 00431-gh-113171-gh-65056-fix-private-non-global-ip-address-ranges-gh-113179-gh-113186-gh-118177-gh-118472.patch +# 00435 # d33a3c90daa3d5d2d7e67f6e9264e5438d9608a0 +# gh-121650: Encode newlines in headers, and verify headers are sound (GH-122233) +# +# Per RFC 2047: +# +# > [...] these encoding schemes allow the +# > encoding of arbitrary octet values, mail readers that implement this +# > decoding should also ensure that display of the decoded data on the +# > recipient's terminal will not cause unwanted side-effects +# +# It seems that the "quoted-word" scheme is a valid way to include +# a newline character in a header value, just like we already allow +# undecodable bytes or control characters. +# They do need to be properly quoted when serialized to text, though. +# +# This should fail for custom fold() implementations that aren't careful +# about newlines. +Patch435: 00435-gh-121650-encode-newlines-in-headers-and-verify-headers-are-sound-gh-122233.patch + # (New patches go here ^^^) # # When adding new patches to "python" and "python3" in Fedora, EL, etc., @@ -1668,6 +1687,7 @@ CheckPython optimized %changelog * Thu Aug 15 2024 Charalampos Stratakis - 3.11.9-5 - Security fix for CVE-2024-4032 (rhbz#2293391) +- Security fix for CVE-2024-6923 (rhbz#2303158) * Tue Jul 23 2024 Lumír Balhar - 3.11.9-4 - Require systemtap-sdt-devel for sys/sdt.h From 73a97226f5d7d54543ff8d461d1b0fdd2d9be21c Mon Sep 17 00:00:00 2001 From: Charalampos Stratakis Date: Fri, 23 Aug 2024 15:08:45 +0200 Subject: [PATCH 082/118] Security fix for CVE-2024-8088 Fixes: rhbz#2307460 --- ...22905-sanitize-names-in-zipfile-path.patch | 128 ++++++++++++++++++ python3.11.spec | 10 +- 2 files changed, 137 insertions(+), 1 deletion(-) create mode 100644 00436-cve-2024-8088-gh-122905-sanitize-names-in-zipfile-path.patch diff --git a/00436-cve-2024-8088-gh-122905-sanitize-names-in-zipfile-path.patch b/00436-cve-2024-8088-gh-122905-sanitize-names-in-zipfile-path.patch new file mode 100644 index 0000000..098c8af --- /dev/null +++ b/00436-cve-2024-8088-gh-122905-sanitize-names-in-zipfile-path.patch @@ -0,0 +1,128 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: "Jason R. Coombs" +Date: Mon, 19 Aug 2024 19:28:20 -0400 +Subject: [PATCH] 00436: [CVE-2024-8088] gh-122905: Sanitize names in + zipfile.Path. + +Co-authored-by: Jason R. Coombs +--- + Lib/test/test_zipfile.py | 17 ++++++ + Lib/zipfile.py | 61 ++++++++++++++++++- + ...-08-11-14-08-04.gh-issue-122905.7tDsxA.rst | 1 + + 3 files changed, 78 insertions(+), 1 deletion(-) + create mode 100644 Misc/NEWS.d/next/Library/2024-08-11-14-08-04.gh-issue-122905.7tDsxA.rst + +diff --git a/Lib/test/test_zipfile.py b/Lib/test/test_zipfile.py +index 4de6f379a4..8bdc7a1b7d 100644 +--- a/Lib/test/test_zipfile.py ++++ b/Lib/test/test_zipfile.py +@@ -3651,6 +3651,23 @@ def test_extract_orig_with_implied_dirs(self, alpharep): + zipfile.Path(zf) + zf.extractall(source_path.parent) + ++ def test_malformed_paths(self): ++ """ ++ Path should handle malformed paths. ++ """ ++ data = io.BytesIO() ++ zf = zipfile.ZipFile(data, "w") ++ zf.writestr("/one-slash.txt", b"content") ++ zf.writestr("//two-slash.txt", b"content") ++ zf.writestr("../parent.txt", b"content") ++ zf.filename = '' ++ root = zipfile.Path(zf) ++ assert list(map(str, root.iterdir())) == [ ++ 'one-slash.txt', ++ 'two-slash.txt', ++ 'parent.txt', ++ ] ++ + + class EncodedMetadataTests(unittest.TestCase): + file_names = ['\u4e00', '\u4e8c', '\u4e09'] # Han 'one', 'two', 'three' +diff --git a/Lib/zipfile.py b/Lib/zipfile.py +index 86829abce4..b7bf9ef7e3 100644 +--- a/Lib/zipfile.py ++++ b/Lib/zipfile.py +@@ -9,6 +9,7 @@ + import itertools + import os + import posixpath ++import re + import shutil + import stat + import struct +@@ -2243,7 +2244,65 @@ def _difference(minuend, subtrahend): + return itertools.filterfalse(set(subtrahend).__contains__, minuend) + + +-class CompleteDirs(ZipFile): ++class SanitizedNames: ++ """ ++ ZipFile mix-in to ensure names are sanitized. ++ """ ++ ++ def namelist(self): ++ return list(map(self._sanitize, super().namelist())) ++ ++ @staticmethod ++ def _sanitize(name): ++ r""" ++ Ensure a relative path with posix separators and no dot names. ++ Modeled after ++ https://github.com/python/cpython/blob/bcc1be39cb1d04ad9fc0bd1b9193d3972835a57c/Lib/zipfile/__init__.py#L1799-L1813 ++ but provides consistent cross-platform behavior. ++ >>> san = SanitizedNames._sanitize ++ >>> san('/foo/bar') ++ 'foo/bar' ++ >>> san('//foo.txt') ++ 'foo.txt' ++ >>> san('foo/.././bar.txt') ++ 'foo/bar.txt' ++ >>> san('foo../.bar.txt') ++ 'foo../.bar.txt' ++ >>> san('\\foo\\bar.txt') ++ 'foo/bar.txt' ++ >>> san('D:\\foo.txt') ++ 'D/foo.txt' ++ >>> san('\\\\server\\share\\file.txt') ++ 'server/share/file.txt' ++ >>> san('\\\\?\\GLOBALROOT\\Volume3') ++ '?/GLOBALROOT/Volume3' ++ >>> san('\\\\.\\PhysicalDrive1\\root') ++ 'PhysicalDrive1/root' ++ Retain any trailing slash. ++ >>> san('abc/') ++ 'abc/' ++ Raises a ValueError if the result is empty. ++ >>> san('../..') ++ Traceback (most recent call last): ++ ... ++ ValueError: Empty filename ++ """ ++ ++ def allowed(part): ++ return part and part not in {'..', '.'} ++ ++ # Remove the drive letter. ++ # Don't use ntpath.splitdrive, because that also strips UNC paths ++ bare = re.sub('^([A-Z]):', r'\1', name, flags=re.IGNORECASE) ++ clean = bare.replace('\\', '/') ++ parts = clean.split('/') ++ joined = '/'.join(filter(allowed, parts)) ++ if not joined: ++ raise ValueError("Empty filename") ++ return joined + '/' * name.endswith('/') ++ ++ ++class CompleteDirs(SanitizedNames, ZipFile): + """ + A ZipFile subclass that ensures that implied directories + are always included in the namelist. +diff --git a/Misc/NEWS.d/next/Library/2024-08-11-14-08-04.gh-issue-122905.7tDsxA.rst b/Misc/NEWS.d/next/Library/2024-08-11-14-08-04.gh-issue-122905.7tDsxA.rst +new file mode 100644 +index 0000000000..1be44c906c +--- /dev/null ++++ b/Misc/NEWS.d/next/Library/2024-08-11-14-08-04.gh-issue-122905.7tDsxA.rst +@@ -0,0 +1 @@ ++:class:`zipfile.Path` objects now sanitize names from the zipfile. diff --git a/python3.11.spec b/python3.11.spec index 9486683..4423724 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 @@ -375,6 +375,10 @@ Patch431: 00431-gh-113171-gh-65056-fix-private-non-global-ip-address-ranges-gh-1 # about newlines. Patch435: 00435-gh-121650-encode-newlines-in-headers-and-verify-headers-are-sound-gh-122233.patch +# 00436 # 1acd6db660ad1124ab7ae449a841608dd9d9062d +# [CVE-2024-8088] gh-122905: Sanitize names in zipfile.Path. +Patch436: 00436-cve-2024-8088-gh-122905-sanitize-names-in-zipfile-path.patch + # (New patches go here ^^^) # # When adding new patches to "python" and "python3" in Fedora, EL, etc., @@ -1685,6 +1689,10 @@ CheckPython optimized # ====================================================== %changelog +* Fri Aug 23 2024 Charalampos Stratakis - 3.11.9-6 +- Security fix for CVE-2024-8088 +- Fixes: rhbz#2307460 + * Thu Aug 15 2024 Charalampos Stratakis - 3.11.9-5 - Security fix for CVE-2024-4032 (rhbz#2293391) - Security fix for CVE-2024-6923 (rhbz#2303158) From 58d3aefea48442409089c784af8d383a838d31e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Tue, 27 Aug 2024 13:32:12 +0000 Subject: [PATCH 083/118] Skip test_sendfile_close_peer_in_the_middle_of_receiving on ppc64le Reported upstream https://github.com/python/cpython/issues/123384 Which was a duplicate of https://github.com/python/cpython/issues/120226 The test is fixed on the main branch, but skipping is easier than backporting. The failure occurs with Kernel 6.10.x even when Python is built with an older Kernel. By skipping the tests, we can ship a CVE fix. --- python3.11.spec | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/python3.11.spec b/python3.11.spec index 4423724..1187e7f 100644 --- a/python3.11.spec +++ b/python3.11.spec @@ -1160,6 +1160,8 @@ CheckPython() { # test_check_probes is failing since it was introduced in 3.12.0rc1, # the test is skipped until it is fixed in upstream. # see: https://github.com/python/cpython/issues/104280#issuecomment-1669249980 + # test_sendfile_close_peer_in_the_middle_of_receiving: + # https://github.com/python/cpython/issues/120226 LD_LIBRARY_PATH=$ConfDir $ConfDir/python -m test.regrtest \ -wW --slowest -j0 --timeout=1800 \ @@ -1171,6 +1173,9 @@ CheckPython() { %ifarch %{mips64} -x test_ctypes \ %endif + %ifarch ppc64le + -i test_sendfile_close_peer_in_the_middle_of_receiving \ + %endif echo FINISHED: CHECKING OF PYTHON FOR CONFIGURATION: $ConfName From 6116f5c4e8fc6ef3ed60a0fd70012508adda5724 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Hrn=C4=8Diar?= Date: Mon, 9 Sep 2024 10:22:00 +0200 Subject: [PATCH 084/118] Update to 3.11.10 --- ...-addresses-in-email-parseaddr-111116.patch | 500 ------------------ ...113179-gh-113186-gh-118177-gh-118472.patch | 366 ------------- ...d-verify-headers-are-sound-gh-122233.patch | 365 ------------- ...22905-sanitize-names-in-zipfile-path.patch | 128 ----- python3.11.spec | 67 +-- sources | 4 +- 6 files changed, 7 insertions(+), 1423 deletions(-) delete mode 100644 00415-cve-2023-27043-gh-102988-reject-malformed-addresses-in-email-parseaddr-111116.patch delete mode 100644 00431-gh-113171-gh-65056-fix-private-non-global-ip-address-ranges-gh-113179-gh-113186-gh-118177-gh-118472.patch delete mode 100644 00435-gh-121650-encode-newlines-in-headers-and-verify-headers-are-sound-gh-122233.patch delete mode 100644 00436-cve-2024-8088-gh-122905-sanitize-names-in-zipfile-path.patch diff --git a/00415-cve-2023-27043-gh-102988-reject-malformed-addresses-in-email-parseaddr-111116.patch b/00415-cve-2023-27043-gh-102988-reject-malformed-addresses-in-email-parseaddr-111116.patch deleted file mode 100644 index 2a5f74b..0000000 --- a/00415-cve-2023-27043-gh-102988-reject-malformed-addresses-in-email-parseaddr-111116.patch +++ /dev/null @@ -1,500 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Victor Stinner -Date: Fri, 15 Dec 2023 16:10:40 +0100 -Subject: [PATCH] 00415: [CVE-2023-27043] gh-102988: Reject malformed addresses - in email.parseaddr() (#111116) - -Detect email address parsing errors and return empty tuple to -indicate the parsing error (old API). Add an optional 'strict' -parameter to getaddresses() and parseaddr() functions. Patch by -Thomas Dwyer. - -Co-Authored-By: Thomas Dwyer ---- - Doc/library/email.utils.rst | 19 +- - Lib/email/utils.py | 151 ++++++++++++- - Lib/test/test_email/test_email.py | 204 +++++++++++++++++- - ...-10-20-15-28-08.gh-issue-102988.dStNO7.rst | 8 + - 4 files changed, 361 insertions(+), 21 deletions(-) - create mode 100644 Misc/NEWS.d/next/Library/2023-10-20-15-28-08.gh-issue-102988.dStNO7.rst - -diff --git a/Doc/library/email.utils.rst b/Doc/library/email.utils.rst -index 0e266b6a45..6723dc4f13 100644 ---- a/Doc/library/email.utils.rst -+++ b/Doc/library/email.utils.rst -@@ -60,13 +60,18 @@ of the new API. - begins with angle brackets, they are stripped off. - - --.. function:: parseaddr(address) -+.. function:: parseaddr(address, *, strict=True) - - Parse address -- which should be the value of some address-containing field such - as :mailheader:`To` or :mailheader:`Cc` -- into its constituent *realname* and - *email address* parts. Returns a tuple of that information, unless the parse - fails, in which case a 2-tuple of ``('', '')`` is returned. - -+ If *strict* is true, use a strict parser which rejects malformed inputs. -+ -+ .. versionchanged:: 3.13 -+ Add *strict* optional parameter and reject malformed inputs by default. -+ - - .. function:: formataddr(pair, charset='utf-8') - -@@ -84,12 +89,15 @@ of the new API. - Added the *charset* option. - - --.. function:: getaddresses(fieldvalues) -+.. function:: getaddresses(fieldvalues, *, strict=True) - - This method returns a list of 2-tuples of the form returned by ``parseaddr()``. - *fieldvalues* is a sequence of header field values as might be returned by -- :meth:`Message.get_all `. Here's a simple -- example that gets all the recipients of a message:: -+ :meth:`Message.get_all `. -+ -+ If *strict* is true, use a strict parser which rejects malformed inputs. -+ -+ Here's a simple example that gets all the recipients of a message:: - - from email.utils import getaddresses - -@@ -99,6 +107,9 @@ of the new API. - resent_ccs = msg.get_all('resent-cc', []) - all_recipients = getaddresses(tos + ccs + resent_tos + resent_ccs) - -+ .. versionchanged:: 3.13 -+ Add *strict* optional parameter and reject malformed inputs by default. -+ - - .. function:: parsedate(date) - -diff --git a/Lib/email/utils.py b/Lib/email/utils.py -index 8993858ab4..94ead0e91f 100644 ---- a/Lib/email/utils.py -+++ b/Lib/email/utils.py -@@ -48,6 +48,7 @@ - specialsre = re.compile(r'[][\\()<>@,:;".]') - escapesre = re.compile(r'[\\"]') - -+ - def _has_surrogates(s): - """Return True if s may contain surrogate-escaped binary data.""" - # This check is based on the fact that unless there are surrogates, utf8 -@@ -106,12 +107,127 @@ def formataddr(pair, charset='utf-8'): - return address - - -+def _iter_escaped_chars(addr): -+ pos = 0 -+ escape = False -+ for pos, ch in enumerate(addr): -+ if escape: -+ yield (pos, '\\' + ch) -+ escape = False -+ elif ch == '\\': -+ escape = True -+ else: -+ yield (pos, ch) -+ if escape: -+ yield (pos, '\\') - --def getaddresses(fieldvalues): -- """Return a list of (REALNAME, EMAIL) for each fieldvalue.""" -- all = COMMASPACE.join(str(v) for v in fieldvalues) -- a = _AddressList(all) -- return a.addresslist -+ -+def _strip_quoted_realnames(addr): -+ """Strip real names between quotes.""" -+ if '"' not in addr: -+ # Fast path -+ return addr -+ -+ start = 0 -+ open_pos = None -+ result = [] -+ for pos, ch in _iter_escaped_chars(addr): -+ if ch == '"': -+ if open_pos is None: -+ open_pos = pos -+ else: -+ if start != open_pos: -+ result.append(addr[start:open_pos]) -+ start = pos + 1 -+ open_pos = None -+ -+ if start < len(addr): -+ result.append(addr[start:]) -+ -+ return ''.join(result) -+ -+ -+supports_strict_parsing = True -+ -+def getaddresses(fieldvalues, *, strict=True): -+ """Return a list of (REALNAME, EMAIL) or ('','') for each fieldvalue. -+ -+ When parsing fails for a fieldvalue, a 2-tuple of ('', '') is returned in -+ its place. -+ -+ If strict is true, use a strict parser which rejects malformed inputs. -+ """ -+ -+ # If strict is true, if the resulting list of parsed addresses is greater -+ # than the number of fieldvalues in the input list, a parsing error has -+ # occurred and consequently a list containing a single empty 2-tuple [('', -+ # '')] is returned in its place. This is done to avoid invalid output. -+ # -+ # Malformed input: getaddresses(['alice@example.com ']) -+ # Invalid output: [('', 'alice@example.com'), ('', 'bob@example.com')] -+ # Safe output: [('', '')] -+ -+ if not strict: -+ all = COMMASPACE.join(str(v) for v in fieldvalues) -+ a = _AddressList(all) -+ return a.addresslist -+ -+ fieldvalues = [str(v) for v in fieldvalues] -+ fieldvalues = _pre_parse_validation(fieldvalues) -+ addr = COMMASPACE.join(fieldvalues) -+ a = _AddressList(addr) -+ result = _post_parse_validation(a.addresslist) -+ -+ # Treat output as invalid if the number of addresses is not equal to the -+ # expected number of addresses. -+ n = 0 -+ for v in fieldvalues: -+ # When a comma is used in the Real Name part it is not a deliminator. -+ # So strip those out before counting the commas. -+ v = _strip_quoted_realnames(v) -+ # Expected number of addresses: 1 + number of commas -+ n += 1 + v.count(',') -+ if len(result) != n: -+ return [('', '')] -+ -+ return result -+ -+ -+def _check_parenthesis(addr): -+ # Ignore parenthesis in quoted real names. -+ addr = _strip_quoted_realnames(addr) -+ -+ opens = 0 -+ for pos, ch in _iter_escaped_chars(addr): -+ if ch == '(': -+ opens += 1 -+ elif ch == ')': -+ opens -= 1 -+ if opens < 0: -+ return False -+ return (opens == 0) -+ -+ -+def _pre_parse_validation(email_header_fields): -+ accepted_values = [] -+ for v in email_header_fields: -+ if not _check_parenthesis(v): -+ v = "('', '')" -+ accepted_values.append(v) -+ -+ return accepted_values -+ -+ -+def _post_parse_validation(parsed_email_header_tuples): -+ accepted_values = [] -+ # The parser would have parsed a correctly formatted domain-literal -+ # The existence of an [ after parsing indicates a parsing failure -+ for v in parsed_email_header_tuples: -+ if '[' in v[1]: -+ v = ('', '') -+ accepted_values.append(v) -+ -+ return accepted_values - - - def _format_timetuple_and_zone(timetuple, zone): -@@ -205,16 +321,33 @@ def parsedate_to_datetime(data): - tzinfo=datetime.timezone(datetime.timedelta(seconds=tz))) - - --def parseaddr(addr): -+def parseaddr(addr, *, strict=True): - """ - Parse addr into its constituent realname and email address parts. - - Return a tuple of realname and email address, unless the parse fails, in - which case return a 2-tuple of ('', ''). -+ -+ If strict is True, use a strict parser which rejects malformed inputs. - """ -- addrs = _AddressList(addr).addresslist -- if not addrs: -- return '', '' -+ if not strict: -+ addrs = _AddressList(addr).addresslist -+ if not addrs: -+ return ('', '') -+ return addrs[0] -+ -+ if isinstance(addr, list): -+ addr = addr[0] -+ -+ if not isinstance(addr, str): -+ return ('', '') -+ -+ addr = _pre_parse_validation([addr])[0] -+ addrs = _post_parse_validation(_AddressList(addr).addresslist) -+ -+ if not addrs or len(addrs) > 1: -+ return ('', '') -+ - return addrs[0] - - -diff --git a/Lib/test/test_email/test_email.py b/Lib/test/test_email/test_email.py -index 785696e5c5..ad60ed3a75 100644 ---- a/Lib/test/test_email/test_email.py -+++ b/Lib/test/test_email/test_email.py -@@ -17,6 +17,7 @@ - - import email - import email.policy -+import email.utils - - from email.charset import Charset - from email.generator import Generator, DecodedGenerator, BytesGenerator -@@ -3336,15 +3337,154 @@ def test_getaddresses(self): - [('Al Person', 'aperson@dom.ain'), - ('Bud Person', 'bperson@dom.ain')]) - -+ def test_getaddresses_comma_in_name(self): -+ """GH-106669 regression test.""" -+ self.assertEqual( -+ utils.getaddresses( -+ [ -+ '"Bud, Person" ', -+ 'aperson@dom.ain (Al Person)', -+ '"Mariusz Felisiak" ', -+ ] -+ ), -+ [ -+ ('Bud, Person', 'bperson@dom.ain'), -+ ('Al Person', 'aperson@dom.ain'), -+ ('Mariusz Felisiak', 'to@example.com'), -+ ], -+ ) -+ -+ def test_parsing_errors(self): -+ """Test for parsing errors from CVE-2023-27043 and CVE-2019-16056""" -+ alice = 'alice@example.org' -+ bob = 'bob@example.com' -+ empty = ('', '') -+ -+ # Test utils.getaddresses() and utils.parseaddr() on malformed email -+ # addresses: default behavior (strict=True) rejects malformed address, -+ # and strict=False which tolerates malformed address. -+ for invalid_separator, expected_non_strict in ( -+ ('(', [(f'<{bob}>', alice)]), -+ (')', [('', alice), empty, ('', bob)]), -+ ('<', [('', alice), empty, ('', bob), empty]), -+ ('>', [('', alice), empty, ('', bob)]), -+ ('[', [('', f'{alice}[<{bob}>]')]), -+ (']', [('', alice), empty, ('', bob)]), -+ ('@', [empty, empty, ('', bob)]), -+ (';', [('', alice), empty, ('', bob)]), -+ (':', [('', alice), ('', bob)]), -+ ('.', [('', alice + '.'), ('', bob)]), -+ ('"', [('', alice), ('', f'<{bob}>')]), -+ ): -+ address = f'{alice}{invalid_separator}<{bob}>' -+ with self.subTest(address=address): -+ self.assertEqual(utils.getaddresses([address]), -+ [empty]) -+ self.assertEqual(utils.getaddresses([address], strict=False), -+ expected_non_strict) -+ -+ self.assertEqual(utils.parseaddr([address]), -+ empty) -+ self.assertEqual(utils.parseaddr([address], strict=False), -+ ('', address)) -+ -+ # Comma (',') is treated differently depending on strict parameter. -+ # Comma without quotes. -+ address = f'{alice},<{bob}>' -+ self.assertEqual(utils.getaddresses([address]), -+ [('', alice), ('', bob)]) -+ self.assertEqual(utils.getaddresses([address], strict=False), -+ [('', alice), ('', bob)]) -+ self.assertEqual(utils.parseaddr([address]), -+ empty) -+ self.assertEqual(utils.parseaddr([address], strict=False), -+ ('', address)) -+ -+ # Real name between quotes containing comma. -+ address = '"Alice, alice@example.org" ' -+ expected_strict = ('Alice, alice@example.org', 'bob@example.com') -+ self.assertEqual(utils.getaddresses([address]), [expected_strict]) -+ self.assertEqual(utils.getaddresses([address], strict=False), [expected_strict]) -+ self.assertEqual(utils.parseaddr([address]), expected_strict) -+ self.assertEqual(utils.parseaddr([address], strict=False), -+ ('', address)) -+ -+ # Valid parenthesis in comments. -+ address = 'alice@example.org (Alice)' -+ expected_strict = ('Alice', 'alice@example.org') -+ self.assertEqual(utils.getaddresses([address]), [expected_strict]) -+ self.assertEqual(utils.getaddresses([address], strict=False), [expected_strict]) -+ self.assertEqual(utils.parseaddr([address]), expected_strict) -+ self.assertEqual(utils.parseaddr([address], strict=False), -+ ('', address)) -+ -+ # Invalid parenthesis in comments. -+ address = 'alice@example.org )Alice(' -+ self.assertEqual(utils.getaddresses([address]), [empty]) -+ self.assertEqual(utils.getaddresses([address], strict=False), -+ [('', 'alice@example.org'), ('', ''), ('', 'Alice')]) -+ self.assertEqual(utils.parseaddr([address]), empty) -+ self.assertEqual(utils.parseaddr([address], strict=False), -+ ('', address)) -+ -+ # Two addresses with quotes separated by comma. -+ address = '"Jane Doe" , "John Doe" ' -+ self.assertEqual(utils.getaddresses([address]), -+ [('Jane Doe', 'jane@example.net'), -+ ('John Doe', 'john@example.net')]) -+ self.assertEqual(utils.getaddresses([address], strict=False), -+ [('Jane Doe', 'jane@example.net'), -+ ('John Doe', 'john@example.net')]) -+ self.assertEqual(utils.parseaddr([address]), empty) -+ self.assertEqual(utils.parseaddr([address], strict=False), -+ ('', address)) -+ -+ # Test email.utils.supports_strict_parsing attribute -+ self.assertEqual(email.utils.supports_strict_parsing, True) -+ - def test_getaddresses_nasty(self): -- eq = self.assertEqual -- eq(utils.getaddresses(['foo: ;']), [('', '')]) -- eq(utils.getaddresses( -- ['[]*-- =~$']), -- [('', ''), ('', ''), ('', '*--')]) -- eq(utils.getaddresses( -- ['foo: ;', '"Jason R. Mastaler" ']), -- [('', ''), ('Jason R. Mastaler', 'jason@dom.ain')]) -+ for addresses, expected in ( -+ (['"Sürname, Firstname" '], -+ [('Sürname, Firstname', 'to@example.com')]), -+ -+ (['foo: ;'], -+ [('', '')]), -+ -+ (['foo: ;', '"Jason R. Mastaler" '], -+ [('', ''), ('Jason R. Mastaler', 'jason@dom.ain')]), -+ -+ ([r'Pete(A nice \) chap) '], -+ [('Pete (A nice ) chap his account his host)', 'pete@silly.test')]), -+ -+ (['(Empty list)(start)Undisclosed recipients :(nobody(I know))'], -+ [('', '')]), -+ -+ (['Mary <@machine.tld:mary@example.net>, , jdoe@test . example'], -+ [('Mary', 'mary@example.net'), ('', ''), ('', 'jdoe@test.example')]), -+ -+ (['John Doe '], -+ [('John Doe (comment)', 'jdoe@machine.example')]), -+ -+ (['"Mary Smith: Personal Account" '], -+ [('Mary Smith: Personal Account', 'smith@home.example')]), -+ -+ (['Undisclosed recipients:;'], -+ [('', '')]), -+ -+ ([r', "Giant; \"Big\" Box" '], -+ [('', 'boss@nil.test'), ('Giant; "Big" Box', 'bob@example.net')]), -+ ): -+ with self.subTest(addresses=addresses): -+ self.assertEqual(utils.getaddresses(addresses), -+ expected) -+ self.assertEqual(utils.getaddresses(addresses, strict=False), -+ expected) -+ -+ addresses = ['[]*-- =~$'] -+ self.assertEqual(utils.getaddresses(addresses), -+ [('', '')]) -+ self.assertEqual(utils.getaddresses(addresses, strict=False), -+ [('', ''), ('', ''), ('', '*--')]) - - def test_getaddresses_embedded_comment(self): - """Test proper handling of a nested comment""" -@@ -3535,6 +3675,54 @@ def test_mime_classes_policy_argument(self): - m = cls(*constructor, policy=email.policy.default) - self.assertIs(m.policy, email.policy.default) - -+ def test_iter_escaped_chars(self): -+ self.assertEqual(list(utils._iter_escaped_chars(r'a\\b\"c\\"d')), -+ [(0, 'a'), -+ (2, '\\\\'), -+ (3, 'b'), -+ (5, '\\"'), -+ (6, 'c'), -+ (8, '\\\\'), -+ (9, '"'), -+ (10, 'd')]) -+ self.assertEqual(list(utils._iter_escaped_chars('a\\')), -+ [(0, 'a'), (1, '\\')]) -+ -+ def test_strip_quoted_realnames(self): -+ def check(addr, expected): -+ self.assertEqual(utils._strip_quoted_realnames(addr), expected) -+ -+ check('"Jane Doe" , "John Doe" ', -+ ' , ') -+ check(r'"Jane \"Doe\"." ', -+ ' ') -+ -+ # special cases -+ check(r'before"name"after', 'beforeafter') -+ check(r'before"name"', 'before') -+ check(r'b"name"', 'b') # single char -+ check(r'"name"after', 'after') -+ check(r'"name"a', 'a') # single char -+ check(r'"name"', '') -+ -+ # no change -+ for addr in ( -+ 'Jane Doe , John Doe ', -+ 'lone " quote', -+ ): -+ self.assertEqual(utils._strip_quoted_realnames(addr), addr) -+ -+ -+ def test_check_parenthesis(self): -+ addr = 'alice@example.net' -+ self.assertTrue(utils._check_parenthesis(f'{addr} (Alice)')) -+ self.assertFalse(utils._check_parenthesis(f'{addr} )Alice(')) -+ self.assertFalse(utils._check_parenthesis(f'{addr} (Alice))')) -+ self.assertFalse(utils._check_parenthesis(f'{addr} ((Alice)')) -+ -+ # Ignore real name between quotes -+ self.assertTrue(utils._check_parenthesis(f'")Alice((" {addr}')) -+ - - # Test the iterator/generators - class TestIterators(TestEmailBase): -diff --git a/Misc/NEWS.d/next/Library/2023-10-20-15-28-08.gh-issue-102988.dStNO7.rst b/Misc/NEWS.d/next/Library/2023-10-20-15-28-08.gh-issue-102988.dStNO7.rst -new file mode 100644 -index 0000000000..3d0e9e4078 ---- /dev/null -+++ b/Misc/NEWS.d/next/Library/2023-10-20-15-28-08.gh-issue-102988.dStNO7.rst -@@ -0,0 +1,8 @@ -+:func:`email.utils.getaddresses` and :func:`email.utils.parseaddr` now -+return ``('', '')`` 2-tuples in more situations where invalid email -+addresses are encountered instead of potentially inaccurate values. Add -+optional *strict* parameter to these two functions: use ``strict=False`` to -+get the old behavior, accept malformed inputs. -+``getattr(email.utils, 'supports_strict_parsing', False)`` can be use to check -+if the *strict* paramater is available. Patch by Thomas Dwyer and Victor -+Stinner to improve the CVE-2023-27043 fix. diff --git a/00431-gh-113171-gh-65056-fix-private-non-global-ip-address-ranges-gh-113179-gh-113186-gh-118177-gh-118472.patch b/00431-gh-113171-gh-65056-fix-private-non-global-ip-address-ranges-gh-113179-gh-113186-gh-118177-gh-118472.patch deleted file mode 100644 index d2a19ab..0000000 --- a/00431-gh-113171-gh-65056-fix-private-non-global-ip-address-ranges-gh-113179-gh-113186-gh-118177-gh-118472.patch +++ /dev/null @@ -1,366 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Petr Viktorin -Date: Thu, 25 Apr 2024 14:45:48 +0200 -Subject: [PATCH] 00431: gh-113171: gh-65056: Fix "private" (non-global) IP - address ranges (GH-113179) (GH-113186) (GH-118177) (GH-118472) - -The _private_networks variables, used by various is_private -implementations, were missing some ranges and at the same time had -overly strict ranges (where there are more specific ranges considered -globally reachable by the IANA registries). - -This patch updates the ranges with what was missing or otherwise -incorrect. - -100.64.0.0/10 is left alone, for now, as it's been made special in [1]. - -The _address_exclude_many() call returns 8 networks for IPv4, 121 -networks for IPv6. - -[1] https://github.com/python/cpython/issues/61602 - -In 3.10 and below, is_private checks whether the network and broadcast -address are both private. -In later versions (where the test wss backported from), it checks -whether they both are in the same private network. - -For 0.0.0.0/0, both 0.0.0.0 and 255.225.255.255 are private, -but one is in 0.0.0.0/8 ("This network") and the other in -255.255.255.255/32 ("Limited broadcast"). ---- - Doc/library/ipaddress.rst | 43 +++++++- - Doc/whatsnew/3.11.rst | 9 ++ - Lib/ipaddress.py | 99 +++++++++++++++---- - Lib/test/test_ipaddress.py | 21 +++- - ...-03-14-01-38-44.gh-issue-113171.VFnObz.rst | 9 ++ - 5 files changed, 157 insertions(+), 24 deletions(-) - create mode 100644 Misc/NEWS.d/next/Library/2024-03-14-01-38-44.gh-issue-113171.VFnObz.rst - -diff --git a/Doc/library/ipaddress.rst b/Doc/library/ipaddress.rst -index 03dc956cd1..f57fa15aa5 100644 ---- a/Doc/library/ipaddress.rst -+++ b/Doc/library/ipaddress.rst -@@ -178,18 +178,53 @@ write code that handles both IP versions correctly. Address objects are - - .. attribute:: is_private - -- ``True`` if the address is allocated for private networks. See -+ ``True`` if the address is defined as not globally reachable by - iana-ipv4-special-registry_ (for IPv4) or iana-ipv6-special-registry_ -- (for IPv6). -+ (for IPv6) with the following exceptions: -+ -+ * ``is_private`` is ``False`` for the shared address space (``100.64.0.0/10``) -+ * For IPv4-mapped IPv6-addresses the ``is_private`` value is determined by the -+ semantics of the underlying IPv4 addresses and the following condition holds -+ (see :attr:`IPv6Address.ipv4_mapped`):: -+ -+ address.is_private == address.ipv4_mapped.is_private -+ -+ ``is_private`` has value opposite to :attr:`is_global`, except for the shared address space -+ (``100.64.0.0/10`` range) where they are both ``False``. -+ -+ .. versionchanged:: 3.11.10 -+ -+ Fixed some false positives and false negatives. -+ -+ * ``192.0.0.0/24`` is considered private with the exception of ``192.0.0.9/32`` and -+ ``192.0.0.10/32`` (previously: only the ``192.0.0.0/29`` sub-range was considered private). -+ * ``64:ff9b:1::/48`` is considered private. -+ * ``2002::/16`` is considered private. -+ * There are exceptions within ``2001::/23`` (otherwise considered private): ``2001:1::1/128``, -+ ``2001:1::2/128``, ``2001:3::/32``, ``2001:4:112::/48``, ``2001:20::/28``, ``2001:30::/28``. -+ The exceptions are not considered private. - - .. attribute:: is_global - -- ``True`` if the address is allocated for public networks. See -+ ``True`` if the address is defined as globally reachable by - iana-ipv4-special-registry_ (for IPv4) or iana-ipv6-special-registry_ -- (for IPv6). -+ (for IPv6) with the following exception: -+ -+ For IPv4-mapped IPv6-addresses the ``is_private`` value is determined by the -+ semantics of the underlying IPv4 addresses and the following condition holds -+ (see :attr:`IPv6Address.ipv4_mapped`):: -+ -+ address.is_global == address.ipv4_mapped.is_global -+ -+ ``is_global`` has value opposite to :attr:`is_private`, except for the shared address space -+ (``100.64.0.0/10`` range) where they are both ``False``. - - .. versionadded:: 3.4 - -+ .. versionchanged:: 3.11.10 -+ -+ Fixed some false positives and false negatives, see :attr:`is_private` for details. -+ - .. attribute:: is_unspecified - - ``True`` if the address is unspecified. See :RFC:`5735` (for IPv4) -diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst -index f670fa1f09..42b61c75c7 100644 ---- a/Doc/whatsnew/3.11.rst -+++ b/Doc/whatsnew/3.11.rst -@@ -2727,3 +2727,12 @@ OpenSSL - * Windows builds and macOS installers from python.org now use OpenSSL 3.0. - - .. _libb2: https://www.blake2.net/ -+ -+Notable changes in 3.11.10 -+========================== -+ -+ipaddress -+--------- -+ -+* Fixed ``is_global`` and ``is_private`` behavior in ``IPv4Address``, -+ ``IPv6Address``, ``IPv4Network`` and ``IPv6Network``. -diff --git a/Lib/ipaddress.py b/Lib/ipaddress.py -index 16ba16cd7d..567beb37e0 100644 ---- a/Lib/ipaddress.py -+++ b/Lib/ipaddress.py -@@ -1086,7 +1086,11 @@ def is_private(self): - """ - return any(self.network_address in priv_network and - self.broadcast_address in priv_network -- for priv_network in self._constants._private_networks) -+ for priv_network in self._constants._private_networks) and all( -+ self.network_address not in network and -+ self.broadcast_address not in network -+ for network in self._constants._private_networks_exceptions -+ ) - - @property - def is_global(self): -@@ -1333,18 +1337,41 @@ def is_reserved(self): - @property - @functools.lru_cache() - def is_private(self): -- """Test if this address is allocated for private networks. -+ """``True`` if the address is defined as not globally reachable by -+ iana-ipv4-special-registry_ (for IPv4) or iana-ipv6-special-registry_ -+ (for IPv6) with the following exceptions: - -- Returns: -- A boolean, True if the address is reserved per -- iana-ipv4-special-registry. -+ * ``is_private`` is ``False`` for ``100.64.0.0/10`` -+ * For IPv4-mapped IPv6-addresses the ``is_private`` value is determined by the -+ semantics of the underlying IPv4 addresses and the following condition holds -+ (see :attr:`IPv6Address.ipv4_mapped`):: - -+ address.is_private == address.ipv4_mapped.is_private -+ -+ ``is_private`` has value opposite to :attr:`is_global`, except for the ``100.64.0.0/10`` -+ IPv4 range where they are both ``False``. - """ -- return any(self in net for net in self._constants._private_networks) -+ return ( -+ any(self in net for net in self._constants._private_networks) -+ and all(self not in net for net in self._constants._private_networks_exceptions) -+ ) - - @property - @functools.lru_cache() - def is_global(self): -+ """``True`` if the address is defined as globally reachable by -+ iana-ipv4-special-registry_ (for IPv4) or iana-ipv6-special-registry_ -+ (for IPv6) with the following exception: -+ -+ For IPv4-mapped IPv6-addresses the ``is_private`` value is determined by the -+ semantics of the underlying IPv4 addresses and the following condition holds -+ (see :attr:`IPv6Address.ipv4_mapped`):: -+ -+ address.is_global == address.ipv4_mapped.is_global -+ -+ ``is_global`` has value opposite to :attr:`is_private`, except for the ``100.64.0.0/10`` -+ IPv4 range where they are both ``False``. -+ """ - return self not in self._constants._public_network and not self.is_private - - @property -@@ -1548,13 +1575,15 @@ class _IPv4Constants: - - _public_network = IPv4Network('100.64.0.0/10') - -+ # Not globally reachable address blocks listed on -+ # https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml - _private_networks = [ - IPv4Network('0.0.0.0/8'), - IPv4Network('10.0.0.0/8'), - IPv4Network('127.0.0.0/8'), - IPv4Network('169.254.0.0/16'), - IPv4Network('172.16.0.0/12'), -- IPv4Network('192.0.0.0/29'), -+ IPv4Network('192.0.0.0/24'), - IPv4Network('192.0.0.170/31'), - IPv4Network('192.0.2.0/24'), - IPv4Network('192.168.0.0/16'), -@@ -1565,6 +1594,11 @@ class _IPv4Constants: - IPv4Network('255.255.255.255/32'), - ] - -+ _private_networks_exceptions = [ -+ IPv4Network('192.0.0.9/32'), -+ IPv4Network('192.0.0.10/32'), -+ ] -+ - _reserved_network = IPv4Network('240.0.0.0/4') - - _unspecified_address = IPv4Address('0.0.0.0') -@@ -2010,27 +2044,42 @@ def is_site_local(self): - @property - @functools.lru_cache() - def is_private(self): -- """Test if this address is allocated for private networks. -+ """``True`` if the address is defined as not globally reachable by -+ iana-ipv4-special-registry_ (for IPv4) or iana-ipv6-special-registry_ -+ (for IPv6) with the following exceptions: - -- Returns: -- A boolean, True if the address is reserved per -- iana-ipv6-special-registry, or is ipv4_mapped and is -- reserved in the iana-ipv4-special-registry. -+ * ``is_private`` is ``False`` for ``100.64.0.0/10`` -+ * For IPv4-mapped IPv6-addresses the ``is_private`` value is determined by the -+ semantics of the underlying IPv4 addresses and the following condition holds -+ (see :attr:`IPv6Address.ipv4_mapped`):: - -+ address.is_private == address.ipv4_mapped.is_private -+ -+ ``is_private`` has value opposite to :attr:`is_global`, except for the ``100.64.0.0/10`` -+ IPv4 range where they are both ``False``. - """ - ipv4_mapped = self.ipv4_mapped - if ipv4_mapped is not None: - return ipv4_mapped.is_private -- return any(self in net for net in self._constants._private_networks) -+ return ( -+ any(self in net for net in self._constants._private_networks) -+ and all(self not in net for net in self._constants._private_networks_exceptions) -+ ) - - @property - def is_global(self): -- """Test if this address is allocated for public networks. -+ """``True`` if the address is defined as globally reachable by -+ iana-ipv4-special-registry_ (for IPv4) or iana-ipv6-special-registry_ -+ (for IPv6) with the following exception: - -- Returns: -- A boolean, true if the address is not reserved per -- iana-ipv6-special-registry. -+ For IPv4-mapped IPv6-addresses the ``is_private`` value is determined by the -+ semantics of the underlying IPv4 addresses and the following condition holds -+ (see :attr:`IPv6Address.ipv4_mapped`):: - -+ address.is_global == address.ipv4_mapped.is_global -+ -+ ``is_global`` has value opposite to :attr:`is_private`, except for the ``100.64.0.0/10`` -+ IPv4 range where they are both ``False``. - """ - return not self.is_private - -@@ -2271,19 +2320,31 @@ class _IPv6Constants: - - _multicast_network = IPv6Network('ff00::/8') - -+ # Not globally reachable address blocks listed on -+ # https://www.iana.org/assignments/iana-ipv6-special-registry/iana-ipv6-special-registry.xhtml - _private_networks = [ - IPv6Network('::1/128'), - IPv6Network('::/128'), - IPv6Network('::ffff:0:0/96'), -+ IPv6Network('64:ff9b:1::/48'), - IPv6Network('100::/64'), - IPv6Network('2001::/23'), -- IPv6Network('2001:2::/48'), - IPv6Network('2001:db8::/32'), -- IPv6Network('2001:10::/28'), -+ # IANA says N/A, let's consider it not globally reachable to be safe -+ IPv6Network('2002::/16'), - IPv6Network('fc00::/7'), - IPv6Network('fe80::/10'), - ] - -+ _private_networks_exceptions = [ -+ IPv6Network('2001:1::1/128'), -+ IPv6Network('2001:1::2/128'), -+ IPv6Network('2001:3::/32'), -+ IPv6Network('2001:4:112::/48'), -+ IPv6Network('2001:20::/28'), -+ IPv6Network('2001:30::/28'), -+ ] -+ - _reserved_networks = [ - IPv6Network('::/8'), IPv6Network('100::/8'), - IPv6Network('200::/7'), IPv6Network('400::/6'), -diff --git a/Lib/test/test_ipaddress.py b/Lib/test/test_ipaddress.py -index fc27628af1..16c34163a0 100644 ---- a/Lib/test/test_ipaddress.py -+++ b/Lib/test/test_ipaddress.py -@@ -2269,6 +2269,10 @@ def testReservedIpv4(self): - self.assertEqual(True, ipaddress.ip_address( - '172.31.255.255').is_private) - self.assertEqual(False, ipaddress.ip_address('172.32.0.0').is_private) -+ self.assertFalse(ipaddress.ip_address('192.0.0.0').is_global) -+ self.assertTrue(ipaddress.ip_address('192.0.0.9').is_global) -+ self.assertTrue(ipaddress.ip_address('192.0.0.10').is_global) -+ self.assertFalse(ipaddress.ip_address('192.0.0.255').is_global) - - self.assertEqual(True, - ipaddress.ip_address('169.254.100.200').is_link_local) -@@ -2294,6 +2298,7 @@ def testPrivateNetworks(self): - self.assertEqual(True, ipaddress.ip_network("169.254.0.0/16").is_private) - self.assertEqual(True, ipaddress.ip_network("172.16.0.0/12").is_private) - self.assertEqual(True, ipaddress.ip_network("192.0.0.0/29").is_private) -+ self.assertEqual(False, ipaddress.ip_network("192.0.0.9/32").is_private) - self.assertEqual(True, ipaddress.ip_network("192.0.0.170/31").is_private) - self.assertEqual(True, ipaddress.ip_network("192.0.2.0/24").is_private) - self.assertEqual(True, ipaddress.ip_network("192.168.0.0/16").is_private) -@@ -2310,8 +2315,8 @@ def testPrivateNetworks(self): - self.assertEqual(True, ipaddress.ip_network("::/128").is_private) - self.assertEqual(True, ipaddress.ip_network("::ffff:0:0/96").is_private) - self.assertEqual(True, ipaddress.ip_network("100::/64").is_private) -- self.assertEqual(True, ipaddress.ip_network("2001::/23").is_private) - self.assertEqual(True, ipaddress.ip_network("2001:2::/48").is_private) -+ self.assertEqual(False, ipaddress.ip_network("2001:3::/48").is_private) - self.assertEqual(True, ipaddress.ip_network("2001:db8::/32").is_private) - self.assertEqual(True, ipaddress.ip_network("2001:10::/28").is_private) - self.assertEqual(True, ipaddress.ip_network("fc00::/7").is_private) -@@ -2390,6 +2395,20 @@ def testReservedIpv6(self): - self.assertEqual(True, ipaddress.ip_address('0::0').is_unspecified) - self.assertEqual(False, ipaddress.ip_address('::1').is_unspecified) - -+ self.assertFalse(ipaddress.ip_address('64:ff9b:1::').is_global) -+ self.assertFalse(ipaddress.ip_address('2001::').is_global) -+ self.assertTrue(ipaddress.ip_address('2001:1::1').is_global) -+ self.assertTrue(ipaddress.ip_address('2001:1::2').is_global) -+ self.assertFalse(ipaddress.ip_address('2001:2::').is_global) -+ self.assertTrue(ipaddress.ip_address('2001:3::').is_global) -+ self.assertFalse(ipaddress.ip_address('2001:4::').is_global) -+ self.assertTrue(ipaddress.ip_address('2001:4:112::').is_global) -+ self.assertFalse(ipaddress.ip_address('2001:10::').is_global) -+ self.assertTrue(ipaddress.ip_address('2001:20::').is_global) -+ self.assertTrue(ipaddress.ip_address('2001:30::').is_global) -+ self.assertFalse(ipaddress.ip_address('2001:40::').is_global) -+ self.assertFalse(ipaddress.ip_address('2002::').is_global) -+ - # some generic IETF reserved addresses - self.assertEqual(True, ipaddress.ip_address('100::').is_reserved) - self.assertEqual(True, ipaddress.ip_network('4000::1/128').is_reserved) -diff --git a/Misc/NEWS.d/next/Library/2024-03-14-01-38-44.gh-issue-113171.VFnObz.rst b/Misc/NEWS.d/next/Library/2024-03-14-01-38-44.gh-issue-113171.VFnObz.rst -new file mode 100644 -index 0000000000..f9a72473be ---- /dev/null -+++ b/Misc/NEWS.d/next/Library/2024-03-14-01-38-44.gh-issue-113171.VFnObz.rst -@@ -0,0 +1,9 @@ -+Fixed various false positives and false negatives in -+ -+* :attr:`ipaddress.IPv4Address.is_private` (see these docs for details) -+* :attr:`ipaddress.IPv4Address.is_global` -+* :attr:`ipaddress.IPv6Address.is_private` -+* :attr:`ipaddress.IPv6Address.is_global` -+ -+Also in the corresponding :class:`ipaddress.IPv4Network` and :class:`ipaddress.IPv6Network` -+attributes. diff --git a/00435-gh-121650-encode-newlines-in-headers-and-verify-headers-are-sound-gh-122233.patch b/00435-gh-121650-encode-newlines-in-headers-and-verify-headers-are-sound-gh-122233.patch deleted file mode 100644 index 5d0fd3d..0000000 --- a/00435-gh-121650-encode-newlines-in-headers-and-verify-headers-are-sound-gh-122233.patch +++ /dev/null @@ -1,365 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Petr Viktorin -Date: Wed, 31 Jul 2024 00:19:48 +0200 -Subject: [PATCH] 00435: gh-121650: Encode newlines in headers, and verify - headers are sound (GH-122233) - -Per RFC 2047: - -> [...] these encoding schemes allow the -> encoding of arbitrary octet values, mail readers that implement this -> decoding should also ensure that display of the decoded data on the -> recipient's terminal will not cause unwanted side-effects - -It seems that the "quoted-word" scheme is a valid way to include -a newline character in a header value, just like we already allow -undecodable bytes or control characters. -They do need to be properly quoted when serialized to text, though. - -This should fail for custom fold() implementations that aren't careful -about newlines. - -(cherry picked from commit 097633981879b3c9de9a1dd120d3aa585ecc2384) - -Co-authored-by: Petr Viktorin -Co-authored-by: Bas Bloemsaat -Co-authored-by: Serhiy Storchaka ---- - Doc/library/email.errors.rst | 7 +++ - Doc/library/email.policy.rst | 18 ++++++ - Doc/whatsnew/3.11.rst | 13 ++++ - Lib/email/_header_value_parser.py | 12 +++- - Lib/email/_policybase.py | 8 +++ - Lib/email/errors.py | 4 ++ - Lib/email/generator.py | 13 +++- - Lib/test/test_email/test_generator.py | 62 +++++++++++++++++++ - Lib/test/test_email/test_policy.py | 26 ++++++++ - ...-07-27-16-10-41.gh-issue-121650.nf6oc9.rst | 5 ++ - 10 files changed, 164 insertions(+), 4 deletions(-) - create mode 100644 Misc/NEWS.d/next/Library/2024-07-27-16-10-41.gh-issue-121650.nf6oc9.rst - -diff --git a/Doc/library/email.errors.rst b/Doc/library/email.errors.rst -index 56aea6598b..27b0481a85 100644 ---- a/Doc/library/email.errors.rst -+++ b/Doc/library/email.errors.rst -@@ -58,6 +58,13 @@ The following exception classes are defined in the :mod:`email.errors` module: - :class:`~email.mime.nonmultipart.MIMENonMultipart` (e.g. - :class:`~email.mime.image.MIMEImage`). - -+ -+.. exception:: HeaderWriteError() -+ -+ Raised when an error occurs when the :mod:`~email.generator` outputs -+ headers. -+ -+ - .. exception:: MessageDefect() - - This is the base class for all defects found when parsing email messages. -diff --git a/Doc/library/email.policy.rst b/Doc/library/email.policy.rst -index bb406c5a56..3edba4028b 100644 ---- a/Doc/library/email.policy.rst -+++ b/Doc/library/email.policy.rst -@@ -228,6 +228,24 @@ added matters. To illustrate:: - - .. versionadded:: 3.6 - -+ -+ .. attribute:: verify_generated_headers -+ -+ If ``True`` (the default), the generator will raise -+ :exc:`~email.errors.HeaderWriteError` instead of writing a header -+ that is improperly folded or delimited, such that it would -+ be parsed as multiple headers or joined with adjacent data. -+ Such headers can be generated by custom header classes or bugs -+ in the ``email`` module. -+ -+ As it's a security feature, this defaults to ``True`` even in the -+ :class:`~email.policy.Compat32` policy. -+ For backwards compatible, but unsafe, behavior, it must be set to -+ ``False`` explicitly. -+ -+ .. versionadded:: 3.11.10 -+ -+ - The following :class:`Policy` method is intended to be called by code using - the email library to create policy instances with custom settings: - -diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst -index 42b61c75c7..f12c871998 100644 ---- a/Doc/whatsnew/3.11.rst -+++ b/Doc/whatsnew/3.11.rst -@@ -2728,6 +2728,7 @@ OpenSSL - - .. _libb2: https://www.blake2.net/ - -+ - Notable changes in 3.11.10 - ========================== - -@@ -2736,3 +2737,15 @@ ipaddress - - * Fixed ``is_global`` and ``is_private`` behavior in ``IPv4Address``, - ``IPv6Address``, ``IPv4Network`` and ``IPv6Network``. -+ -+email -+----- -+ -+* Headers with embedded newlines are now quoted on output. -+ -+ The :mod:`~email.generator` will now refuse to serialize (write) headers -+ that are improperly folded or delimited, such that they would be parsed as -+ multiple headers or joined with adjacent data. -+ If you need to turn this safety feature off, -+ set :attr:`~email.policy.Policy.verify_generated_headers`. -+ (Contributed by Bas Bloemsaat and Petr Viktorin in :gh:`121650`.) -diff --git a/Lib/email/_header_value_parser.py b/Lib/email/_header_value_parser.py -index 8cb8852cf0..255a953092 100644 ---- a/Lib/email/_header_value_parser.py -+++ b/Lib/email/_header_value_parser.py -@@ -92,6 +92,8 @@ - ASPECIALS = TSPECIALS | set("*'%") - ATTRIBUTE_ENDS = ASPECIALS | WSP - EXTENDED_ATTRIBUTE_ENDS = ATTRIBUTE_ENDS - set('%') -+NLSET = {'\n', '\r'} -+SPECIALSNL = SPECIALS | NLSET - - def quote_string(value): - return '"'+str(value).replace('\\', '\\\\').replace('"', r'\"')+'"' -@@ -2780,9 +2782,13 @@ def _refold_parse_tree(parse_tree, *, policy): - wrap_as_ew_blocked -= 1 - continue - tstr = str(part) -- if part.token_type == 'ptext' and set(tstr) & SPECIALS: -- # Encode if tstr contains special characters. -- want_encoding = True -+ if not want_encoding: -+ if part.token_type == 'ptext': -+ # Encode if tstr contains special characters. -+ want_encoding = not SPECIALSNL.isdisjoint(tstr) -+ else: -+ # Encode if tstr contains newlines. -+ want_encoding = not NLSET.isdisjoint(tstr) - try: - tstr.encode(encoding) - charset = encoding -diff --git a/Lib/email/_policybase.py b/Lib/email/_policybase.py -index c9cbadd2a8..d1f48211f9 100644 ---- a/Lib/email/_policybase.py -+++ b/Lib/email/_policybase.py -@@ -157,6 +157,13 @@ class Policy(_PolicyBase, metaclass=abc.ABCMeta): - message_factory -- the class to use to create new message objects. - If the value is None, the default is Message. - -+ verify_generated_headers -+ -- if true, the generator verifies that each header -+ they are properly folded, so that a parser won't -+ treat it as multiple headers, start-of-body, or -+ part of another header. -+ This is a check against custom Header & fold() -+ implementations. - """ - - raise_on_defect = False -@@ -165,6 +172,7 @@ class Policy(_PolicyBase, metaclass=abc.ABCMeta): - max_line_length = 78 - mangle_from_ = False - message_factory = None -+ verify_generated_headers = True - - def handle_defect(self, obj, defect): - """Based on policy, either raise defect or call register_defect. -diff --git a/Lib/email/errors.py b/Lib/email/errors.py -index 3ad0056554..02aa5eced6 100644 ---- a/Lib/email/errors.py -+++ b/Lib/email/errors.py -@@ -29,6 +29,10 @@ class CharsetError(MessageError): - """An illegal charset was given.""" - - -+class HeaderWriteError(MessageError): -+ """Error while writing headers.""" -+ -+ - # These are parsing defects which the parser was able to work around. - class MessageDefect(ValueError): - """Base class for a message defect.""" -diff --git a/Lib/email/generator.py b/Lib/email/generator.py -index eb597de76d..563ca17072 100644 ---- a/Lib/email/generator.py -+++ b/Lib/email/generator.py -@@ -14,12 +14,14 @@ - from copy import deepcopy - from io import StringIO, BytesIO - from email.utils import _has_surrogates -+from email.errors import HeaderWriteError - - UNDERSCORE = '_' - NL = '\n' # XXX: no longer used by the code below. - - NLCRE = re.compile(r'\r\n|\r|\n') - fcre = re.compile(r'^From ', re.MULTILINE) -+NEWLINE_WITHOUT_FWSP = re.compile(r'\r\n[^ \t]|\r[^ \n\t]|\n[^ \t]') - - - class Generator: -@@ -222,7 +224,16 @@ def _dispatch(self, msg): - - def _write_headers(self, msg): - for h, v in msg.raw_items(): -- self.write(self.policy.fold(h, v)) -+ folded = self.policy.fold(h, v) -+ if self.policy.verify_generated_headers: -+ linesep = self.policy.linesep -+ if not folded.endswith(self.policy.linesep): -+ raise HeaderWriteError( -+ f'folded header does not end with {linesep!r}: {folded!r}') -+ if NEWLINE_WITHOUT_FWSP.search(folded.removesuffix(linesep)): -+ raise HeaderWriteError( -+ f'folded header contains newline: {folded!r}') -+ self.write(folded) - # A blank line always separates headers from body - self.write(self._NL) - -diff --git a/Lib/test/test_email/test_generator.py b/Lib/test/test_email/test_generator.py -index 89e7edeb63..d29400f0ed 100644 ---- a/Lib/test/test_email/test_generator.py -+++ b/Lib/test/test_email/test_generator.py -@@ -6,6 +6,7 @@ - from email.generator import Generator, BytesGenerator - from email.headerregistry import Address - from email import policy -+import email.errors - from test.test_email import TestEmailBase, parameterize - - -@@ -216,6 +217,44 @@ def test_rfc2231_wrapping_switches_to_default_len_if_too_narrow(self): - g.flatten(msg) - self.assertEqual(s.getvalue(), self.typ(expected)) - -+ def test_keep_encoded_newlines(self): -+ msg = self.msgmaker(self.typ(textwrap.dedent("""\ -+ To: nobody -+ Subject: Bad subject=?UTF-8?Q?=0A?=Bcc: injection@example.com -+ -+ None -+ """))) -+ expected = textwrap.dedent("""\ -+ To: nobody -+ Subject: Bad subject=?UTF-8?Q?=0A?=Bcc: injection@example.com -+ -+ None -+ """) -+ s = self.ioclass() -+ g = self.genclass(s, policy=self.policy.clone(max_line_length=80)) -+ g.flatten(msg) -+ self.assertEqual(s.getvalue(), self.typ(expected)) -+ -+ def test_keep_long_encoded_newlines(self): -+ msg = self.msgmaker(self.typ(textwrap.dedent("""\ -+ To: nobody -+ Subject: Bad subject=?UTF-8?Q?=0A?=Bcc: injection@example.com -+ -+ None -+ """))) -+ expected = textwrap.dedent("""\ -+ To: nobody -+ Subject: Bad subject -+ =?utf-8?q?=0A?=Bcc: -+ injection@example.com -+ -+ None -+ """) -+ s = self.ioclass() -+ g = self.genclass(s, policy=self.policy.clone(max_line_length=30)) -+ g.flatten(msg) -+ self.assertEqual(s.getvalue(), self.typ(expected)) -+ - - class TestGenerator(TestGeneratorBase, TestEmailBase): - -@@ -224,6 +263,29 @@ class TestGenerator(TestGeneratorBase, TestEmailBase): - ioclass = io.StringIO - typ = str - -+ def test_verify_generated_headers(self): -+ """gh-121650: by default the generator prevents header injection""" -+ class LiteralHeader(str): -+ name = 'Header' -+ def fold(self, **kwargs): -+ return self -+ -+ for text in ( -+ 'Value\r\nBad Injection\r\n', -+ 'NoNewLine' -+ ): -+ with self.subTest(text=text): -+ message = message_from_string( -+ "Header: Value\r\n\r\nBody", -+ policy=self.policy, -+ ) -+ -+ del message['Header'] -+ message['Header'] = LiteralHeader(text) -+ -+ with self.assertRaises(email.errors.HeaderWriteError): -+ message.as_string() -+ - - class TestBytesGenerator(TestGeneratorBase, TestEmailBase): - -diff --git a/Lib/test/test_email/test_policy.py b/Lib/test/test_email/test_policy.py -index c6b9c80efe..baa35fd68e 100644 ---- a/Lib/test/test_email/test_policy.py -+++ b/Lib/test/test_email/test_policy.py -@@ -26,6 +26,7 @@ class PolicyAPITests(unittest.TestCase): - 'raise_on_defect': False, - 'mangle_from_': True, - 'message_factory': None, -+ 'verify_generated_headers': True, - } - # These default values are the ones set on email.policy.default. - # If any of these defaults change, the docs must be updated. -@@ -294,6 +295,31 @@ def test_short_maxlen_error(self): - with self.assertRaises(email.errors.HeaderParseError): - policy.fold("Subject", subject) - -+ def test_verify_generated_headers(self): -+ """Turning protection off allows header injection""" -+ policy = email.policy.default.clone(verify_generated_headers=False) -+ for text in ( -+ 'Header: Value\r\nBad: Injection\r\n', -+ 'Header: NoNewLine' -+ ): -+ with self.subTest(text=text): -+ message = email.message_from_string( -+ "Header: Value\r\n\r\nBody", -+ policy=policy, -+ ) -+ class LiteralHeader(str): -+ name = 'Header' -+ def fold(self, **kwargs): -+ return self -+ -+ del message['Header'] -+ message['Header'] = LiteralHeader(text) -+ -+ self.assertEqual( -+ message.as_string(), -+ f"{text}\nBody", -+ ) -+ - # XXX: Need subclassing tests. - # For adding subclassed objects, make sure the usual rules apply (subclass - # wins), but that the order still works (right overrides left). -diff --git a/Misc/NEWS.d/next/Library/2024-07-27-16-10-41.gh-issue-121650.nf6oc9.rst b/Misc/NEWS.d/next/Library/2024-07-27-16-10-41.gh-issue-121650.nf6oc9.rst -new file mode 100644 -index 0000000000..83dd28d4ac ---- /dev/null -+++ b/Misc/NEWS.d/next/Library/2024-07-27-16-10-41.gh-issue-121650.nf6oc9.rst -@@ -0,0 +1,5 @@ -+:mod:`email` headers with embedded newlines are now quoted on output. The -+:mod:`~email.generator` will now refuse to serialize (write) headers that -+are unsafely folded or delimited; see -+:attr:`~email.policy.Policy.verify_generated_headers`. (Contributed by Bas -+Bloemsaat and Petr Viktorin in :gh:`121650`.) diff --git a/00436-cve-2024-8088-gh-122905-sanitize-names-in-zipfile-path.patch b/00436-cve-2024-8088-gh-122905-sanitize-names-in-zipfile-path.patch deleted file mode 100644 index 098c8af..0000000 --- a/00436-cve-2024-8088-gh-122905-sanitize-names-in-zipfile-path.patch +++ /dev/null @@ -1,128 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: "Jason R. Coombs" -Date: Mon, 19 Aug 2024 19:28:20 -0400 -Subject: [PATCH] 00436: [CVE-2024-8088] gh-122905: Sanitize names in - zipfile.Path. - -Co-authored-by: Jason R. Coombs ---- - Lib/test/test_zipfile.py | 17 ++++++ - Lib/zipfile.py | 61 ++++++++++++++++++- - ...-08-11-14-08-04.gh-issue-122905.7tDsxA.rst | 1 + - 3 files changed, 78 insertions(+), 1 deletion(-) - create mode 100644 Misc/NEWS.d/next/Library/2024-08-11-14-08-04.gh-issue-122905.7tDsxA.rst - -diff --git a/Lib/test/test_zipfile.py b/Lib/test/test_zipfile.py -index 4de6f379a4..8bdc7a1b7d 100644 ---- a/Lib/test/test_zipfile.py -+++ b/Lib/test/test_zipfile.py -@@ -3651,6 +3651,23 @@ def test_extract_orig_with_implied_dirs(self, alpharep): - zipfile.Path(zf) - zf.extractall(source_path.parent) - -+ def test_malformed_paths(self): -+ """ -+ Path should handle malformed paths. -+ """ -+ data = io.BytesIO() -+ zf = zipfile.ZipFile(data, "w") -+ zf.writestr("/one-slash.txt", b"content") -+ zf.writestr("//two-slash.txt", b"content") -+ zf.writestr("../parent.txt", b"content") -+ zf.filename = '' -+ root = zipfile.Path(zf) -+ assert list(map(str, root.iterdir())) == [ -+ 'one-slash.txt', -+ 'two-slash.txt', -+ 'parent.txt', -+ ] -+ - - class EncodedMetadataTests(unittest.TestCase): - file_names = ['\u4e00', '\u4e8c', '\u4e09'] # Han 'one', 'two', 'three' -diff --git a/Lib/zipfile.py b/Lib/zipfile.py -index 86829abce4..b7bf9ef7e3 100644 ---- a/Lib/zipfile.py -+++ b/Lib/zipfile.py -@@ -9,6 +9,7 @@ - import itertools - import os - import posixpath -+import re - import shutil - import stat - import struct -@@ -2243,7 +2244,65 @@ def _difference(minuend, subtrahend): - return itertools.filterfalse(set(subtrahend).__contains__, minuend) - - --class CompleteDirs(ZipFile): -+class SanitizedNames: -+ """ -+ ZipFile mix-in to ensure names are sanitized. -+ """ -+ -+ def namelist(self): -+ return list(map(self._sanitize, super().namelist())) -+ -+ @staticmethod -+ def _sanitize(name): -+ r""" -+ Ensure a relative path with posix separators and no dot names. -+ Modeled after -+ https://github.com/python/cpython/blob/bcc1be39cb1d04ad9fc0bd1b9193d3972835a57c/Lib/zipfile/__init__.py#L1799-L1813 -+ but provides consistent cross-platform behavior. -+ >>> san = SanitizedNames._sanitize -+ >>> san('/foo/bar') -+ 'foo/bar' -+ >>> san('//foo.txt') -+ 'foo.txt' -+ >>> san('foo/.././bar.txt') -+ 'foo/bar.txt' -+ >>> san('foo../.bar.txt') -+ 'foo../.bar.txt' -+ >>> san('\\foo\\bar.txt') -+ 'foo/bar.txt' -+ >>> san('D:\\foo.txt') -+ 'D/foo.txt' -+ >>> san('\\\\server\\share\\file.txt') -+ 'server/share/file.txt' -+ >>> san('\\\\?\\GLOBALROOT\\Volume3') -+ '?/GLOBALROOT/Volume3' -+ >>> san('\\\\.\\PhysicalDrive1\\root') -+ 'PhysicalDrive1/root' -+ Retain any trailing slash. -+ >>> san('abc/') -+ 'abc/' -+ Raises a ValueError if the result is empty. -+ >>> san('../..') -+ Traceback (most recent call last): -+ ... -+ ValueError: Empty filename -+ """ -+ -+ def allowed(part): -+ return part and part not in {'..', '.'} -+ -+ # Remove the drive letter. -+ # Don't use ntpath.splitdrive, because that also strips UNC paths -+ bare = re.sub('^([A-Z]):', r'\1', name, flags=re.IGNORECASE) -+ clean = bare.replace('\\', '/') -+ parts = clean.split('/') -+ joined = '/'.join(filter(allowed, parts)) -+ if not joined: -+ raise ValueError("Empty filename") -+ return joined + '/' * name.endswith('/') -+ -+ -+class CompleteDirs(SanitizedNames, ZipFile): - """ - A ZipFile subclass that ensures that implied directories - are always included in the namelist. -diff --git a/Misc/NEWS.d/next/Library/2024-08-11-14-08-04.gh-issue-122905.7tDsxA.rst b/Misc/NEWS.d/next/Library/2024-08-11-14-08-04.gh-issue-122905.7tDsxA.rst -new file mode 100644 -index 0000000000..1be44c906c ---- /dev/null -+++ b/Misc/NEWS.d/next/Library/2024-08-11-14-08-04.gh-issue-122905.7tDsxA.rst -@@ -0,0 +1 @@ -+:class:`zipfile.Path` objects now sanitize names from the zipfile. diff --git a/python3.11.spec b/python3.11.spec index 1187e7f..b795256 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}.9 +%global general_version %{pybasever}.10 #global prerel ... %global upstream_version %{general_version}%{?prerel} Version: %{general_version}%{?prerel:~%{prerel}} -Release: 6%{?dist} +Release: 1%{?dist} License: Python-2.0.1 @@ -319,66 +319,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 -# 00415 # 744762808f7303a55fa941f65cacb94fd7099e5e -# [CVE-2023-27043] gh-102988: Reject malformed addresses in email.parseaddr() (#111116) -# -# Detect email address parsing errors and return empty tuple to -# indicate the parsing error (old API). Add an optional 'strict' -# parameter to getaddresses() and parseaddr() functions. Patch by -# Thomas Dwyer. -Patch415: 00415-cve-2023-27043-gh-102988-reject-malformed-addresses-in-email-parseaddr-111116.patch - -# 00431 # 4e176bf669bb71e518ee3e79a492ae02ec6397bc -# gh-113171: gh-65056: Fix "private" (non-global) IP address ranges (GH-113179) (GH-113186) (GH-118177) (GH-118472) -# -# The _private_networks variables, used by various is_private -# implementations, were missing some ranges and at the same time had -# overly strict ranges (where there are more specific ranges considered -# globally reachable by the IANA registries). -# -# This patch updates the ranges with what was missing or otherwise -# incorrect. -# -# 100.64.0.0/10 is left alone, for now, as it's been made special in [1]. -# -# The _address_exclude_many() call returns 8 networks for IPv4, 121 -# networks for IPv6. -# -# [1] https://github.com/python/cpython/issues/61602 -# -# In 3.10 and below, is_private checks whether the network and broadcast -# address are both private. -# In later versions (where the test wss backported from), it checks -# whether they both are in the same private network. -# -# For 0.0.0.0/0, both 0.0.0.0 and 255.225.255.255 are private, -# but one is in 0.0.0.0/8 ("This network") and the other in -# 255.255.255.255/32 ("Limited broadcast"). -Patch431: 00431-gh-113171-gh-65056-fix-private-non-global-ip-address-ranges-gh-113179-gh-113186-gh-118177-gh-118472.patch - -# 00435 # d33a3c90daa3d5d2d7e67f6e9264e5438d9608a0 -# gh-121650: Encode newlines in headers, and verify headers are sound (GH-122233) -# -# Per RFC 2047: -# -# > [...] these encoding schemes allow the -# > encoding of arbitrary octet values, mail readers that implement this -# > decoding should also ensure that display of the decoded data on the -# > recipient's terminal will not cause unwanted side-effects -# -# It seems that the "quoted-word" scheme is a valid way to include -# a newline character in a header value, just like we already allow -# undecodable bytes or control characters. -# They do need to be properly quoted when serialized to text, though. -# -# This should fail for custom fold() implementations that aren't careful -# about newlines. -Patch435: 00435-gh-121650-encode-newlines-in-headers-and-verify-headers-are-sound-gh-122233.patch - -# 00436 # 1acd6db660ad1124ab7ae449a841608dd9d9062d -# [CVE-2024-8088] gh-122905: Sanitize names in zipfile.Path. -Patch436: 00436-cve-2024-8088-gh-122905-sanitize-names-in-zipfile-path.patch - # (New patches go here ^^^) # # When adding new patches to "python" and "python3" in Fedora, EL, etc., @@ -1694,6 +1634,9 @@ CheckPython optimized # ====================================================== %changelog +* Mon Sep 09 2024 Tomáš Hrnčiar - 3.11.10-1 +- Update to 3.11.10 + * Fri Aug 23 2024 Charalampos Stratakis - 3.11.9-6 - Security fix for CVE-2024-8088 - Fixes: rhbz#2307460 diff --git a/sources b/sources index 86a3b52..24b6016 100644 --- a/sources +++ b/sources @@ -1,2 +1,2 @@ -SHA512 (Python-3.11.9.tar.xz) = 2b0a1d936b4ef8376f9655797aece8ffdff75031ad7bfa840f330cac2aed189aecc80c163edc12ea772851d7a011f3fc1960470a73d9d4290cf3ab8ad6ed7e6a -SHA512 (Python-3.11.9.tar.xz.asc) = b18b50e7168b2ca5376a1fa75e50e8baae2026d4f11d4cf613d758f3f17df4610fe4653fb2ac0c5c4ec0f6e630dc6490ad1ff32a2fd0ebd60f9f3bd136207ffc +SHA512 (Python-3.11.10.tar.xz) = 6ce77cced1ce90bb5eea38504dfc1bc19c872149a5a63fdd8353ac8c772c54ab7a42176e141c7f6f898d31761bf93e1739b238920fbeefbedd6016ad033c1de0 +SHA512 (Python-3.11.10.tar.xz.asc) = 3a9efe1dd39fd6883ae3fc8dd7f6e25af7e06c6e6049cf9a31a1a82e6d7c84f85ac838d2a71127977d93ce77233a8bbff86a10a80d24fcee85a4e70fcbd1db19 From 61754725b2f1852fe560986e084feb7c092d825a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Hrn=C4=8Diar?= Date: Wed, 11 Sep 2024 19:54:15 +0200 Subject: [PATCH 085/118] Fix ThreadedVSOCKSocketStreamTest --- ...treamtest-gh-119465-gh-119479-119484.patch | 66 +++++++++++++++++++ python3.11.spec | 11 ++++ 2 files changed, 77 insertions(+) create mode 100644 00438-fix-threadedvsocksocketstreamtest-gh-119465-gh-119479-119484.patch diff --git a/00438-fix-threadedvsocksocketstreamtest-gh-119465-gh-119479-119484.patch b/00438-fix-threadedvsocksocketstreamtest-gh-119465-gh-119479-119484.patch new file mode 100644 index 0000000..a4830ed --- /dev/null +++ b/00438-fix-threadedvsocksocketstreamtest-gh-119465-gh-119479-119484.patch @@ -0,0 +1,66 @@ +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/python3.11.spec b/python3.11.spec index b795256..acebdec 100644 --- a/python3.11.spec +++ b/python3.11.spec @@ -319,6 +319,17 @@ 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 + # (New patches go here ^^^) # # When adding new patches to "python" and "python3" in Fedora, EL, etc., From 77dc13a527c22f461ca53b3c4905e9c45df15abe Mon Sep 17 00:00:00 2001 From: Lumir Balhar Date: Tue, 3 Dec 2024 20:59:35 +0100 Subject: [PATCH 086/118] 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 087/118] 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 088/118] 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 089/118] 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 090/118] 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 091/118] 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 092/118] 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 093/118] 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 094/118] 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 095/118] 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 096/118] 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 097/118] 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 098/118] 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 099/118] 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 100/118] 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 101/118] 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 102/118] 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 103/118] 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 104/118] 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 105/118] 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 106/118] 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 107/118] 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 108/118] 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 109/118] 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 110/118] 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 111/118] 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 112/118] 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 113/118] 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 114/118] 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 115/118] 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 116/118] 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 117/118] 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 118/118] 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