From 75538d3684a89581b6b85a5336f0cd6a4f19619e Mon Sep 17 00:00:00 2001 From: Charalampos Stratakis Date: Tue, 13 May 2025 02:32:52 +0200 Subject: [PATCH 01/20] 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 | 214 ++++++++++++++++++ python3.10.spec | 22 +- 3 files changed, 235 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..5c0cda1 --- /dev/null +++ b/00462-fix-pyssl_seterror-handling-ssl_error_syscall.patch @@ -0,0 +1,214 @@ +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 | 41 +++++++--------- + ...-02-18-09-50-31.gh-issue-115627.HGchj0.rst | 2 + + Modules/_ssl.c | 48 +++++++------------ + 3 files changed, 38 insertions(+), 53 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 0f1397de73..21d3676c22 100644 +--- a/Lib/test/test_ssl.py ++++ b/Lib/test/test_ssl.py +@@ -2605,16 +2605,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: +@@ -3296,23 +3298,16 @@ def test_wrong_cert_tls13(self): + client_context.wrap_socket(socket.socket(), + server_hostname=hostname, + suppress_ragged_eofs=False) as s: +- # TLS 1.3 perform client cert exchange after handshake + s.connect((HOST, server.port)) +- try: ++ with self.assertRaisesRegex( ++ 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') + s.read(1000) + s.write(b'should have failed already') + s.read(1000) +- except ssl.SSLError as e: +- if support.verbose: +- sys.stdout.write("\nSSLError is %r\n" % e) +- except OSError as e: +- if e.errno != errno.ECONNRESET: +- raise +- if support.verbose: +- sys.stdout.write("\nsocket.error is %r\n" % e) +- else: +- self.fail("Use of invalid cert should have failed!") + + def test_rude_shutdown(self): + """A brutal shutdown of an SSL server should raise an OSError +@@ -4558,8 +4553,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 6852cc363b..91bf27bfef 100644 +--- a/Modules/_ssl.c ++++ b/Modules/_ssl.c +@@ -582,7 +582,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; +@@ -595,7 +595,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) { +@@ -628,32 +627,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_SYS) { +@@ -1014,7 +1002,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; +@@ -2433,7 +2421,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); +@@ -2463,7 +2451,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); + } +@@ -2585,7 +2573,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) +@@ -2709,7 +2697,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.10.spec b/python3.10.spec index 0512cb9..b91f16c 100644 --- a/python3.10.spec +++ b/python3.10.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 @@ -286,8 +286,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 # 8448a0d6edd44d0818b8c02dc603b769b5363e5b @@ -349,6 +348,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 # f0db87ee65704fa5545ea25f2cca8c43fc639fab +# 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., @@ -1635,6 +1647,10 @@ CheckPython optimized # ====================================================== %changelog +* Tue May 13 2025 Charalampos Stratakis - 3.10.17-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.10.17-2 - test_ssl: Don't stop ThreadedEchoServer on OSError in ConnectionHandler - Fixes: rhbz#2355052 From 6c238008d198b1eba6f88c3fcec17d99b94e1f9b 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:39:00 +0200 Subject: [PATCH 02/20] Update to 3.10.18 --- ...rver-on-oserror-in-connectionhandler.patch | 80 ------------------- python3.10.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 ab62987..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 a1a581a907..0f1397de73 100644 ---- a/Lib/test/test_ssl.py -+++ b/Lib/test/test_ssl.py -@@ -2488,7 +2488,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: -@@ -2623,10 +2622,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, -@@ -2660,21 +2655,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.10.spec b/python3.10.spec index b91f16c..b722825 100644 --- a/python3.10.spec +++ b/python3.10.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}.17 +%global general_version %{pybasever}.18 #global prerel ... %global upstream_version %{general_version}%{?prerel} Version: %{general_version}%{?prerel:~%{prerel}} -Release: 3%{?dist} +Release: 1%{?dist} License: Python-2.0.1 @@ -333,21 +333,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 # f0db87ee65704fa5545ea25f2cca8c43fc639fab # Fix PySSL_SetError handling SSL_ERROR_SYSCALL # @@ -1647,6 +1632,9 @@ CheckPython optimized # ====================================================== %changelog +* Wed Jun 04 2025 Tomáš Hrnčiar - 3.10.18-1 +- Update to 3.10.18 + * Tue May 13 2025 Charalampos Stratakis - 3.10.17-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 7d7438b..64bd7d3 100644 --- a/sources +++ b/sources @@ -1,2 +1,2 @@ -SHA512 (Python-3.10.17.tar.xz) = 11b1e647f8db05041bcafe110698af8bf5e9f7c8d23c0e9eb568a60544bb9a9e9c3ac94b34f0898f0d4e6c23da3cb81f844ae9d9c8b750058763502eaba39880 -SHA512 (Python-3.10.17.tar.xz.asc) = f5fea78e2ea413c9befb6181787b3a5ea3bc0f5dbf808a94465b558c09353482cd34631a4c505f72aa343a2f4fae291453324cd8e6b18df214baaf4680fc17cf +SHA512 (Python-3.10.18.tar.xz) = 2c444f024cd15babd156964b50aa0245020a17c0c600250ffcf112e91594a3d6e1fb87c9b87a57cb7a802dae90004d801ed95a3103d79aefb8ed714279997708 +SHA512 (Python-3.10.18.tar.xz.asc) = dbe1426b1b8371bf390b53595d2c656fbd311fed55ad3c705e175fa0c72d51a022f286877ec55ad74547a3b57ae945c9af7ece4dacc7132e21b9b7eb4421add6 From ec3cbfebe9b9284a1b03109477aa73457b07447d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Thu, 26 Jun 2025 13:13:07 +0200 Subject: [PATCH 03/20] Fixup the patch 1 commit message after the importpatches/exportpatches change This fixes up 772c5976f4261a78d3bd7af3ab4331adccf5f9fe + 75538d3684a89581b6b85a5336f0cd6a4f19619e. --- 00001-rpath.patch | 3 ++- python3.10.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.10.spec b/python3.10.spec index b722825..64ead49 100644 --- a/python3.10.spec +++ b/python3.10.spec @@ -286,7 +286,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 # 8448a0d6edd44d0818b8c02dc603b769b5363e5b From 9d6cf58680bd1e6b1724e619140915f784e59437 Mon Sep 17 00:00:00 2001 From: Fedora Release Engineering Date: Fri, 25 Jul 2025 11:18:56 +0000 Subject: [PATCH 04/20] Rebuilt for https://fedoraproject.org/wiki/Fedora_43_Mass_Rebuild --- python3.10.spec | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/python3.10.spec b/python3.10.spec index 64ead49..9e6fd43 100644 --- a/python3.10.spec +++ b/python3.10.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 @@ -1634,6 +1634,9 @@ CheckPython optimized # ====================================================== %changelog +* Fri Jul 25 2025 Fedora Release Engineering - 3.10.18-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_43_Mass_Rebuild + * Wed Jun 04 2025 Tomáš Hrnčiar - 3.10.18-1 - Update to 3.10.18 From 207259522d0b3054a2128fad5695067bda8bd0c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Zachar?= Date: Fri, 25 Jul 2025 13:33:03 +0200 Subject: [PATCH 05/20] Drop STI and use tmt instead Resolves: rhbz#2383056 --- {tests/.fmf => .fmf}/version | 0 plan.fmf | 61 ++++++++++++++++++++++++++++++++++++ tests/provision.fmf | 4 --- tests/tests.yml | 55 -------------------------------- 4 files changed, 61 insertions(+), 59 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..71f3e63 --- /dev/null +++ b/plan.fmf @@ -0,0 +1,61 @@ +execute: + how: tmt + +provision: + hardware: + memory: '>= 3 GB' + +environment: + pybasever: '3.10' + +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='' ./parallel.sh" + - name: debugtest + path: /selftest + test: "VERSION=${pybasever} PYTHON=python${pybasever}d X='' ./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 + - "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 460b4a1..0000000 --- a/tests/tests.yml +++ /dev/null @@ -1,55 +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.10" - 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='' ./parallel.sh" - - debugtest: - dir: python/selftest - run: "VERSION={{ pybasever }} PYTHON=python{{ pybasever }}d X='' ./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 - - 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 b1fc74dd76704c00bde4673ae6520484d77e1dca Mon Sep 17 00:00:00 2001 From: Lumir Balhar Date: Tue, 26 Aug 2025 10:01:22 +0200 Subject: [PATCH 06/20] 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 a3bdce551cae631446ca1d887cf1c58cbaf31b45 Mon Sep 17 00:00:00 2001 From: Karolina Surma Date: Fri, 10 Oct 2025 14:22:08 +0200 Subject: [PATCH 07/20] Update to Python 3.10.19 --- python3.10.spec | 9 ++++++--- sources | 4 ++-- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/python3.10.spec b/python3.10.spec index 9e6fd43..ed7b1b6 100644 --- a/python3.10.spec +++ b/python3.10.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}.18 +%global general_version %{pybasever}.19 #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 23.0.1 -%global setuptools_version 65.5.0 +%global setuptools_version 79.0.1 # Expensive optimizations (mainly, profile-guided optimizations) %bcond_without optimizations @@ -1634,6 +1634,9 @@ CheckPython optimized # ====================================================== %changelog +* Fri Oct 10 2025 Karolina Surma - 3.10.19-1 +- Update to Python 3.10.19 + * Fri Jul 25 2025 Fedora Release Engineering - 3.10.18-2 - Rebuilt for https://fedoraproject.org/wiki/Fedora_43_Mass_Rebuild diff --git a/sources b/sources index 64bd7d3..6de6cda 100644 --- a/sources +++ b/sources @@ -1,2 +1,2 @@ -SHA512 (Python-3.10.18.tar.xz) = 2c444f024cd15babd156964b50aa0245020a17c0c600250ffcf112e91594a3d6e1fb87c9b87a57cb7a802dae90004d801ed95a3103d79aefb8ed714279997708 -SHA512 (Python-3.10.18.tar.xz.asc) = dbe1426b1b8371bf390b53595d2c656fbd311fed55ad3c705e175fa0c72d51a022f286877ec55ad74547a3b57ae945c9af7ece4dacc7132e21b9b7eb4421add6 +SHA512 (Python-3.10.19.tar.xz) = 9ea1e952bb5f7c9cc8d3efd8e7ae0059c129b6e09d12ded7d4e22476fad35f2c8186b1e003ea35a0099ffa5ff0a114985c3e960fba84e7037670b840a3e19c68 +SHA512 (Python-3.10.19.tar.xz.asc) = 64bcee68c2f4e0718daaf19d405f4a5bd0ce3fc3d13bb5cbae8d4a36e419dd104c94323b497f1d06110f6b62a1b3b351279c534145f4e8cea9af0d7bb0a8b5c9 From bd23e23416c9d72129581321bfdc90b279c93f28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Fri, 5 Sep 2025 11:41:55 +0000 Subject: [PATCH 08/20] Inject SBOM into the installed wheels (when using the bundled ones) --- python3.10.spec | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/python3.10.spec b/python3.10.spec index ed7b1b6..2c5aee0 100644 --- a/python3.10.spec +++ b/python3.10.spec @@ -246,6 +246,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} @@ -1064,6 +1067,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 14cfcd8b1f83f11d889d8531d462f43a987d5f50 Mon Sep 17 00:00:00 2001 From: Karolina Surma Date: Tue, 6 Jan 2026 17:53:12 +0100 Subject: [PATCH 09/20] 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 generated version will always match at least the one present in the buildroot during the Python build. --- python3.10.spec | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/python3.10.spec b/python3.10.spec index 2c5aee0..6a4fa7e 100644 --- a/python3.10.spec +++ b/python3.10.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++ @@ -497,12 +496,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} + # Since patch 251 changed from distutils to sysconfig, pip needed to be adapted # The previous versions could cause serious bugs during `sudo pip install --upgrade ...` @@ -1642,6 +1649,9 @@ CheckPython optimized # ====================================================== %changelog +* Tue Jan 06 2026 Karolina Surma - 3.10.19-2 +- Require at least the same expat version as used during the build time + * Fri Oct 10 2025 Karolina Surma - 3.10.19-1 - Update to Python 3.10.19 From 311900d817ce3e8b6439334b7140e827753ca833 Mon Sep 17 00:00:00 2001 From: Karolina Surma Date: Mon, 12 Jan 2026 11:55:39 +0100 Subject: [PATCH 10/20] Extend the expat requirement to differentiate between 32 and 64 arches (cherry picked from python3.15 commit a5ca170d3f1e6e19f5df66f21482c2b10593af42) --- python3.10.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python3.10.spec b/python3.10.spec index 6a4fa7e..2691ab5 100644 --- a/python3.10.spec +++ b/python3.10.spec @@ -508,7 +508,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} # Since patch 251 changed from distutils to sysconfig, pip needed to be adapted From 6c0fab4bc9126543051bdacd26cd75d3d8918b2d Mon Sep 17 00:00:00 2001 From: Fedora Release Engineering Date: Sat, 17 Jan 2026 10:39:54 +0000 Subject: [PATCH 11/20] Rebuilt for https://fedoraproject.org/wiki/Fedora_44_Mass_Rebuild --- python3.10.spec | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/python3.10.spec b/python3.10.spec index 2691ab5..de79e10 100644 --- a/python3.10.spec +++ b/python3.10.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 @@ -1649,6 +1649,9 @@ CheckPython optimized # ====================================================== %changelog +* Sat Jan 17 2026 Fedora Release Engineering - 3.10.19-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_44_Mass_Rebuild + * Tue Jan 06 2026 Karolina Surma - 3.10.19-2 - Require at least the same expat version as used during the build time From e0dac6a2c5af911856a043bb5280c77a2494b3c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Hrn=C4=8Diar?= Date: Mon, 9 Feb 2026 10:38:43 +0100 Subject: [PATCH 12/20] 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.10.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..3504e6b --- /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 0d3b9634f1..d0492fe191 100644 +--- a/Lib/test/support/__init__.py ++++ b/Lib/test/support/__init__.py +@@ -2157,3 +2157,10 @@ def adjust_int_max_str_digits(max_digits): + yield + finally: + sys.set_int_max_str_digits(current) ++ ++ ++def control_characters_c0() -> list[str]: ++ """Returns a list of C0 control characters as strings. ++ C0 control characters defined as the byte range 0x00-0x1F, and 0x7F. ++ """ ++ return [chr(c) for c in range(0x00, 0x20)] + ["\x7F"] +diff --git a/Lib/test/test_wsgiref.py b/Lib/test/test_wsgiref.py +index 42094f4677..01ca51ba45 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.support import warnings_helper + from test.test_httpservers import NoLogRequestHandler + from unittest import TestCase +@@ -527,6 +527,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..0b4fd18 --- /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 54122f985b..9ab8e43bbf 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 f817707743..9ce59b3040 100644 +--- a/Lib/test/test_imaplib.py ++++ b/Lib/test/test_imaplib.py +@@ -505,6 +505,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..9a64894 --- /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 1220ca32ef..2655e366fd 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 +@@ -365,6 +366,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.10.spec b/python3.10.spec index de79e10..0a4531b 100644 --- a/python3.10.spec +++ b/python3.10.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 @@ -350,6 +350,31 @@ 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 +# 00473 # e0df4af4663a200a370a7c7b2391588396bcf20f +# 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., @@ -1649,6 +1674,9 @@ CheckPython optimized # ====================================================== %changelog +* Mon Feb 09 2026 Tomáš Hrnčiar - 3.10.19-4 +- Security fixes for CVE-2026-0865, CVE-2025-15366 and CVE-2025-15367 + * Sat Jan 17 2026 Fedora Release Engineering - 3.10.19-3 - Rebuilt for https://fedoraproject.org/wiki/Fedora_44_Mass_Rebuild From c9e6166456a3fea8d2a44bb6ecdb528bd274e8e1 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:17:40 +0100 Subject: [PATCH 13/20] Update to 3.10.20 --- ..._seterror-handling-ssl_error_syscall.patch | 2 +- 00473-cve-2026-0865.patch | 90 ------------------- python3.10.spec | 16 ++-- sources | 4 +- 4 files changed, 8 insertions(+), 104 deletions(-) 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 5c0cda1..fcf142f 100644 --- a/00462-fix-pyssl_seterror-handling-ssl_error_syscall.patch +++ b/00462-fix-pyssl_seterror-handling-ssl_error_syscall.patch @@ -102,7 +102,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 6852cc363b..91bf27bfef 100644 +index 3bd8b96dcc..6f5fb23b8b 100644 --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -582,7 +582,7 @@ PySSL_ChainExceptions(PySSLSocket *sslsock) { diff --git a/00473-cve-2026-0865.patch b/00473-cve-2026-0865.patch deleted file mode 100644 index 3504e6b..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 0d3b9634f1..d0492fe191 100644 ---- a/Lib/test/support/__init__.py -+++ b/Lib/test/support/__init__.py -@@ -2157,3 +2157,10 @@ def adjust_int_max_str_digits(max_digits): - yield - finally: - sys.set_int_max_str_digits(current) -+ -+ -+def control_characters_c0() -> list[str]: -+ """Returns a list of C0 control characters as strings. -+ C0 control characters defined as the byte range 0x00-0x1F, and 0x7F. -+ """ -+ return [chr(c) for c in range(0x00, 0x20)] + ["\x7F"] -diff --git a/Lib/test/test_wsgiref.py b/Lib/test/test_wsgiref.py -index 42094f4677..01ca51ba45 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.support import warnings_helper - from test.test_httpservers import NoLogRequestHandler - from unittest import TestCase -@@ -527,6 +527,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.10.spec b/python3.10.spec index 0a4531b..ddee0fe 100644 --- a/python3.10.spec +++ b/python3.10.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}.19 +%global general_version %{pybasever}.20 #global prerel ... %global upstream_version %{general_version}%{?prerel} Version: %{general_version}%{?prerel:~%{prerel}} -Release: 4%{?dist} +Release: 1%{?dist} License: Python-2.0.1 @@ -350,15 +350,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 -# 00473 # e0df4af4663a200a370a7c7b2391588396bcf20f -# 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 # @@ -1674,6 +1665,9 @@ CheckPython optimized # ====================================================== %changelog +* Tue Mar 03 2026 Tomáš Hrnčiar - 3.10.20-1 +- Update to 3.10.20 + * Mon Feb 09 2026 Tomáš Hrnčiar - 3.10.19-4 - Security fixes for CVE-2026-0865, CVE-2025-15366 and CVE-2025-15367 diff --git a/sources b/sources index 6de6cda..073dea3 100644 --- a/sources +++ b/sources @@ -1,2 +1,2 @@ -SHA512 (Python-3.10.19.tar.xz) = 9ea1e952bb5f7c9cc8d3efd8e7ae0059c129b6e09d12ded7d4e22476fad35f2c8186b1e003ea35a0099ffa5ff0a114985c3e960fba84e7037670b840a3e19c68 -SHA512 (Python-3.10.19.tar.xz.asc) = 64bcee68c2f4e0718daaf19d405f4a5bd0ce3fc3d13bb5cbae8d4a36e419dd104c94323b497f1d06110f6b62a1b3b351279c534145f4e8cea9af0d7bb0a8b5c9 +SHA512 (Python-3.10.20.tar.xz) = 591d3acf7ef47307b8c58fec9516731b374bcdf6eb21883410f67402f823a183f1abffec1116583e394610730f414d5a98b4c3437ea5174a4d2adbb99b8f6e5b +SHA512 (Python-3.10.20.tar.xz.asc) = cb90ce514c63c63adc10cbb3db778eae626b922461715954daf08b3a3a99b8b4c750fded624787b7d28fc10a203b0e0e5494b91e5305ef56a23fda46c023c203 From 458effe6fa67601a6c8dbc89c8ea31630a0cdb54 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 14/20] Explicitly build with OpenSSL 3 for now https://fedoraproject.org/wiki/Changes/OpenSSL40 --- python3.10.spec | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/python3.10.spec b/python3.10.spec index ddee0fe..b076721 100644 --- a/python3.10.spec +++ b/python3.10.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 @@ -216,7 +216,6 @@ BuildRequires: make BuildRequires: mpdecimal-devel BuildRequires: ncurses-devel -BuildRequires: openssl-devel BuildRequires: pkgconfig BuildRequires: readline-devel BuildRequires: redhat-rpm-config >= 127 @@ -229,6 +228,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 @@ -1665,6 +1668,9 @@ CheckPython optimized # ====================================================== %changelog +* Sat Apr 11 2026 Miro Hrončok - 3.10.20-2 +- Explicitly build with OpenSSL 3 + * Tue Mar 03 2026 Tomáš Hrnčiar - 3.10.20-1 - Update to 3.10.20 From 16aa6aa9ffefb7c724be998444c3d6a41f393827 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Thu, 2 Jul 2026 10:59:38 +0200 Subject: [PATCH 15/20] Fix ssl.SSLError: [ASN1: NOT_ENOUGH_DATA] not enough data with OpenSSL 3.5.7+ --- 00489-openssl-3.5.7.patch | 75 +++++++++++++++++++++++++++++++++++++++ python3.10.spec | 13 +++++++ 2 files changed, 88 insertions(+) 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..ea5bf03 --- /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 21d3676c22..f772bd6ab6 100644 +--- a/Lib/test/test_ssl.py ++++ b/Lib/test/test_ssl.py +@@ -1533,6 +1533,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 6f5fb23b8b..7b3cf61474 100644 +--- a/Modules/_ssl.c ++++ b/Modules/_ssl.c +@@ -3949,7 +3949,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); + +@@ -3977,6 +3977,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, +@@ -4012,9 +4016,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.10.spec b/python3.10.spec index b076721..53f3806 100644 --- a/python3.10.spec +++ b/python3.10.spec @@ -369,6 +369,18 @@ Patch474: 00474-cve-2025-15366.patch # (cherry-picked from commit b234a2b67539f787e191d2ef19a7cbdce32874e7) Patch475: 00475-cve-2025-15367.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., @@ -1670,6 +1682,7 @@ CheckPython optimized %changelog * Sat Apr 11 2026 Miro Hrončok - 3.10.20-2 - Explicitly build with OpenSSL 3 +- Fix ssl.SSLError: [ASN1: NOT_ENOUGH_DATA] not enough data with OpenSSL 3.5.7+ * Tue Mar 03 2026 Tomáš Hrnčiar - 3.10.20-1 - Update to 3.10.20 From e6d9413cd5d26f89148ae857642b9a1921465822 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lum=C3=ADr=20Balhar?= Date: Wed, 1 Jul 2026 10:55:23 +0000 Subject: [PATCH 16/20] 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 71f3e63..88053e4 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 @@ -50,8 +53,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 c30eb404789121d3ed86e736ccdf5952df55279a Mon Sep 17 00:00:00 2001 From: Fedora Release Engineering Date: Thu, 16 Jul 2026 22:47:20 +0000 Subject: [PATCH 17/20] Rebuilt for https://fedoraproject.org/wiki/Fedora_45_Mass_Rebuild --- python3.10.spec | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/python3.10.spec b/python3.10.spec index 53f3806..85c416e 100644 --- a/python3.10.spec +++ b/python3.10.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 @@ -1680,6 +1680,9 @@ CheckPython optimized # ====================================================== %changelog +* Thu Jul 16 2026 Fedora Release Engineering - 3.10.20-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_45_Mass_Rebuild + * Sat Apr 11 2026 Miro Hrončok - 3.10.20-2 - Explicitly build with OpenSSL 3 - Fix ssl.SSLError: [ASN1: NOT_ENOUGH_DATA] not enough data with OpenSSL 3.5.7+ From 7da201e90094c47501dcb1ee89872aef1884f4a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Thu, 30 Jul 2026 17:25:58 +0200 Subject: [PATCH 18/20] 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.10.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..bf0a459 --- /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 15f7fb4a80..4a3d8f7ce6 100644 +--- a/Lib/test/test_socket.py ++++ b/Lib/test/test_socket.py +@@ -142,6 +142,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() +@@ -166,7 +186,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.10.spec b/python3.10.spec index 85c416e..d06a2f6 100644 --- a/python3.10.spec +++ b/python3.10.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 @@ -381,6 +381,13 @@ Patch475: 00475-cve-2025-15367.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., @@ -1680,6 +1687,10 @@ CheckPython optimized # ====================================================== %changelog +* Thu Jul 30 2026 Miro Hrončok - 3.10.20-4 + - 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.10.20-3 - Rebuilt for https://fedoraproject.org/wiki/Fedora_45_Mass_Rebuild From b4205523e70d79d5be55bc4d9368bbe1cbceddcb 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 19/20] 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.10.spec | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/python3.10.spec b/python3.10.spec index d06a2f6..97d0e29 100644 --- a/python3.10.spec +++ b/python3.10.spec @@ -545,8 +545,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 # Since patch 251 changed from distutils to sysconfig, pip needed to be adapted From daba5b738caf36d3903f98c1c65be5efbcfa658a Mon Sep 17 00:00:00 2001 From: Karolina Surma Date: Thu, 13 Aug 2026 12:14:24 +0200 Subject: [PATCH 20/20] Update to Python 3.10.21 --- ..._seterror-handling-ssl_error_syscall.patch | 10 +-- 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.10.spec | 28 +++---- sources | 4 +- 6 files changed, 39 insertions(+), 165 deletions(-) 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/00462-fix-pyssl_seterror-handling-ssl_error_syscall.patch b/00462-fix-pyssl_seterror-handling-ssl_error_syscall.patch index fcf142f..1eaf3a2 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 0f1397de73..21d3676c22 100644 +index f4bba8ff03..f772bd6ab6 100644 --- a/Lib/test/test_ssl.py +++ b/Lib/test/test_ssl.py -@@ -2605,16 +2605,18 @@ def run(self): +@@ -2607,16 +2607,18 @@ def run(self): self.write(msg.lower()) except OSError as e: # handles SSLError and socket errors @@ -53,7 +53,7 @@ index 0f1397de73..21d3676c22 100644 try: self.write(b"ERROR\n") except OSError: -@@ -3296,23 +3298,16 @@ def test_wrong_cert_tls13(self): +@@ -3298,23 +3300,16 @@ def test_wrong_cert_tls13(self): client_context.wrap_socket(socket.socket(), server_hostname=hostname, suppress_ragged_eofs=False) as s: @@ -82,7 +82,7 @@ index 0f1397de73..21d3676c22 100644 def test_rude_shutdown(self): """A brutal shutdown of an SSL server should raise an OSError -@@ -4558,8 +4553,8 @@ def msg_cb(conn, direction, version, content_type, msg_type, data): +@@ -4560,8 +4555,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( @@ -102,7 +102,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 3bd8b96dcc..6f5fb23b8b 100644 +index af770c7f18..7b3cf61474 100644 --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -582,7 +582,7 @@ PySSL_ChainExceptions(PySSLSocket *sslsock) { diff --git a/00489-openssl-3.5.7.patch b/00489-openssl-3.5.7.patch deleted file mode 100644 index ea5bf03..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 21d3676c22..f772bd6ab6 100644 ---- a/Lib/test/test_ssl.py -+++ b/Lib/test/test_ssl.py -@@ -1533,6 +1533,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 6f5fb23b8b..7b3cf61474 100644 ---- a/Modules/_ssl.c -+++ b/Modules/_ssl.c -@@ -3949,7 +3949,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); - -@@ -3977,6 +3977,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, -@@ -4012,9 +4016,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 bf0a459..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 15f7fb4a80..4a3d8f7ce6 100644 ---- a/Lib/test/test_socket.py -+++ b/Lib/test/test_socket.py -@@ -142,6 +142,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() -@@ -166,7 +186,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..58ffd5d --- /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 5eb3c82fbd..aa8ad1c323 100644 +--- a/Lib/test/test_httpservers.py ++++ b/Lib/test/test_httpservers.py +@@ -872,7 +872,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.10.spec b/python3.10.spec index 97d0e29..3378bf7 100644 --- a/python3.10.spec +++ b/python3.10.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}.20 +%global general_version %{pybasever}.21 #global prerel ... %global upstream_version %{general_version}%{?prerel} Version: %{general_version}%{?prerel:~%{prerel}} -Release: 4%{?dist} +Release: 1%{?dist} License: Python-2.0.1 @@ -369,24 +369,11 @@ Patch474: 00474-cve-2025-15366.patch # (cherry-picked from commit b234a2b67539f787e191d2ef19a7cbdce32874e7) Patch475: 00475-cve-2025-15367.patch -# 00489 # 008af720a5f6f98ed3feb8ebdbf88ab9dea4db22 -# Use BIO_eof to detect EOF for SSL_FILETYPE_ASN1 +# 00494 # 430aab133397ed44cc9ee621fd311e02fee317b5 +# Increase the timeout of test_large_content_length_truncated # -# 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 ^^^) # @@ -1691,6 +1678,9 @@ CheckPython optimized # ====================================================== %changelog +* Thu Aug 13 2026 Karolina Surma - 3.10.21-1 +- Update to Python 3.10.21 + * Thu Jul 30 2026 Miro Hrončok - 3.10.20-4 - 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 073dea3..1833fd0 100644 --- a/sources +++ b/sources @@ -1,2 +1,2 @@ -SHA512 (Python-3.10.20.tar.xz) = 591d3acf7ef47307b8c58fec9516731b374bcdf6eb21883410f67402f823a183f1abffec1116583e394610730f414d5a98b4c3437ea5174a4d2adbb99b8f6e5b -SHA512 (Python-3.10.20.tar.xz.asc) = cb90ce514c63c63adc10cbb3db778eae626b922461715954daf08b3a3a99b8b4c750fded624787b7d28fc10a203b0e0e5494b91e5305ef56a23fda46c023c203 +SHA512 (Python-3.10.21.tar.xz) = 6f6de7c5e4c0457f2d189ed5d111c83fb8775e19123afe4f9fd0ae2b93f3fa2bbb7ad849ade6bb5227d4a6a3d63abc8e167fbe5fb54fa715660c89fd6274daee +SHA512 (Python-3.10.21.tar.xz.asc) = 72d6aeaa0f51e527f82392cf1f969b0ad50a48fe10e8b7e5feb6117718223d00757f7b375b3ac82e257571d5a61f8162e9dd59b81fcf8f2a441c6deb42be71cb