Compare commits

...
Sign in to create a new pull request.

19 commits

Author SHA1 Message Date
Miro Hrončok
0ca3f59c07 On EL 9, also supports reparse deferral in expat
This replaces one downstream-only patch with another.
Yet arguably, this is the safer thing to do.

Read the patch description for details; won't copy paste them here.

Also, require expat >= version-release when expat < 2.7.4.

Assisted-By: Claude Opus 4.6
2026-08-13 12:47:37 +02:00
Karolina Surma
b93f3ee7d7 Update to Python 3.13.15 2026-08-11 10:32:30 +02:00
Fedora Release Engineering
8cc71e2467 Rebuilt for https://fedoraproject.org/wiki/Fedora_45_Mass_Rebuild 2026-07-16 22:48:21 +00:00
Lumir Balhar
ae2158c990 Run a new test to monitor changes in required symbols 2026-07-01 12:34:13 +02:00
Karolina Surma
a5e28d44e7 Update to Python 3.13.14 2026-06-11 16:12:16 +02:00
Miro Hrončok
58718512ed Explicitly build with OpenSSL 3 for now
https://fedoraproject.org/wiki/Changes/OpenSSL40
2026-04-09 13:26:27 +02:00
Tomáš Hrnčiar
c731000e1e Update to 3.13.13 2026-04-08 15:53:50 +02:00
Miro Hrončok
c444274dd9 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)
2026-03-31 15:45:13 +02:00
Lumir Balhar
007c7d59dd Security fix for CVE-2026-4519 (rhbz#2449729) 2026-03-26 09:25:11 +01:00
Tomáš Hrnčiar
b909398e15 Backport patches to fix CVEs CVE-2025-15366, CVE-2025-15367 2026-02-10 09:54:41 +01:00
Tomáš Hrnčiar
ad7f5eb689 Update to 3.13.12 2026-02-09 17:21:36 +01:00
Fedora Release Engineering
1045416eac Rebuilt for https://fedoraproject.org/wiki/Fedora_44_Mass_Rebuild 2026-01-17 10:40:12 +00:00
Karolina Surma
faeed1b6c7 Extend the expat requirement to differentiate between 32 and 64 arches
(cherry picked from python3.15 commit a5ca170d3f1e6e19f5df66f21482c2b10593af42)
2026-01-13 16:28:34 +01:00
Karolina Surma
1b3b52c264 Require at least the same expat version as used during the build
In the past we have had a versioned requirement on expat, e.g.:
https://src.fedoraproject.org/rpms/python3.13/c/c686992b6c25a39d0e4117053ddb669fd5998723
The explanation is still valid: if Python is built with an expat version
with new symbols, and used with an installed older expat, it won't work,
preventing crating new venvs, and many more.
This has happened again now with expat 2.7.2 introducing new symbols.

Reintroduce the versioned requirement and make it future-proof - the
generated version will always match at least the one present in the buildroot
during the Python build.
2026-01-07 12:27:50 +01:00
Miro Hrončok
98ab1346cf Update to 3.13.11 2025-12-05 22:38:46 +01:00
Tomáš Hrnčiar
efb1f534c5 Update to 3.13.10 2025-12-03 10:30:59 +01:00
Miro Hrončok
f17c52832b Inject SBOM into the installed wheels (when using the bundled ones) 2025-10-15 11:58:34 +00:00
Karolina Surma
1f3785e703 trace is officially licensed as HPND-SMC
https://gitlab.com/fedora/legal/fedora-license-data/-/issues/657#note_2815942473
2025-10-15 11:53:43 +00:00
Miro Hrončok
edb5d53104 Update to Python 3.13.9 2025-10-14 23:40:57 +02:00
10 changed files with 502 additions and 258 deletions

View file

@ -30,7 +30,7 @@ Co-authored-by: Lumír Balhar <frenzy.madness@gmail.com>
3 files changed, 72 insertions(+), 4 deletions(-)
diff --git a/Lib/site.py b/Lib/site.py
index aedf36399c..2ae49a8029 100644
index 041dca113a..ca6320df2f 100644
--- a/Lib/site.py
+++ b/Lib/site.py
@@ -415,8 +415,15 @@ def getsitepackages(prefixes=None):
@ -51,7 +51,7 @@ index aedf36399c..2ae49a8029 100644
if os.path.isdir(sitedir):
addsitedir(sitedir, known_paths)
diff --git a/Lib/sysconfig/__init__.py b/Lib/sysconfig/__init__.py
index f7bd675bb3..f1ff347c3d 100644
index 43edebce34..40e85568ea 100644
--- a/Lib/sysconfig/__init__.py
+++ b/Lib/sysconfig/__init__.py
@@ -106,6 +106,12 @@
@ -130,7 +130,7 @@ index f7bd675bb3..f1ff347c3d 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 9723300f51..310706652a 100644
index ce17206a3c..fd95071099 100644
--- a/Lib/test/test_sysconfig.py
+++ b/Lib/test/test_sysconfig.py
@@ -130,8 +130,19 @@ def test_get_path(self):
@ -154,7 +154,7 @@ index 9723300f51..310706652a 100644
os.path.normpath(expected),
)
@@ -393,7 +404,7 @@ def test_get_config_h_filename(self):
@@ -395,7 +406,7 @@ def test_get_config_h_filename(self):
self.assertTrue(os.path.isfile(config_h), config_h)
def test_get_scheme_names(self):
@ -163,7 +163,7 @@ index 9723300f51..310706652a 100644
if HAS_USER_BASE:
wanted.extend(['nt_user', 'osx_framework_user', 'posix_user'])
self.assertEqual(get_scheme_names(), tuple(sorted(wanted)))
@@ -405,6 +416,8 @@ def test_symlink(self): # Issue 7880
@@ -407,6 +418,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))

View file

@ -1,32 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= <miro@hroncok.cz>
Date: Fri, 25 Apr 2025 09:33:37 +0200
Subject: 00461: Downstream only: Install wheel in test venvs when setuptools <
71
---
Lib/test/support/__init__.py | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py
index 4605938b87..a0055d6887 100644
--- a/Lib/test/support/__init__.py
+++ b/Lib/test/support/__init__.py
@@ -2462,9 +2462,16 @@ def run_command(cmd):
else:
python = os.path.join(venv, 'bin', python_exe)
+ setuptools_whl = _findwheel('setuptools')
+ whl_filename = os.path.basename(setuptools_whl)
+ setuptools_major = int(whl_filename.split('-')[1].split('.')[0])
+ if setuptools_major >= 71: # we need 70.1+, but that's OK
+ wheels = (setuptools_whl,)
+ else:
+ wheels = (setuptools_whl, _findwheel('wheel'))
cmd = (python, '-X', 'dev',
'-m', 'pip', 'install',
- _findwheel('setuptools'),
+ *wheels,
)
run_command(cmd)

View file

@ -1,102 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Charalampos Stratakis <cstratak@redhat.com>
Date: Tue, 3 Jun 2025 03:02:15 +0200
Subject: 00464: Enable PAC and BTI protections for aarch64
Apply protection against ROP/JOP attacks for aarch64 on asm_trampoline.S
The BTI flag must be applied in the assembler sources for this class
of attacks to be mitigated on newer aarch64 processors.
Upstream PR: https://github.com/python/cpython/pull/130864/files
The upstream patch is incomplete but only for the case where
frame pointers are not used on 3.13+.
Since on Fedora we always compile with frame pointers the BTI/PAC
hardware protections can be enabled without losing Perf unwinding.
---
Python/asm_trampoline.S | 4 +++
Python/asm_trampoline_aarch64.h | 50 +++++++++++++++++++++++++++++++++
2 files changed, 54 insertions(+)
create mode 100644 Python/asm_trampoline_aarch64.h
diff --git a/Python/asm_trampoline.S b/Python/asm_trampoline.S
index a14e68c0e8..2513cde4e7 100644
--- a/Python/asm_trampoline.S
+++ b/Python/asm_trampoline.S
@@ -1,3 +1,5 @@
+#include "asm_trampoline_aarch64.h"
+
.text
.globl _Py_trampoline_func_start
# The following assembly is equivalent to:
@@ -21,10 +23,12 @@ _Py_trampoline_func_start:
#if defined(__aarch64__) && defined(__AARCH64EL__) && !defined(__ILP32__)
// ARM64 little endian, 64bit ABI
// generate with aarch64-linux-gnu-gcc 12.1
+ SIGN_LR
stp x29, x30, [sp, -16]!
mov x29, sp
blr x3
ldp x29, x30, [sp], 16
+ VERIFY_LR
ret
#endif
#ifdef __riscv
diff --git a/Python/asm_trampoline_aarch64.h b/Python/asm_trampoline_aarch64.h
new file mode 100644
index 0000000000..4b0ec4a7dc
--- /dev/null
+++ b/Python/asm_trampoline_aarch64.h
@@ -0,0 +1,50 @@
+#ifndef ASM_TRAMPOLINE_AARCH_64_H_
+#define ASM_TRAMPOLINE_AARCH_64_H_
+
+/*
+ * References:
+ * - https://developer.arm.com/documentation/101028/0012/5--Feature-test-macros
+ * - https://github.com/ARM-software/abi-aa/blob/main/aaelf64/aaelf64.rst
+ */
+
+#if defined(__ARM_FEATURE_BTI_DEFAULT) && __ARM_FEATURE_BTI_DEFAULT == 1
+ #define BTI_J hint 36 /* bti j: for jumps, IE br instructions */
+ #define BTI_C hint 34 /* bti c: for calls, IE bl instructions */
+ #define GNU_PROPERTY_AARCH64_BTI 1 /* bit 0 GNU Notes is for BTI support */
+#else
+ #define BTI_J
+ #define BTI_C
+ #define GNU_PROPERTY_AARCH64_BTI 0
+#endif
+
+#if defined(__ARM_FEATURE_PAC_DEFAULT)
+ #if __ARM_FEATURE_PAC_DEFAULT & 1
+ #define SIGN_LR hint 25 /* paciasp: sign with the A key */
+ #define VERIFY_LR hint 29 /* autiasp: verify with the A key */
+ #elif __ARM_FEATURE_PAC_DEFAULT & 2
+ #define SIGN_LR hint 27 /* pacibsp: sign with the b key */
+ #define VERIFY_LR hint 31 /* autibsp: verify with the b key */
+ #endif
+ #define GNU_PROPERTY_AARCH64_POINTER_AUTH 2 /* bit 1 GNU Notes is for PAC support */
+#else
+ #define SIGN_LR BTI_C
+ #define VERIFY_LR
+ #define GNU_PROPERTY_AARCH64_POINTER_AUTH 0
+#endif
+
+/* Add the BTI and PAC support to GNU Notes section */
+#if GNU_PROPERTY_AARCH64_BTI != 0 || GNU_PROPERTY_AARCH64_POINTER_AUTH != 0
+ .pushsection .note.gnu.property, "a"; /* Start a new allocatable section */
+ .balign 8; /* align it on a byte boundry */
+ .long 4; /* size of "GNU\0" */
+ .long 0x10; /* size of descriptor */
+ .long 0x5; /* NT_GNU_PROPERTY_TYPE_0 */
+ .asciz "GNU";
+ .long 0xc0000000; /* GNU_PROPERTY_AARCH64_FEATURE_1_AND */
+ .long 4; /* Four bytes of data */
+ .long (GNU_PROPERTY_AARCH64_BTI|GNU_PROPERTY_AARCH64_POINTER_AUTH); /* BTI or PAC is enabled */
+ .long 0; /* padding for 8 byte alignment */
+ .popsection; /* end the section */
+#endif
+
+#endif

View file

@ -0,0 +1,133 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= <miro@hroncok.cz>
Date: Wed, 12 Aug 2026 15:18:39 +0200
Subject: 00466: Downstream only: Lower XML_COMBINED_VERSION threshold for
reparse deferral
RHEL 9 expat 2.5.0 has XML_SetReparseDeferralEnabled backported
via the CVE-2023-52425 fix, but XML_COMBINED_VERSION remains 20500.
CPython's #if XML_COMBINED_VERSION >= 20600 guards compile the setter
as a no-op, so SetReparseDeferralEnabled silently does nothing and
GetReparseDeferralEnabled always returns False, even though the expat
library actually supports (and enables) reparse deferral.
Lower the threshold from 20600 to 20500 so that CPython uses the
backported function. This makes the Python API actually work on RHEL 9
and fixes test failures (test_reparse_deferral_disabled,
test_flush_reparse_deferral_disabled, test_simple_xml_chunk_*).
The spec file BuildRequires expat-devel >= 2.5.0-2 to ensure the
backported function is available.
---
Lib/test/test_pyexpat.py | 6 +++---
Lib/test/test_sax.py | 4 ++--
Lib/test/test_xml_etree.py | 4 ++--
Modules/pyexpat.c | 6 +++---
4 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/Lib/test/test_pyexpat.py b/Lib/test/test_pyexpat.py
index ae7cec6540..7f73a8c5e7 100644
--- a/Lib/test/test_pyexpat.py
+++ b/Lib/test/test_pyexpat.py
@@ -1001,7 +1001,7 @@ def test_error_path_no_crash(self):
class ReparseDeferralTest(unittest.TestCase):
def test_getter_setter_round_trip(self):
parser = expat.ParserCreate()
- enabled = (expat.version_info >= (2, 6, 0))
+ enabled = (expat.version_info >= (2, 5, 0))
self.assertIs(parser.GetReparseDeferralEnabled(), enabled)
parser.SetReparseDeferralEnabled(False)
@@ -1010,7 +1010,7 @@ def test_getter_setter_round_trip(self):
self.assertIs(parser.GetReparseDeferralEnabled(), enabled)
def test_reparse_deferral_enabled(self):
- if expat.version_info < (2, 6, 0):
+ if expat.version_info < (2, 5, 0):
self.skipTest(f'Expat {expat.version_info} does not '
'support reparse deferral')
@@ -1041,7 +1041,7 @@ def start_element(name, _):
parser = expat.ParserCreate()
parser.StartElementHandler = start_element
- if expat.version_info >= (2, 6, 0):
+ if expat.version_info >= (2, 5, 0):
parser.SetReparseDeferralEnabled(False)
self.assertFalse(parser.GetReparseDeferralEnabled())
diff --git a/Lib/test/test_sax.py b/Lib/test/test_sax.py
index 9b3014a94a..0e38c9488e 100644
--- a/Lib/test/test_sax.py
+++ b/Lib/test/test_sax.py
@@ -1215,7 +1215,7 @@ def test_expat_incremental_reset(self):
self.assertEqual(result.getvalue(), start + b"<doc>text</doc>")
- @unittest.skipIf(pyexpat.version_info < (2, 6, 0),
+ @unittest.skipIf(pyexpat.version_info < (2, 5, 0),
f'Expat {pyexpat.version_info} does not '
'support reparse deferral')
def test_flush_reparse_deferral_enabled(self):
@@ -1249,7 +1249,7 @@ def test_flush_reparse_deferral_disabled(self):
for chunk in ("<doc", ">"):
parser.feed(chunk)
- if pyexpat.version_info >= (2, 6, 0):
+ if pyexpat.version_info >= (2, 5, 0):
parser._parser.SetReparseDeferralEnabled(False)
self.assertEqual(result.getvalue(), start) # i.e. no elements started
diff --git a/Lib/test/test_xml_etree.py b/Lib/test/test_xml_etree.py
index 4a76a5be1e..effb899d7b 100644
--- a/Lib/test/test_xml_etree.py
+++ b/Lib/test/test_xml_etree.py
@@ -1804,7 +1804,7 @@ def test_unknown_event(self):
with self.assertRaisesRegex(ValueError, "unknown event 'bogus'"):
ET.XMLPullParser(events=(x.decode() for x in (b'start', b'end', b'bogus')))
- @unittest.skipIf(pyexpat.version_info < (2, 6, 0),
+ @unittest.skipIf(pyexpat.version_info < (2, 5, 0),
f'Expat {pyexpat.version_info} does not '
'support reparse deferral')
def test_flush_reparse_deferral_enabled(self):
@@ -1834,7 +1834,7 @@ def test_flush_reparse_deferral_disabled(self):
for chunk in ("<doc", ">"):
parser.feed(chunk)
- if pyexpat.version_info >= (2, 6, 0):
+ if pyexpat.version_info >= (2, 5, 0):
if not ET is pyET:
self.skipTest(f'XMLParser.(Get|Set)ReparseDeferralEnabled '
'methods not available in C')
diff --git a/Modules/pyexpat.c b/Modules/pyexpat.c
index 9e5d84eb5e..b008fe66c1 100644
--- a/Modules/pyexpat.c
+++ b/Modules/pyexpat.c
@@ -781,7 +781,7 @@ pyexpat_xmlparser_SetReparseDeferralEnabled_impl(xmlparseobject *self,
int enabled)
/*[clinic end generated code: output=5ec539e3b63c8c49 input=021eb9e0bafc32c5]*/
{
-#if XML_COMBINED_VERSION >= 20600
+#if XML_COMBINED_VERSION >= 20500
XML_SetReparseDeferralEnabled(self->itself, enabled ? XML_TRUE : XML_FALSE);
self->reparse_deferral_enabled = (bool)enabled;
#endif
@@ -1446,7 +1446,7 @@ newxmlparseobject(pyexpat_state *state, const char *encoding,
self->ns_prefixes = 0;
self->handlers = NULL;
self->intern = Py_XNewRef(intern);
-#if XML_COMBINED_VERSION >= 20600
+#if XML_COMBINED_VERSION >= 20500
self->reparse_deferral_enabled = true;
#else
self->reparse_deferral_enabled = false;
@@ -2332,7 +2332,7 @@ pyexpat_exec(PyObject *mod)
#else
capi->SetHashSalt16Bytes = NULL;
#endif
-#if XML_COMBINED_VERSION >= 20600
+#if XML_COMBINED_VERSION >= 20500
capi->SetReparseDeferralEnabled = XML_SetReparseDeferralEnabled;
#else
capi->SetReparseDeferralEnabled = NULL;

View file

@ -1,69 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Karolina Surma <ksurma@redhat.com>
Date: Tue, 24 Jun 2025 11:12:13 +0200
Subject: 00466: Downstream only: Skip tests not working with older expat
version
We want to run these tests in Fedora and EPEL 10, but not in EPEL 9,
which has too old version of expat. We set the upper bound version
in the conditionalized skip to a release available in CentOS Stream 10,
which is tested as working.
---
Lib/test/test_pyexpat.py | 2 ++
Lib/test/test_sax.py | 2 ++
Lib/test/test_xml_etree.py | 6 ++++++
3 files changed, 10 insertions(+)
diff --git a/Lib/test/test_pyexpat.py b/Lib/test/test_pyexpat.py
index a091430463..55ebf34c52 100644
--- a/Lib/test/test_pyexpat.py
+++ b/Lib/test/test_pyexpat.py
@@ -826,6 +826,8 @@ def start_element(name, _):
self.assertEqual(started, ['doc'])
+ @unittest.skipIf(expat.version_info < (2, 7, 1),
+ f"Skip for expat < 2.7.1 (version available in RHEL 10)")
def test_reparse_deferral_disabled(self):
started = []
diff --git a/Lib/test/test_sax.py b/Lib/test/test_sax.py
index 9b3014a94a..90401e0d8f 100644
--- a/Lib/test/test_sax.py
+++ b/Lib/test/test_sax.py
@@ -1240,6 +1240,8 @@ def test_flush_reparse_deferral_enabled(self):
self.assertEqual(result.getvalue(), start + b"<doc></doc>")
+ @unittest.skipIf(pyexpat.version_info < (2, 7, 1),
+ f"Skip for expat < 2.7.1 (version available in RHEL 10)")
def test_flush_reparse_deferral_disabled(self):
result = BytesIO()
xmlgen = XMLGenerator(result)
diff --git a/Lib/test/test_xml_etree.py b/Lib/test/test_xml_etree.py
index 78598b35da..802d1399ea 100644
--- a/Lib/test/test_xml_etree.py
+++ b/Lib/test/test_xml_etree.py
@@ -1548,9 +1548,13 @@ def test_simple_xml(self, chunk_size=None, flush=False):
self.assert_event_tags(parser, [('end', 'root')])
self.assertIsNone(parser.close())
+ @unittest.skipIf(pyexpat.version_info < (2, 7, 1),
+ f"Skip for expat < 2.7.1 (version available in RHEL 10)")
def test_simple_xml_chunk_1(self):
self.test_simple_xml(chunk_size=1, flush=True)
+ @unittest.skipIf(pyexpat.version_info < (2, 7, 1),
+ f"Skip for expat < 2.7.1 (version available in RHEL 10)")
def test_simple_xml_chunk_5(self):
self.test_simple_xml(chunk_size=5, flush=True)
@@ -1777,6 +1781,8 @@ def test_flush_reparse_deferral_enabled(self):
self.assert_event_tags(parser, [('end', 'doc')])
+ @unittest.skipIf(pyexpat.version_info < (2, 7, 1),
+ f"Skip for expat < 2.7.1 (version available in RHEL 10)")
def test_flush_reparse_deferral_disabled(self):
parser = ET.XMLPullParser(events=('start', 'end'))

View file

@ -0,0 +1,59 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Seth Michael Larson <seth@python.org>
Date: Tue, 20 Jan 2026 14:46:32 -0600
Subject: 00475: CVE-2025-15367
Reject control characters in POP3 commands
---
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 4469bff44b..b97274c5c3 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 eb6dab4015..bd621caee4 100644
--- a/Lib/test/test_poplib.py
+++ b/Lib/test/test_poplib.py
@@ -18,6 +18,7 @@
from test.support import asynchat
from test.support import asyncore
from test.support.testcase import ExtraAssertions
+from test.support import control_characters_c0
test_support.requires_working_socket(module=True)
@@ -396,6 +397,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.

View file

@ -0,0 +1,173 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Petr Viktorin <encukou@gmail.com>
Date: Mon, 9 Feb 2026 10:44:21 +0100
Subject: 00477: Raise an error when importing stdlib modules compiled for a
different Python version
This is a downstream workaround "implementing" python#137212 -
the mechanism for the check exists in Python 3.15+, where it needs to be
added to the standard library modules.
In Fedora, we need it also in previous Python versions, as we experience
segmentation fault when importing stdlib modules after update while
Python is running.
_curses, _tkinter, _tracemalloc and readline are not calling PyModuleDef_Init,
which is modified with this patch, hence they need a
direct call to the check function.
Co-Authored-By: Karolina Surma <ksurma@redhat.com>
---
Include/moduleobject.h | 43 +++++++++++++++++++++++++++++++++++++++++
Makefile.pre.in | 3 +++
Modules/_cursesmodule.c | 6 ++++++
Modules/_tkinter.c | 6 ++++++
Modules/_tracemalloc.c | 6 ++++++
Modules/readline.c | 6 ++++++
Objects/moduleobject.c | 1 +
7 files changed, 71 insertions(+)
diff --git a/Include/moduleobject.h b/Include/moduleobject.h
index 2a17c891dd..64017c666c 100644
--- a/Include/moduleobject.h
+++ b/Include/moduleobject.h
@@ -116,6 +116,49 @@ struct PyModuleDef {
freefunc m_free;
};
+#if defined(_PyHack_check_version_on_modinit) && defined(Py_BUILD_CORE)
+/* The mechanism for the check has been implemented on Python 3.15+:
+ * https://github.com/python/cpython/pull/137212.
+ * In Fedora, we need this in older Pythons too:
+ * if somebody attempts to import a module compiled for a different Python version,
+ * instead of segmentation fault a meaningful error is raised.
+ */
+PyAPI_DATA(const unsigned long) Py_Version;
+
+static inline int
+_PyHack_CheckInternalAPIVersion(const char *mod_name)
+{
+ if (PY_VERSION_HEX != Py_Version) {
+ PyErr_Format(
+ PyExc_ImportError,
+ "internal Python C API version mismatch: "
+ "module %s compiled with %lu.%lu.%lu; "
+ "runtime version is %lu.%lu.%lu",
+ mod_name,
+ (const unsigned long)((PY_VERSION_HEX >> 24) & 0xFF),
+ (const unsigned long)((PY_VERSION_HEX >> 16) & 0xFF),
+ (const unsigned long)((PY_VERSION_HEX >> 8) & 0xFF),
+ (const unsigned long)((Py_Version >> 24) & 0xFF),
+ (const unsigned long)((Py_Version >> 16) & 0xFF),
+ (const unsigned long)((Py_Version >> 8) & 0xFF)
+ );
+ return -1;
+ }
+ return 0;
+}
+
+static inline PyObject *
+PyModuleDef_Init_with_check(PyModuleDef *def)
+{
+ if (_PyHack_CheckInternalAPIVersion(def->m_name) < 0) {
+ return NULL;
+ }
+ return PyModuleDef_Init(def);
+}
+
+#define PyModuleDef_Init PyModuleDef_Init_with_check
+#endif
+
#ifdef __cplusplus
}
#endif
diff --git a/Makefile.pre.in b/Makefile.pre.in
index 2363b99a25..f1a07645f0 100644
--- a/Makefile.pre.in
+++ b/Makefile.pre.in
@@ -3159,3 +3159,6 @@ MODULE__MULTIBYTECODEC_DEPS=$(srcdir)/Modules/cjkcodecs/multibytecodec.h
# Local Variables:
# mode: makefile
# End:
+
+# Fedora-specific, downstream only
+PY_STDMODULE_CFLAGS += -D_PyHack_check_version_on_modinit=1
diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c
index 1996488a0e..cfdffd8ec4 100644
--- a/Modules/_cursesmodule.c
+++ b/Modules/_cursesmodule.c
@@ -5011,6 +5011,12 @@ curses_destructor(PyObject *op)
PyMODINIT_FUNC
PyInit__curses(void)
{
+ #ifdef _PyHack_check_version_on_modinit
+ if (_PyHack_CheckInternalAPIVersion("_curses") < 0) {
+ return NULL;
+ }
+ #endif
+
PyObject *m, *d, *v, *c_api_object;
/* Initialize object type */
diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c
index 4e8d75e8e1..32e58755aa 100644
--- a/Modules/_tkinter.c
+++ b/Modules/_tkinter.c
@@ -3499,6 +3499,12 @@ static struct PyModuleDef _tkintermodule = {
PyMODINIT_FUNC
PyInit__tkinter(void)
{
+ #ifdef _PyHack_check_version_on_modinit
+ if (_PyHack_CheckInternalAPIVersion("_tkinter") < 0) {
+ return NULL;
+ }
+ #endif
+
PyObject *m, *uexe, *cexe;
tcl_lock = PyThread_allocate_lock();
diff --git a/Modules/_tracemalloc.c b/Modules/_tracemalloc.c
index 0b85187e5f..87f358ed07 100644
--- a/Modules/_tracemalloc.c
+++ b/Modules/_tracemalloc.c
@@ -215,6 +215,12 @@ static struct PyModuleDef module_def = {
PyMODINIT_FUNC
PyInit__tracemalloc(void)
{
+ #ifdef _PyHack_check_version_on_modinit
+ if (_PyHack_CheckInternalAPIVersion("_tracemalloc") < 0) {
+ return NULL;
+ }
+ #endif
+
PyObject *m;
m = PyModule_Create(&module_def);
if (m == NULL)
diff --git a/Modules/readline.c b/Modules/readline.c
index 7a612deae4..8b2f47eec1 100644
--- a/Modules/readline.c
+++ b/Modules/readline.c
@@ -1548,6 +1548,12 @@ static struct PyModuleDef readlinemodule = {
PyMODINIT_FUNC
PyInit_readline(void)
{
+ #ifdef _PyHack_check_version_on_modinit
+ if (_PyHack_CheckInternalAPIVersion("readline") < 0) {
+ return NULL;
+ }
+ #endif
+
const char *backend = "readline";
PyObject *m;
readlinestate *mod_state;
diff --git a/Objects/moduleobject.c b/Objects/moduleobject.c
index d787f29004..31175ceb3f 100644
--- a/Objects/moduleobject.c
+++ b/Objects/moduleobject.c
@@ -43,6 +43,7 @@ _PyModule_IsExtension(PyObject *obj)
}
+#undef PyModuleDef_Init
PyObject*
PyModuleDef_Init(PyModuleDef* def)
{

View file

@ -43,6 +43,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
@ -62,8 +65,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

View file

@ -45,11 +45,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}.15
#global prerel ...
%global upstream_version %{general_version}%{?prerel}
Version: %{general_version}%{?prerel:~%{prerel}}
Release: 1%{?dist}
Release: 2%{?dist}
License: Python-2.0.1
@ -109,31 +109,30 @@ License: Python-2.0.1
# This needs to be manually updated when we update Python.
# Explore the sources tarball (you need the version before %%prep is executed):
# $ tar -tf Python-%%{upstream_version}.tar.xz | grep whl
%global pip_version 25.2
%global pip_version 26.2.1
%global setuptools_version 79.0.1
# All of those also include a list of indirect bundled libs:
# pip
# $ %%{_rpmconfigdir}/pythonbundles.py <(unzip -p Lib/ensurepip/_bundled/pip-*.whl pip/_vendor/vendor.txt)
%global pip_bundled_provides %{expand:
Provides: bundled(python3dist(cachecontrol)) = 0.14.3
Provides: bundled(python3dist(certifi)) = 2025.7.14
Provides: bundled(python3dist(dependency-groups)) = 1.3.1
Provides: bundled(python3dist(distlib)) = 0.4
Provides: bundled(python3dist(cachecontrol)) = 0.14.4
Provides: bundled(python3dist(certifi)) = 2026.6.17
Provides: bundled(python3dist(distlib)) = 0.4.2
Provides: bundled(python3dist(distro)) = 1.9
Provides: bundled(python3dist(idna)) = 3.10
Provides: bundled(python3dist(msgpack)) = 1.1.1
Provides: bundled(python3dist(packaging)) = 25
Provides: bundled(python3dist(platformdirs)) = 4.3.8
Provides: bundled(python3dist(pygments)) = 2.19.2
Provides: bundled(python3dist(idna)) = 3.18
Provides: bundled(python3dist(msgpack)) = 1.1.2
Provides: bundled(python3dist(packaging)) = 26.2
Provides: bundled(python3dist(platformdirs)) = 4.10
Provides: bundled(python3dist(pygments)) = 2.20
Provides: bundled(python3dist(pyproject-hooks)) = 1.2
Provides: bundled(python3dist(requests)) = 2.32.4
Provides: bundled(python3dist(resolvelib)) = 1.2
Provides: bundled(python3dist(rich)) = 14.1
Provides: bundled(python3dist(requests)) = 2.34.2
Provides: bundled(python3dist(resolvelib)) = 1.2.1
Provides: bundled(python3dist(rich)) = 14.2
Provides: bundled(python3dist(setuptools)) = 70.3
Provides: bundled(python3dist(tomli)) = 2.2.1
Provides: bundled(python3dist(tomli)) = 2.4.1
Provides: bundled(python3dist(tomli-w)) = 1.2
Provides: bundled(python3dist(truststore)) = 0.10.1
Provides: bundled(python3dist(urllib3)) = 1.26.20
Provides: bundled(python3dist(truststore)) = 0.10.4
Provides: bundled(python3dist(urllib3)) = 2.7
}
# setuptools
# vendor.txt not in .whl
@ -255,7 +254,7 @@ Obsoletes: python%{pybasever}%{?1:-%{1}}\
BuildRequires: autoconf
BuildRequires: bluez-libs-devel
BuildRequires: bzip2-devel
BuildRequires: expat-devel
BuildRequires: expat-devel >= 2.5.0-2
BuildRequires: findutils
BuildRequires: gcc
BuildRequires: gdbm-devel
@ -268,7 +267,6 @@ BuildRequires: libuuid-devel
BuildRequires: make
BuildRequires: mpdecimal-devel
BuildRequires: ncurses-devel
BuildRequires: openssl-devel
BuildRequires: pkgconfig
BuildRequires: python-rpm-macros
BuildRequires: readline-devel
@ -281,6 +279,10 @@ BuildRequires: xz-devel
BuildRequires: zlib-devel
BuildRequires: /usr/bin/dtrace
# 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 %{undefined rhel}
BuildRequires: libb2-devel
%endif
@ -368,35 +370,45 @@ Source11: idle3.appdata.xml
# pypa/distutils integration: https://github.com/pypa/distutils/pull/70
Patch251: 00251-change-user-install-location.patch
# 00461 # 920175020b21c0aff5edcc4c28d688b5061f591c
# Downstream only: Install wheel in test venvs when setuptools < 71
Patch461: 00461-downstream-only-install-wheel-in-test-venvs-when-setuptools-71.patch
# 00466 # 713a1368544eddd55088d67f88a23ce31722a4cb
# Downstream only: Lower XML_COMBINED_VERSION threshold for reparse deferral
#
# RHEL 9 expat 2.5.0 has XML_SetReparseDeferralEnabled backported
# via the CVE-2023-52425 fix, but XML_COMBINED_VERSION remains 20500.
# CPython's #if XML_COMBINED_VERSION >= 20600 guards compile the setter
# as a no-op, so SetReparseDeferralEnabled silently does nothing and
# GetReparseDeferralEnabled always returns False, even though the expat
# library actually supports (and enables) reparse deferral.
#
# Lower the threshold from 20600 to 20500 so that CPython uses the
# backported function. This makes the Python API actually work on RHEL 9
# and fixes test failures (test_reparse_deferral_disabled,
# test_flush_reparse_deferral_disabled, test_simple_xml_chunk_*).
#
# The spec file BuildRequires expat-devel >= 2.5.0-2 to ensure the
# backported function is available.
Patch466: 00466-downstream-only-lower-xml_combined_version-threshold-for-reparse-deferral.patch
# 00464 # 292acffec7a379cb6d1f3c47b9e5a2f170bbadb6
# Enable PAC and BTI protections for aarch64
# 00475 # d44fac01037662db286449a78c8fb819788f764c
# CVE-2025-15367
#
# Apply protection against ROP/JOP attacks for aarch64 on asm_trampoline.S
#
# The BTI flag must be applied in the assembler sources for this class
# of attacks to be mitigated on newer aarch64 processors.
#
# Upstream PR: https://github.com/python/cpython/pull/130864/files
#
# The upstream patch is incomplete but only for the case where
# frame pointers are not used on 3.13+.
#
# Since on Fedora we always compile with frame pointers the BTI/PAC
# hardware protections can be enabled without losing Perf unwinding.
Patch464: 00464-enable-pac-and-bti-protections-for-aarch64.patch
# Reject control characters in POP3 commands
Patch475: 00475-cve-2025-15367.patch
# 00466 # e10760fb955ee33d2917f8a57bb4e24d71e5341c
# Downstream only: Skip tests not working with older expat version
# 00477 # 9c62c492e7f2e3b152dbf287c08d307c3f013221
# Raise an error when importing stdlib modules compiled for a different Python version
#
# We want to run these tests in Fedora and EPEL 10, but not in EPEL 9,
# which has too old version of expat. We set the upper bound version
# in the conditionalized skip to a release available in CentOS Stream 10,
# which is tested as working.
Patch466: 00466-downstream-only-skip-tests-not-working-with-older-expat-version.patch
# This is a downstream workaround "implementing" python#137212 -
# the mechanism for the check exists in Python 3.15+, where it needs to be
# added to the standard library modules.
# In Fedora, we need it also in previous Python versions, as we experience
# segmentation fault when importing stdlib modules after update while
# Python is running.
#
# _curses, _tkinter, _tracemalloc and readline are not calling PyModuleDef_Init,
# which is modified with this patch, hence they need a
# direct call to the check function.
Patch477: 00477-raise-an-error-when-importing-stdlib-modules-compiled-for-a-different-python-version.patch
# (New patches go here ^^^)
#
@ -522,14 +534,13 @@ Summary: Python runtime libraries
# Combined manually from https://docs.python.org/3.13/license.html
# Hash of Doc/license.rst which is compared in %%prep, generated with:
# $ sha256sum Doc/license.rst | cut -f1 -d" "
%global license_file_hash 62f2c9c2c75d511170eb464ad5f83b78cc1f37eb2eb49c2846c9aa6c4557ee99
%global license_file_hash 952ac05720d7f1dcb63589b35eb0931b1442eb250230a4ad31198eddf0ad6abc
# Licenses of incorporated software:
# Mersenne Twister in _random C extension contains code under BSD-3-Clause
# socket.getaddrinfo() and socket.getnameinfo() are BSD-3-Clause
# test.support.asynchat and test.support.asyncore are MIT-CMU
# http.cookies is MIT-CMU
# trace is under temporary SPDX ref: https://gitlab.com/fedora/legal/fedora-license-data/-/issues/657
# trace: LicenseRef-Fedora-Temporary-Python-trace
# trace is HPND-SMC
# uu is MIT-CMU
# xmlrpc.client is MIT-CMU
# test.test_epoll is MIT
@ -546,10 +557,11 @@ Summary: Python runtime libraries
# mimalloc is MIT
# parts of asyncio from uvloop are MIT
# Python/qsbr.c is adapted from code under BSD-2-Clause
# An extract of the `Unicode Character Database` converted to an internal format is Unicode-3.0
# Bundled libb2 is not declared in the upstream document, but it's:
# CC0-1.0, covered by grandfathering exception
# We don't query upstream for changes, as 3.13 is the last Python version containing it.
%global libs_license Python-2.0.1 AND CC0-1.0 AND MIT AND BSD-3-Clause AND MIT-CMU AND LicenseRef-Fedora-Temporary-Python-trace AND BSD-2-Clause AND dtoa
%global libs_license Python-2.0.1 AND CC0-1.0 AND MIT AND BSD-3-Clause AND MIT-CMU AND HPND-SMC AND BSD-2-Clause AND dtoa AND Unicode-3.0
%if %{with rpmwheels}
Requires: %{python_wheel_pkg_prefix}-pip-wheel >= 23.1.2
License: %{libs_license}
@ -585,6 +597,28 @@ 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 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_...
# 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.
# We also include release, in case pyxpat uses ABI that was backported
# (e.g. XML_SetReparseDeferralEnabled was added in c9s expat 2.5.0-2).
# 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}-%%{release}' 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
This package contains runtime libraries for use by Python:
- the majority of the Python standard library
@ -761,6 +795,9 @@ License: %{libs_license} AND Apache-2.0 AND ISC AND LGPL-2.1-only AND MPL-2.0 AN
Provides: bundled(libb2) = 0.98.1
Provides: bundled(mimalloc) = 2.12
Requires: tzdata
%if v"%{expat_version}" < v"2.7.4"
Requires: expat%{?_isa} >= %{expat_version}
%endif
%description -n python%{pybasever}-freethreading
The provisional Free Threading (PEP 703) build of Python.
@ -1264,6 +1301,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
# ======================================================
@ -1776,6 +1818,42 @@ CheckPython freethreading
# ======================================================
%changelog
* Wed Aug 12 2026 Miro Hrončok <mhroncok@redhat.com> - 3.13.15-2
- On EPEL 9, also supports reparse deferral in expat
* Mon Aug 10 2026 Karolina Surma <ksurma@redhat.com> - 3.13.15-1
- Update to Python 3.13.15
* Thu Jul 16 2026 Fedora Release Engineering <releng@fedoraproject.org> - 3.13.14-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_45_Mass_Rebuild
* Thu Jun 11 2026 Karolina Surma <ksurma@redhat.com> - 3.13.14-1
- Update to Python 3.13.14
* Wed Apr 08 2026 Tomáš Hrnčiar <thrnciar@redhat.com> - 3.13.13-1
- Update to 3.13.13
* Thu Mar 26 2026 Lumír Balhar <lbalhar@redhat.com> - 3.13.12-2
- Security fix for CVE-2026-4519 (rhbz#2449729)
* Wed Feb 04 2026 Tomáš Hrnčiar <thrnciar@redhat.com> - 3.13.12-1
- Update to 3.13.12
* Sat Jan 17 2026 Fedora Release Engineering <releng@fedoraproject.org> - 3.13.11-3
- Rebuilt for https://fedoraproject.org/wiki/Fedora_44_Mass_Rebuild
* Tue Jan 06 2026 Karolina Surma <ksurma@redhat.com> - 3.13.11-2
- Require at least the same expat version as used during the build time
* Fri Dec 05 2025 Miro Hrončok <mhroncok@redhat.com> - 3.13.11-1
- Update to 3.13.11
* Wed Dec 03 2025 Tomáš Hrnčiar <thrnciar@redhat.com> - 3.13.10-1
- Update to 3.13.10
* Tue Oct 14 2025 Miro Hrončok <mhroncok@redhat.com> - 3.13.9-1
- Update to Python 3.13.9
* Tue Oct 07 2025 Karolina Surma <ksurma@redhat.com> - 3.13.8-1
- Update to Python 3.13.8

View file

@ -1,2 +1,2 @@
SHA512 (Python-3.13.8.tar.xz) = 8569959f24083824f6644b839c6ebd587e67fb74b3c5fed9ef44bfbbba46076e98db33a27218b2d44edd15b3b05ae85e94b71491598cbb871d7d43a9d6fa2b84
SHA512 (Python-3.13.8.tar.xz.asc) = ea5bae3f5a909d16526b614085cd4543153800348dd82ef90945ceed19acbab8db76f7c1279e39d26b9e69608aa0f7cf1eab9a562d00fd1c9badd5b0fafc5c21
SHA512 (Python-3.13.15.tar.xz) = b0ab766a3de0b4cfdbf0b93300d7330c734d3f7057577bb03e95e39da4cdade81993e769c7fa6dfdcc13b9d43a3b399d9cd89b5477b413662e9e691c1b7886b8
SHA512 (Python-3.13.15.tar.xz.asc) = 662c00be95f62e80db43cf42099fef91f764ff7a4433cadf7eb19dedb5e4775adb12878d5ed2295fcea187731de186163ad9672ab72cde62a2335ca58ec1ad86