Compare commits

..

No commits in common. 'c9-beta' and 'cs10' have entirely different histories.

2
.gitignore vendored

@ -1 +1 @@
SOURCES/Python-3.12.5.tar.xz
SOURCES/Python-3.12.6.tar.xz

@ -1 +1 @@
d9b83c17a717e1cbd3ab6bd14cfe3e508e6d87b2 SOURCES/Python-3.12.5.tar.xz
6d2bbe1603b01764c541608938766233bf56f780 SOURCES/Python-3.12.6.tar.xz

@ -1,4 +1,4 @@
From 43ce74d971fad62db6ccd723fe6b01da9c7ff407 Mon Sep 17 00:00:00 2001
From d307f5706434e0cb445fb48291852bd7ec46ddbd Mon Sep 17 00:00:00 2001
From: Charalampos Stratakis <cstratak@redhat.com>
Date: Thu, 12 Dec 2019 16:58:31 +0100
Subject: [PATCH 1/5] Expose blake2b and blake2s hashes from OpenSSL
@ -254,7 +254,7 @@ index fb61a44..1e42b87 100644
2.45.0
From 6872b634078a2c69644235781ebffb07f8edcb83 Mon Sep 17 00:00:00 2001
From c247ff164269fb68236a79a1359cc37c1a8a0004 Mon Sep 17 00:00:00 2001
From: Petr Viktorin <pviktori@redhat.com>
Date: Thu, 25 Jul 2019 17:19:06 +0200
Subject: [PATCH 2/5] Disable Python's hash implementations in FIPS mode,
@ -445,10 +445,10 @@ index a8bad9d..1b1d937 100644
+ if (_Py_hashlib_fips_error(exc, name)) return NULL; \
+} while (0)
diff --git a/configure.ac b/configure.ac
index 65ad1c2..b5f9ab5 100644
index 384718d..c4a1198 100644
--- a/configure.ac
+++ b/configure.ac
@@ -7463,7 +7463,8 @@ PY_STDLIB_MOD([_sha2],
@@ -7445,7 +7445,8 @@ PY_STDLIB_MOD([_sha2],
PY_STDLIB_MOD([_sha3], [test "$with_builtin_sha3" = yes])
PY_STDLIB_MOD([_blake2],
[test "$with_builtin_blake2" = yes], [],
@ -462,7 +462,7 @@ index 65ad1c2..b5f9ab5 100644
2.45.0
From f904abdd7a607282c2cdfd18288045cedfa28414 Mon Sep 17 00:00:00 2001
From e58b32f238f1d4503248f3a8b1489f7567bdbd6d Mon Sep 17 00:00:00 2001
From: Charalampos Stratakis <cstratak@redhat.com>
Date: Fri, 29 Jan 2021 14:16:21 +0100
Subject: [PATCH 3/5] Use python's fall back crypto implementations only if we
@ -555,7 +555,7 @@ index dd61a9a..6031b02 100644
2.45.0
From 9bf0a53b7831409613c44fd7feecb56476f5e5e7 Mon Sep 17 00:00:00 2001
From 2b14d347948dc01af587b9e21cd448833a38c7b5 Mon Sep 17 00:00:00 2001
From: Charalampos Stratakis <cstratak@redhat.com>
Date: Wed, 31 Jul 2019 15:43:43 +0200
Subject: [PATCH 4/5] Test equivalence of hashes for the various digests with
@ -715,18 +715,18 @@ index 6031b02..5bd5297 100644
2.45.0
From 8a76571515a64a57b4ea0586ae8376cf2ef0ac60 Mon Sep 17 00:00:00 2001
From b98c72b356a529a68cb4216526b838a57937cf6f Mon Sep 17 00:00:00 2001
From: Petr Viktorin <pviktori@redhat.com>
Date: Mon, 26 Aug 2019 19:39:48 +0200
Subject: [PATCH 5/5] Guard against Python HMAC in FIPS mode
---
Lib/hmac.py | 13 +++++++++----
Lib/hmac.py | 12 +++++++++---
Lib/test/test_hmac.py | 10 ++++++++++
2 files changed, 19 insertions(+), 4 deletions(-)
2 files changed, 19 insertions(+), 3 deletions(-)
diff --git a/Lib/hmac.py b/Lib/hmac.py
index 8b4eb2f..e8e4864 100644
index 8b4eb2f..8930bda 100644
--- a/Lib/hmac.py
+++ b/Lib/hmac.py
@@ -16,8 +16,9 @@ else:
@ -741,14 +741,7 @@ index 8b4eb2f..e8e4864 100644
# The size of the digests returned by HMAC depends on the underlying
# hashing module used. Use digest_size from the instance of HMAC instead.
@@ -48,17 +49,18 @@ class HMAC:
msg argument. Passing it as a keyword argument is
recommended, though not required for legacy API reasons.
"""
-
if not isinstance(key, (bytes, bytearray)):
raise TypeError("key: expected bytes or bytearray, but got %r" % type(key).__name__)
@@ -55,10 +56,12 @@ class HMAC:
if not digestmod:
raise TypeError("Missing required argument 'digestmod'.")
@ -762,7 +755,7 @@ index 8b4eb2f..e8e4864 100644
self._init_old(key, msg, digestmod)
else:
self._init_old(key, msg, digestmod)
@@ -69,6 +71,9 @@ class HMAC:
@@ -69,6 +72,9 @@ class HMAC:
self.block_size = self._hmac.block_size
def _init_old(self, key, msg, digestmod):
@ -773,7 +766,7 @@ index 8b4eb2f..e8e4864 100644
digest_cons = digestmod
elif isinstance(digestmod, str):
diff --git a/Lib/test/test_hmac.py b/Lib/test/test_hmac.py
index 1502fba..7997073 100644
index a39a2c4..b7b24ab 100644
--- a/Lib/test/test_hmac.py
+++ b/Lib/test/test_hmac.py
@@ -5,6 +5,7 @@ import hashlib
@ -812,7 +805,7 @@ index 1502fba..7997073 100644
@unittest.skipUnless(sha256_module is not None, 'need _sha256')
def test_with_sha256_module(self):
h = hmac.HMAC(b"key", b"hash this!", digestmod=sha256_module.sha256)
@@ -489,6 +497,7 @@ class UpdateTestCase(unittest.TestCase):
@@ -481,6 +489,7 @@ class SanityTestCase(unittest.TestCase):
class CopyTestCase(unittest.TestCase):
@ -820,7 +813,7 @@ index 1502fba..7997073 100644
@hashlib_helper.requires_hashdigest('sha256')
def test_attributes_old(self):
# Testing if attributes are of same type.
@@ -500,6 +509,7 @@ class CopyTestCase(unittest.TestCase):
@@ -492,6 +501,7 @@ class CopyTestCase(unittest.TestCase):
self.assertEqual(type(h1._outer), type(h2._outer),
"Types of outer don't match.")

@ -1,483 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Victor Stinner <vstinner@python.org>
Date: Fri, 15 Dec 2023 16:10:40 +0100
Subject: [PATCH] 00415: [CVE-2023-27043] gh-102988: Reject malformed addresses
in email.parseaddr() (#111116)
Detect email address parsing errors and return empty tuple to
indicate the parsing error (old API). Add an optional 'strict'
parameter to getaddresses() and parseaddr() functions. Patch by
Thomas Dwyer.
Co-Authored-By: Thomas Dwyer <github@tomd.tel>
---
Doc/library/email.utils.rst | 19 +-
Lib/email/utils.py | 151 +++++++++++++-
Lib/test/test_email/test_email.py | 187 +++++++++++++++++-
...-10-20-15-28-08.gh-issue-102988.dStNO7.rst | 8 +
4 files changed, 344 insertions(+), 21 deletions(-)
create mode 100644 Misc/NEWS.d/next/Library/2023-10-20-15-28-08.gh-issue-102988.dStNO7.rst
diff --git a/Doc/library/email.utils.rst b/Doc/library/email.utils.rst
index 6ba42491d6..6bd45200d8 100644
--- a/Doc/library/email.utils.rst
+++ b/Doc/library/email.utils.rst
@@ -58,13 +58,18 @@ of the new API.
begins with angle brackets, they are stripped off.
-.. function:: parseaddr(address)
+.. function:: parseaddr(address, *, strict=True)
Parse address -- which should be the value of some address-containing field such
as :mailheader:`To` or :mailheader:`Cc` -- into its constituent *realname* and
*email address* parts. Returns a tuple of that information, unless the parse
fails, in which case a 2-tuple of ``('', '')`` is returned.
+ If *strict* is true, use a strict parser which rejects malformed inputs.
+
+ .. versionchanged:: 3.13
+ Add *strict* optional parameter and reject malformed inputs by default.
+
.. function:: formataddr(pair, charset='utf-8')
@@ -82,12 +87,15 @@ of the new API.
Added the *charset* option.
-.. function:: getaddresses(fieldvalues)
+.. function:: getaddresses(fieldvalues, *, strict=True)
This method returns a list of 2-tuples of the form returned by ``parseaddr()``.
*fieldvalues* is a sequence of header field values as might be returned by
- :meth:`Message.get_all <email.message.Message.get_all>`. Here's a simple
- example that gets all the recipients of a message::
+ :meth:`Message.get_all <email.message.Message.get_all>`.
+
+ If *strict* is true, use a strict parser which rejects malformed inputs.
+
+ Here's a simple example that gets all the recipients of a message::
from email.utils import getaddresses
@@ -97,6 +105,9 @@ of the new API.
resent_ccs = msg.get_all('resent-cc', [])
all_recipients = getaddresses(tos + ccs + resent_tos + resent_ccs)
+ .. versionchanged:: 3.13
+ Add *strict* optional parameter and reject malformed inputs by default.
+
.. function:: parsedate(date)
diff --git a/Lib/email/utils.py b/Lib/email/utils.py
index 1de547a011..e53abc8b84 100644
--- a/Lib/email/utils.py
+++ b/Lib/email/utils.py
@@ -48,6 +48,7 @@
specialsre = re.compile(r'[][\\()<>@,:;".]')
escapesre = re.compile(r'[\\"]')
+
def _has_surrogates(s):
"""Return True if s may contain surrogate-escaped binary data."""
# This check is based on the fact that unless there are surrogates, utf8
@@ -106,12 +107,127 @@ def formataddr(pair, charset='utf-8'):
return address
+def _iter_escaped_chars(addr):
+ pos = 0
+ escape = False
+ for pos, ch in enumerate(addr):
+ if escape:
+ yield (pos, '\\' + ch)
+ escape = False
+ elif ch == '\\':
+ escape = True
+ else:
+ yield (pos, ch)
+ if escape:
+ yield (pos, '\\')
-def getaddresses(fieldvalues):
- """Return a list of (REALNAME, EMAIL) for each fieldvalue."""
- all = COMMASPACE.join(str(v) for v in fieldvalues)
- a = _AddressList(all)
- return a.addresslist
+
+def _strip_quoted_realnames(addr):
+ """Strip real names between quotes."""
+ if '"' not in addr:
+ # Fast path
+ return addr
+
+ start = 0
+ open_pos = None
+ result = []
+ for pos, ch in _iter_escaped_chars(addr):
+ if ch == '"':
+ if open_pos is None:
+ open_pos = pos
+ else:
+ if start != open_pos:
+ result.append(addr[start:open_pos])
+ start = pos + 1
+ open_pos = None
+
+ if start < len(addr):
+ result.append(addr[start:])
+
+ return ''.join(result)
+
+
+supports_strict_parsing = True
+
+def getaddresses(fieldvalues, *, strict=True):
+ """Return a list of (REALNAME, EMAIL) or ('','') for each fieldvalue.
+
+ When parsing fails for a fieldvalue, a 2-tuple of ('', '') is returned in
+ its place.
+
+ If strict is true, use a strict parser which rejects malformed inputs.
+ """
+
+ # If strict is true, if the resulting list of parsed addresses is greater
+ # than the number of fieldvalues in the input list, a parsing error has
+ # occurred and consequently a list containing a single empty 2-tuple [('',
+ # '')] is returned in its place. This is done to avoid invalid output.
+ #
+ # Malformed input: getaddresses(['alice@example.com <bob@example.com>'])
+ # Invalid output: [('', 'alice@example.com'), ('', 'bob@example.com')]
+ # Safe output: [('', '')]
+
+ if not strict:
+ all = COMMASPACE.join(str(v) for v in fieldvalues)
+ a = _AddressList(all)
+ return a.addresslist
+
+ fieldvalues = [str(v) for v in fieldvalues]
+ fieldvalues = _pre_parse_validation(fieldvalues)
+ addr = COMMASPACE.join(fieldvalues)
+ a = _AddressList(addr)
+ result = _post_parse_validation(a.addresslist)
+
+ # Treat output as invalid if the number of addresses is not equal to the
+ # expected number of addresses.
+ n = 0
+ for v in fieldvalues:
+ # When a comma is used in the Real Name part it is not a deliminator.
+ # So strip those out before counting the commas.
+ v = _strip_quoted_realnames(v)
+ # Expected number of addresses: 1 + number of commas
+ n += 1 + v.count(',')
+ if len(result) != n:
+ return [('', '')]
+
+ return result
+
+
+def _check_parenthesis(addr):
+ # Ignore parenthesis in quoted real names.
+ addr = _strip_quoted_realnames(addr)
+
+ opens = 0
+ for pos, ch in _iter_escaped_chars(addr):
+ if ch == '(':
+ opens += 1
+ elif ch == ')':
+ opens -= 1
+ if opens < 0:
+ return False
+ return (opens == 0)
+
+
+def _pre_parse_validation(email_header_fields):
+ accepted_values = []
+ for v in email_header_fields:
+ if not _check_parenthesis(v):
+ v = "('', '')"
+ accepted_values.append(v)
+
+ return accepted_values
+
+
+def _post_parse_validation(parsed_email_header_tuples):
+ accepted_values = []
+ # The parser would have parsed a correctly formatted domain-literal
+ # The existence of an [ after parsing indicates a parsing failure
+ for v in parsed_email_header_tuples:
+ if '[' in v[1]:
+ v = ('', '')
+ accepted_values.append(v)
+
+ return accepted_values
def _format_timetuple_and_zone(timetuple, zone):
@@ -205,16 +321,33 @@ def parsedate_to_datetime(data):
tzinfo=datetime.timezone(datetime.timedelta(seconds=tz)))
-def parseaddr(addr):
+def parseaddr(addr, *, strict=True):
"""
Parse addr into its constituent realname and email address parts.
Return a tuple of realname and email address, unless the parse fails, in
which case return a 2-tuple of ('', '').
+
+ If strict is True, use a strict parser which rejects malformed inputs.
"""
- addrs = _AddressList(addr).addresslist
- if not addrs:
- return '', ''
+ if not strict:
+ addrs = _AddressList(addr).addresslist
+ if not addrs:
+ return ('', '')
+ return addrs[0]
+
+ if isinstance(addr, list):
+ addr = addr[0]
+
+ if not isinstance(addr, str):
+ return ('', '')
+
+ addr = _pre_parse_validation([addr])[0]
+ addrs = _post_parse_validation(_AddressList(addr).addresslist)
+
+ if not addrs or len(addrs) > 1:
+ return ('', '')
+
return addrs[0]
diff --git a/Lib/test/test_email/test_email.py b/Lib/test/test_email/test_email.py
index fc8d87974e..ef8aa0d53c 100644
--- a/Lib/test/test_email/test_email.py
+++ b/Lib/test/test_email/test_email.py
@@ -16,6 +16,7 @@
import email
import email.policy
+import email.utils
from email.charset import Charset
from email.generator import Generator, DecodedGenerator, BytesGenerator
@@ -3352,15 +3353,137 @@ def test_getaddresses_comma_in_name(self):
],
)
+ def test_parsing_errors(self):
+ """Test for parsing errors from CVE-2023-27043 and CVE-2019-16056"""
+ alice = 'alice@example.org'
+ bob = 'bob@example.com'
+ empty = ('', '')
+
+ # Test utils.getaddresses() and utils.parseaddr() on malformed email
+ # addresses: default behavior (strict=True) rejects malformed address,
+ # and strict=False which tolerates malformed address.
+ for invalid_separator, expected_non_strict in (
+ ('(', [(f'<{bob}>', alice)]),
+ (')', [('', alice), empty, ('', bob)]),
+ ('<', [('', alice), empty, ('', bob), empty]),
+ ('>', [('', alice), empty, ('', bob)]),
+ ('[', [('', f'{alice}[<{bob}>]')]),
+ (']', [('', alice), empty, ('', bob)]),
+ ('@', [empty, empty, ('', bob)]),
+ (';', [('', alice), empty, ('', bob)]),
+ (':', [('', alice), ('', bob)]),
+ ('.', [('', alice + '.'), ('', bob)]),
+ ('"', [('', alice), ('', f'<{bob}>')]),
+ ):
+ address = f'{alice}{invalid_separator}<{bob}>'
+ with self.subTest(address=address):
+ self.assertEqual(utils.getaddresses([address]),
+ [empty])
+ self.assertEqual(utils.getaddresses([address], strict=False),
+ expected_non_strict)
+
+ self.assertEqual(utils.parseaddr([address]),
+ empty)
+ self.assertEqual(utils.parseaddr([address], strict=False),
+ ('', address))
+
+ # Comma (',') is treated differently depending on strict parameter.
+ # Comma without quotes.
+ address = f'{alice},<{bob}>'
+ self.assertEqual(utils.getaddresses([address]),
+ [('', alice), ('', bob)])
+ self.assertEqual(utils.getaddresses([address], strict=False),
+ [('', alice), ('', bob)])
+ self.assertEqual(utils.parseaddr([address]),
+ empty)
+ self.assertEqual(utils.parseaddr([address], strict=False),
+ ('', address))
+
+ # Real name between quotes containing comma.
+ address = '"Alice, alice@example.org" <bob@example.com>'
+ expected_strict = ('Alice, alice@example.org', 'bob@example.com')
+ self.assertEqual(utils.getaddresses([address]), [expected_strict])
+ self.assertEqual(utils.getaddresses([address], strict=False), [expected_strict])
+ self.assertEqual(utils.parseaddr([address]), expected_strict)
+ self.assertEqual(utils.parseaddr([address], strict=False),
+ ('', address))
+
+ # Valid parenthesis in comments.
+ address = 'alice@example.org (Alice)'
+ expected_strict = ('Alice', 'alice@example.org')
+ self.assertEqual(utils.getaddresses([address]), [expected_strict])
+ self.assertEqual(utils.getaddresses([address], strict=False), [expected_strict])
+ self.assertEqual(utils.parseaddr([address]), expected_strict)
+ self.assertEqual(utils.parseaddr([address], strict=False),
+ ('', address))
+
+ # Invalid parenthesis in comments.
+ address = 'alice@example.org )Alice('
+ self.assertEqual(utils.getaddresses([address]), [empty])
+ self.assertEqual(utils.getaddresses([address], strict=False),
+ [('', 'alice@example.org'), ('', ''), ('', 'Alice')])
+ self.assertEqual(utils.parseaddr([address]), empty)
+ self.assertEqual(utils.parseaddr([address], strict=False),
+ ('', address))
+
+ # Two addresses with quotes separated by comma.
+ address = '"Jane Doe" <jane@example.net>, "John Doe" <john@example.net>'
+ self.assertEqual(utils.getaddresses([address]),
+ [('Jane Doe', 'jane@example.net'),
+ ('John Doe', 'john@example.net')])
+ self.assertEqual(utils.getaddresses([address], strict=False),
+ [('Jane Doe', 'jane@example.net'),
+ ('John Doe', 'john@example.net')])
+ self.assertEqual(utils.parseaddr([address]), empty)
+ self.assertEqual(utils.parseaddr([address], strict=False),
+ ('', address))
+
+ # Test email.utils.supports_strict_parsing attribute
+ self.assertEqual(email.utils.supports_strict_parsing, True)
+
def test_getaddresses_nasty(self):
- eq = self.assertEqual
- eq(utils.getaddresses(['foo: ;']), [('', '')])
- eq(utils.getaddresses(
- ['[]*-- =~$']),
- [('', ''), ('', ''), ('', '*--')])
- eq(utils.getaddresses(
- ['foo: ;', '"Jason R. Mastaler" <jason@dom.ain>']),
- [('', ''), ('Jason R. Mastaler', 'jason@dom.ain')])
+ for addresses, expected in (
+ (['"Sürname, Firstname" <to@example.com>'],
+ [('Sürname, Firstname', 'to@example.com')]),
+
+ (['foo: ;'],
+ [('', '')]),
+
+ (['foo: ;', '"Jason R. Mastaler" <jason@dom.ain>'],
+ [('', ''), ('Jason R. Mastaler', 'jason@dom.ain')]),
+
+ ([r'Pete(A nice \) chap) <pete(his account)@silly.test(his host)>'],
+ [('Pete (A nice ) chap his account his host)', 'pete@silly.test')]),
+
+ (['(Empty list)(start)Undisclosed recipients :(nobody(I know))'],
+ [('', '')]),
+
+ (['Mary <@machine.tld:mary@example.net>, , jdoe@test . example'],
+ [('Mary', 'mary@example.net'), ('', ''), ('', 'jdoe@test.example')]),
+
+ (['John Doe <jdoe@machine(comment). example>'],
+ [('John Doe (comment)', 'jdoe@machine.example')]),
+
+ (['"Mary Smith: Personal Account" <smith@home.example>'],
+ [('Mary Smith: Personal Account', 'smith@home.example')]),
+
+ (['Undisclosed recipients:;'],
+ [('', '')]),
+
+ ([r'<boss@nil.test>, "Giant; \"Big\" Box" <bob@example.net>'],
+ [('', 'boss@nil.test'), ('Giant; "Big" Box', 'bob@example.net')]),
+ ):
+ with self.subTest(addresses=addresses):
+ self.assertEqual(utils.getaddresses(addresses),
+ expected)
+ self.assertEqual(utils.getaddresses(addresses, strict=False),
+ expected)
+
+ addresses = ['[]*-- =~$']
+ self.assertEqual(utils.getaddresses(addresses),
+ [('', '')])
+ self.assertEqual(utils.getaddresses(addresses, strict=False),
+ [('', ''), ('', ''), ('', '*--')])
def test_getaddresses_embedded_comment(self):
"""Test proper handling of a nested comment"""
@@ -3551,6 +3674,54 @@ def test_mime_classes_policy_argument(self):
m = cls(*constructor, policy=email.policy.default)
self.assertIs(m.policy, email.policy.default)
+ def test_iter_escaped_chars(self):
+ self.assertEqual(list(utils._iter_escaped_chars(r'a\\b\"c\\"d')),
+ [(0, 'a'),
+ (2, '\\\\'),
+ (3, 'b'),
+ (5, '\\"'),
+ (6, 'c'),
+ (8, '\\\\'),
+ (9, '"'),
+ (10, 'd')])
+ self.assertEqual(list(utils._iter_escaped_chars('a\\')),
+ [(0, 'a'), (1, '\\')])
+
+ def test_strip_quoted_realnames(self):
+ def check(addr, expected):
+ self.assertEqual(utils._strip_quoted_realnames(addr), expected)
+
+ check('"Jane Doe" <jane@example.net>, "John Doe" <john@example.net>',
+ ' <jane@example.net>, <john@example.net>')
+ check(r'"Jane \"Doe\"." <jane@example.net>',
+ ' <jane@example.net>')
+
+ # special cases
+ check(r'before"name"after', 'beforeafter')
+ check(r'before"name"', 'before')
+ check(r'b"name"', 'b') # single char
+ check(r'"name"after', 'after')
+ check(r'"name"a', 'a') # single char
+ check(r'"name"', '')
+
+ # no change
+ for addr in (
+ 'Jane Doe <jane@example.net>, John Doe <john@example.net>',
+ 'lone " quote',
+ ):
+ self.assertEqual(utils._strip_quoted_realnames(addr), addr)
+
+
+ def test_check_parenthesis(self):
+ addr = 'alice@example.net'
+ self.assertTrue(utils._check_parenthesis(f'{addr} (Alice)'))
+ self.assertFalse(utils._check_parenthesis(f'{addr} )Alice('))
+ self.assertFalse(utils._check_parenthesis(f'{addr} (Alice))'))
+ self.assertFalse(utils._check_parenthesis(f'{addr} ((Alice)'))
+
+ # Ignore real name between quotes
+ self.assertTrue(utils._check_parenthesis(f'")Alice((" {addr}'))
+
# Test the iterator/generators
class TestIterators(TestEmailBase):
diff --git a/Misc/NEWS.d/next/Library/2023-10-20-15-28-08.gh-issue-102988.dStNO7.rst b/Misc/NEWS.d/next/Library/2023-10-20-15-28-08.gh-issue-102988.dStNO7.rst
new file mode 100644
index 0000000000..3d0e9e4078
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2023-10-20-15-28-08.gh-issue-102988.dStNO7.rst
@@ -0,0 +1,8 @@
+:func:`email.utils.getaddresses` and :func:`email.utils.parseaddr` now
+return ``('', '')`` 2-tuples in more situations where invalid email
+addresses are encountered instead of potentially inaccurate values. Add
+optional *strict* parameter to these two functions: use ``strict=False`` to
+get the old behavior, accept malformed inputs.
+``getattr(email.utils, 'supports_strict_parsing', False)`` can be use to check
+if the *strict* paramater is available. Patch by Thomas Dwyer and Victor
+Stinner to improve the CVE-2023-27043 fix.

@ -1,63 +0,0 @@
From 60d40d7095983e0bc23a103b2050adc519dc7fe3 Mon Sep 17 00:00:00 2001
From: Lumir Balhar <lbalhar@redhat.com>
Date: Fri, 3 May 2024 14:17:48 +0200
Subject: [PATCH] Expect failures in tests not working properly with expat with
a fixed CVE in RHEL
---
Lib/test/test_pyexpat.py | 1 +
Lib/test/test_sax.py | 1 +
Lib/test/test_xml_etree.py | 3 +++
3 files changed, 5 insertions(+)
diff --git a/Lib/test/test_pyexpat.py b/Lib/test/test_pyexpat.py
index 43cbd27..27b1502 100644
--- a/Lib/test/test_pyexpat.py
+++ b/Lib/test/test_pyexpat.py
@@ -793,6 +793,7 @@ class ReparseDeferralTest(unittest.TestCase):
self.assertEqual(started, ['doc'])
+ @unittest.expectedFailure
def test_reparse_deferral_disabled(self):
started = []
diff --git a/Lib/test/test_sax.py b/Lib/test/test_sax.py
index 9b3014a..646c92d 100644
--- a/Lib/test/test_sax.py
+++ b/Lib/test/test_sax.py
@@ -1240,6 +1240,7 @@ class ExpatReaderTest(XmlTestBase):
self.assertEqual(result.getvalue(), start + b"<doc></doc>")
+ @unittest.expectedFailure
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 9c382d1..62f2871 100644
--- a/Lib/test/test_xml_etree.py
+++ b/Lib/test/test_xml_etree.py
@@ -1424,9 +1424,11 @@ class XMLPullParserTest(unittest.TestCase):
self.assert_event_tags(parser, [('end', 'root')])
self.assertIsNone(parser.close())
+ @unittest.expectedFailure
def test_simple_xml_chunk_1(self):
self.test_simple_xml(chunk_size=1, flush=True)
+ @unittest.expectedFailure
def test_simple_xml_chunk_5(self):
self.test_simple_xml(chunk_size=5, flush=True)
@@ -1651,6 +1653,7 @@ class XMLPullParserTest(unittest.TestCase):
self.assert_event_tags(parser, [('end', 'doc')])
+ @unittest.expectedFailure
def test_flush_reparse_deferral_disabled(self):
parser = ET.XMLPullParser(events=('start', 'end'))
--
2.44.0

@ -1,121 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: "Miss Islington (bot)"
<31488909+miss-islington@users.noreply.github.com>
Date: Mon, 12 Aug 2024 02:35:17 +0200
Subject: [PATCH] 00436: [CVE-2024-8088] gh-122905: Sanitize names in
zipfile.Path.
---
Lib/test/test_zipfile/_path/test_path.py | 17 +++++
Lib/zipfile/_path/__init__.py | 64 ++++++++++++++++++-
...-08-11-14-08-04.gh-issue-122905.7tDsxA.rst | 1 +
3 files changed, 81 insertions(+), 1 deletion(-)
create mode 100644 Misc/NEWS.d/next/Library/2024-08-11-14-08-04.gh-issue-122905.7tDsxA.rst
diff --git a/Lib/test/test_zipfile/_path/test_path.py b/Lib/test/test_zipfile/_path/test_path.py
index 06d5aab69b..90885dbbe3 100644
--- a/Lib/test/test_zipfile/_path/test_path.py
+++ b/Lib/test/test_zipfile/_path/test_path.py
@@ -577,3 +577,20 @@ def test_getinfo_missing(self, alpharep):
zipfile.Path(alpharep)
with self.assertRaises(KeyError):
alpharep.getinfo('does-not-exist')
+
+ def test_malformed_paths(self):
+ """
+ Path should handle malformed paths.
+ """
+ data = io.BytesIO()
+ zf = zipfile.ZipFile(data, "w")
+ zf.writestr("/one-slash.txt", b"content")
+ zf.writestr("//two-slash.txt", b"content")
+ zf.writestr("../parent.txt", b"content")
+ zf.filename = ''
+ root = zipfile.Path(zf)
+ assert list(map(str, root.iterdir())) == [
+ 'one-slash.txt',
+ 'two-slash.txt',
+ 'parent.txt',
+ ]
diff --git a/Lib/zipfile/_path/__init__.py b/Lib/zipfile/_path/__init__.py
index 78c413563b..42f9fded21 100644
--- a/Lib/zipfile/_path/__init__.py
+++ b/Lib/zipfile/_path/__init__.py
@@ -83,7 +83,69 @@ def __setstate__(self, state):
super().__init__(*args, **kwargs)
-class CompleteDirs(InitializedState, zipfile.ZipFile):
+class SanitizedNames:
+ """
+ ZipFile mix-in to ensure names are sanitized.
+ """
+
+ def namelist(self):
+ return list(map(self._sanitize, super().namelist()))
+
+ @staticmethod
+ def _sanitize(name):
+ r"""
+ Ensure a relative path with posix separators and no dot names.
+
+ Modeled after
+ https://github.com/python/cpython/blob/bcc1be39cb1d04ad9fc0bd1b9193d3972835a57c/Lib/zipfile/__init__.py#L1799-L1813
+ but provides consistent cross-platform behavior.
+
+ >>> san = SanitizedNames._sanitize
+ >>> san('/foo/bar')
+ 'foo/bar'
+ >>> san('//foo.txt')
+ 'foo.txt'
+ >>> san('foo/.././bar.txt')
+ 'foo/bar.txt'
+ >>> san('foo../.bar.txt')
+ 'foo../.bar.txt'
+ >>> san('\\foo\\bar.txt')
+ 'foo/bar.txt'
+ >>> san('D:\\foo.txt')
+ 'D/foo.txt'
+ >>> san('\\\\server\\share\\file.txt')
+ 'server/share/file.txt'
+ >>> san('\\\\?\\GLOBALROOT\\Volume3')
+ '?/GLOBALROOT/Volume3'
+ >>> san('\\\\.\\PhysicalDrive1\\root')
+ 'PhysicalDrive1/root'
+
+ Retain any trailing slash.
+ >>> san('abc/')
+ 'abc/'
+
+ Raises a ValueError if the result is empty.
+ >>> san('../..')
+ Traceback (most recent call last):
+ ...
+ ValueError: Empty filename
+ """
+
+ def allowed(part):
+ return part and part not in {'..', '.'}
+
+ # Remove the drive letter.
+ # Don't use ntpath.splitdrive, because that also strips UNC paths
+ bare = re.sub('^([A-Z]):', r'\1', name, flags=re.IGNORECASE)
+ clean = bare.replace('\\', '/')
+ parts = clean.split('/')
+ joined = '/'.join(filter(allowed, parts))
+ if not joined:
+ raise ValueError("Empty filename")
+ return joined + '/' * name.endswith('/')
+
+
+class CompleteDirs(InitializedState, SanitizedNames, zipfile.ZipFile):
"""
A ZipFile subclass that ensures that implied directories
are always included in the namelist.
diff --git a/Misc/NEWS.d/next/Library/2024-08-11-14-08-04.gh-issue-122905.7tDsxA.rst b/Misc/NEWS.d/next/Library/2024-08-11-14-08-04.gh-issue-122905.7tDsxA.rst
new file mode 100644
index 0000000000..1be44c906c
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2024-08-11-14-08-04.gh-issue-122905.7tDsxA.rst
@@ -0,0 +1 @@
+:class:`zipfile.Path` objects now sanitize names from the zipfile.

@ -1,18 +0,0 @@
-----BEGIN PGP SIGNATURE-----
iQKTBAABCgB9FiEEcWlgX2LHUTVtBUomqCHmgOX6YwUFAmayiFtfFIAAAAAALgAo
aXNzdWVyLWZwckBub3RhdGlvbnMub3BlbnBncC5maWZ0aGhvcnNlbWFuLm5ldDcx
Njk2MDVGNjJDNzUxMzU2RDA1NEEyNkE4MjFFNjgwRTVGQTYzMDUACgkQqCHmgOX6
YwUr4g//VyVs9tvbtiSp8pGe8f1gYErEw54r124sL/CBuNii8Irts1j5ymGxcm+l
hshPK5UlqRnhd5dCJWFTvLTXa5Ko2R1L3JyyxfGd1hmDuMhrWsDHijI0R7L/mGM5
6X2LTaadBVNvk8HaNKvR8SEWvo68rdnOuYElFA9ir7uqwjO26ZWz9FfH80YDGwo8
Blef2NYw8rNhiaZMFV0HYV7D+YyUAZnFNfW8M7Fd4oskUyj1tD9J89T9FFLYN09d
BcCIf+EdiEfqRpKxH89bW2g52kDrm4jYGONtpyF8eruyS3YwYSbvbuWioBYKmlxC
s51mieXz6G325GTZnmPxLek3ywPv6Gil9y0wH3fIr2BsWsmXust4LBpjDGt56Fy6
seokGBg8xzsBSk3iEqNoFmNsy/QOiuCcDejX4XqBDNodOlETQPJb07TkTI2iOmg9
NG4Atiz1HvGVxK68UuK9IIcNHyaWUmH8h4VQFGvc6KV6feP5Nm21Y12PZ5XIqJBO
Y8M/VJIJ5koaNPQfnBbbI5YBkUr4BVpIXIpY5LM/L5sUo2C3R7hMi0VGK88HGfSQ
KV4JmZgf6RMBNmrWY12sryS1QQ6q3P110GTUGQWB3sxxNbhmfcrK+4viqHc83yDz
ifmk33HuqaQGU7OzUMHeNcoCJIPo3H1FpoHOn9wLLCtA1pT+as4=
=t0Rk
-----END PGP SIGNATURE-----

@ -0,0 +1,18 @@
-----BEGIN PGP SIGNATURE-----
iQKTBAABCgB9FiEEcWlgX2LHUTVtBUomqCHmgOX6YwUFAmbbZv1fFIAAAAAALgAo
aXNzdWVyLWZwckBub3RhdGlvbnMub3BlbnBncC5maWZ0aGhvcnNlbWFuLm5ldDcx
Njk2MDVGNjJDNzUxMzU2RDA1NEEyNkE4MjFFNjgwRTVGQTYzMDUACgkQqCHmgOX6
YwV51g//WpQjF/Rt19lgaWojZ3qDkvmTM2kpvfDGLe9Tkm1fWYzji4TLS3TnzGEp
dw2K6ApqGX4aO9AKMBRdfiFyhaDp0ENlBzSspvyzVT4LsRxiWXqyJ1qZB9mui/S8
k5pw2qygaS4gYEAOLrVEwmQ52pig1wMAouSmRuopVk5DGYUN6Wir7RZMrYynsd6P
6HYqpZby2L1fKlcj2xYY44niuL5a+I8ucWN9qOBzRLCuzq20lVoII817vORjCqa7
ZUMKrDXDlzHnISNqZyyX37/oi6a8UdNm0o8V9yDJLiBu9+Dy3OueoIguuzimk4hq
ZnepBoCcr2YAxIsXvwl2qfQBOCjJ5WAZ/wzA/eQMo9Jn1TYRBwuMC1MmP0ylt7Me
/pS57bGuulkfPv9pMto7qc2lNpotBmAsfGJAJMczeEmyo5tAXnJUBE94JRmiLaR/
zwPmJB3O9uEQhEa8+cjx4+9bK6+YvAXkb9x92Wn70u+IaalPj8CRA7B45hy1KYHT
5s/ndwFFWThxqxH61oqjPvlZW5PWBC83yi/KovhgDWNL2G9CTusKevMqX/LMUAKz
M3mJU/24vUu9bJNxB2qsa3UeP8hbb6WN5LLQyxRsXPjVQ9iTeMWrQkz1mRGIK2Ec
OFbYH2SGa/RELds6MZWzvZuXIefCoyuc51WsXnc4LFr2ZGv4dAI=
=CK1W
-----END PGP SIGNATURE-----

@ -1,6 +1,3 @@
%global __python3 /usr/bin/python3.12
%global python3_pkgversion 3.12
# ==================
# Top-level metadata
# ==================
@ -16,7 +13,7 @@ URL: https://www.python.org/
# WARNING When rebasing to a new Python version,
# remember to update the python3-docs package as well
%global general_version %{pybasever}.5
%global general_version %{pybasever}.6
#global prerel ...
%global upstream_version %{general_version}%{?prerel}
Version: %{general_version}%{?prerel:~%{prerel}}
@ -34,8 +31,12 @@ License: Python-2.0.1
# Main Python, i.e. whether this is the main Python version in the distribution
# that owns /usr/bin/python3 and other unique paths
# This also means the built subpackages are called python3 rather than python3X
# RHEL: Disabled by default
# By default, this is determined by the %%__default_python3_pkgversion value
%if "%{?__default_python3_pkgversion}" == "%{pybasever}"
%bcond_without main_python
%else
%bcond_with main_python
%endif
# If this is *not* Main Python, should it contain `Provides: python(abi) ...`?
# In Fedora no package shall depend on an alternative Python via this tag, so we do not provide it.
@ -61,8 +62,12 @@ License: Python-2.0.1
# Whether to use RPM build wheels from the python-{pip,setuptools,wheel}-wheel packages
# Uses upstream bundled prebuilt wheels otherwise
# Only F39+ has a pip new enough to work with Python 3.12
%if 0%{?fedora} >= 39 || 0%{?rhel} >= 10
%bcond_without rpmwheels
%else
%bcond_with rpmwheels
%endif
# If the rpmwheels condition is disabled, we use the bundled wheel packages
# from Python with the versions below.
# This needs to be manually updated when we update Python.
@ -142,6 +147,14 @@ Provides: bundled(python3dist(packaging)) = 23
%bcond_with valgrind
%endif
# In RHEL 9+, we obsolete/provide Platform Python from regular Python
# This is only appropriate for the main Python build
%if 0%{?rhel} >= 9 && %{with main_python}
%bcond_without rhel8_compat_shims
%else
%bcond_with rhel8_compat_shims
%endif
# =====================
# General global macros
# =====================
@ -201,12 +214,21 @@ Provides: bundled(python3dist(packaging)) = 23
# The -O flag for the compiler, debug builds
# -Wno-cpp avoids some warnings with -O0
%global optflags_debug -O0 -Wno-cpp
# Remove the default -O2 flag, our flags are applied in %%build/%%install
%global __global_compiler_flags %(echo '%{__global_compiler_flags}' | sed 's/-O[[:digit:]]//')
# Disable automatic bytecompilation. The python3 binary is not yet be
# available in /usr/bin when Python is built. Also, the bytecompilation fails
# on files that test invalid syntax.
%undefine py_auto_byte_compile
# When a main_python build is attempted despite the %%__default_python3_pkgversion value
# We undefine magic macros so the python3-... package does not provide wrong python3X-...
%if %{with main_python} && ("%{?__default_python3_pkgversion}" != "%{pybasever}")
%undefine __pythonname_provides
%{warn:Doing a main_python build with wrong %%__default_python3_pkgversion (0%{?__default_python3_pkgversion}, but this is %pyshortver)}
%endif
%if %{with main_python}
# To keep the upgrade path clean, we Obsolete python3.X from the python3
# package and python3.X-foo from individual subpackages.
@ -232,7 +254,8 @@ BuildRequires: bluez-libs-devel
BuildRequires: bzip2
BuildRequires: bzip2-devel
BuildRequires: desktop-file-utils
BuildRequires: expat-devel
# See the runtime requirement in the -libs subpackage
BuildRequires: expat-devel >= 2.6
BuildRequires: findutils
BuildRequires: gcc-c++
@ -249,7 +272,6 @@ BuildRequires: libappstream-glib
BuildRequires: libb2-devel
%endif
BuildRequires: libffi-devel
BuildRequires: libnsl2-devel
BuildRequires: libtirpc-devel
BuildRequires: libGL-devel
BuildRequires: libuuid-devel
@ -262,7 +284,7 @@ BuildRequires: openssl-devel
BuildRequires: pkgconfig
BuildRequires: python-rpm-macros
BuildRequires: readline-devel
BuildRequires: redhat-rpm-config
BuildRequires: redhat-rpm-config >= 127
BuildRequires: sqlite-devel
BuildRequires: gdb
@ -378,26 +400,6 @@ Patch371: 00371-revert-bpo-1596321-fix-threading-_shutdown-for-the-main-thread-g
# - https://access.redhat.com/articles/7004769
Patch397: 00397-tarfile-filter.patch
# 00415 # 83e0fc3ec7bc38055c536f482578a10f6efcc08c
# [CVE-2023-27043] gh-102988: Reject malformed addresses in email.parseaddr() (#111116)
#
# Detect email address parsing errors and return empty tuple to
# indicate the parsing error (old API). Add an optional 'strict'
# parameter to getaddresses() and parseaddr() functions. Patch by
# Thomas Dwyer.
Patch415: 00415-cve-2023-27043-gh-102988-reject-malformed-addresses-in-email-parseaddr-111116.patch
# 00422 # a353cebef737c41420dc7ae2469dd657371b8881
# Fix tests for XMLPullParser with Expat 2.6.0
#
# Feeding the parser by too small chunks defers parsing to prevent
# CVE-2023-52425. Future versions of Expat may be more reactive.
Patch422: 00422-fix-tests-for-xmlpullparser-with-expat-2-6-0.patch
# 00436 # c76cc2aa3a2c30375ade4859b732ada851cc89ed
# [CVE-2024-8088] gh-122905: Sanitize names in zipfile.Path.
Patch436: 00436-cve-2024-8088-gh-122905-sanitize-names-in-zipfile-path.patch
# (New patches go here ^^^)
#
# When adding new patches to "python" and "python3" in Fedora, EL, etc.,
@ -445,6 +447,12 @@ Provides: python%{pybasever}%{?_isa} = %{version}-%{release}
Recommends: %{_bindir}/python
%endif
%if %{with rhel8_compat_shims}
Provides: platform-python = %{version}-%{release}
Provides: platform-python%{?_isa} = %{version}-%{release}
Obsoletes: platform-python < %{pybasever}
%endif
# Python interpreter packages used to be named (or provide) name pythonXY (e.g.
# python39). However, to align it with the executable names and to prepare for
# Python 3.10, they were renamed to pythonX.Y (e.g. python3.9, python3.10). We
@ -521,12 +529,12 @@ Summary: Python runtime libraries
%if %{with rpmwheels}
Requires: %{python_wheel_pkg_prefix}-pip-wheel >= 23.1.2
# Bundled libb2 is CC0, covered by grandfathering exception
License: Python and CC0
License: Python-2.0.1 AND CC0-1.0
%else
Provides: bundled(python3dist(pip)) = %{pip_version}
%pip_bundled_provides
# License manually combined form Python + pip
License: Python and CC0 and MIT and ASL 2.0 and BSD and ISC and LGPLv2 and MPLv2.0 and (ASL 2.0 or BSD)
License: Python-2.0.1 AND CC0-1.0 AND MIT AND Apache-2.0 AND BSD-2-Clause AND BSD-3-Clause AND ISC AND LGPL-2.1-only AND MPL-2.0 AND (Apache-2.0 OR BSD-2-Clause)
%endif
%unversioned_obsoletes_of_python3_X_if_main libs
@ -549,6 +557,14 @@ Recommends: (%{pkgname}-tkinter%{?_isa} = %{version}-%{release} if tk%{?_isa})
# The zoneinfo module needs tzdata
Requires: tzdata
# The requirement on libexpat is generated, but we need to version it.
# When built with expat >= 2.6, but installed with older expat, we get:
# ImportError: /usr/lib64/python3.X/lib-dynload/pyexpat.cpython-....so:
# undefined symbol: XML_SetReparseDeferralEnabled
# This breaks many things, including python -m venv.
# Other subpackages (like -debug) also need this, but they all depend on -libs.
Requires: expat >= 2.6
%description -n %{pkgname}-libs
This package contains runtime libraries for use by Python:
- the majority of the Python standard library
@ -570,10 +586,6 @@ Requires: (python3-rpm-macros if rpm-build)
# On Fedora, we keep this to avoid one additional round of %%generate_buildrequires.
%{!?rhel:Requires: (pyproject-rpm-macros if rpm-build)}
# We provide the python3.12-rpm-macros here to make it possible to
# BuildRequire them in the same manner as RHEL8.
Provides: %{pkgname}-rpm-macros = %{version}-%{release}
%unversioned_obsoletes_of_python3_X_if_main devel
%if %{with main_python}
@ -597,6 +609,12 @@ Provides: 2to3 = %{version}-%{release}
Conflicts: %{pkgname} < %{version}-%{release}
%if %{with rhel8_compat_shims}
Provides: platform-python-devel = %{version}-%{release}
Provides: platform-python-devel%{?_isa} = %{version}-%{release}
Obsoletes: platform-python-devel < %{pybasever}
%endif
%description -n %{pkgname}-devel
This package contains the header files and configuration needed to compile
Python extension modules (typically written in C or C++), to embed Python
@ -658,12 +676,12 @@ Requires: %{pkgname}-libs%{?_isa} = %{version}-%{release}
Requires: %{python_wheel_pkg_prefix}-setuptools-wheel
Requires: %{python_wheel_pkg_prefix}-wheel-wheel
%else
Provides: bundled(python%{python3_pkgversion}dist(setuptools)) = %{setuptools_version}
Provides: bundled(python3dist(setuptools)) = %{setuptools_version}
%setuptools_bundled_provides
Provides: bundled(python%{python3_pkgversion}dist(wheel)) = %{wheel_version}
Provides: bundled(python3dist(wheel)) = %{wheel_version}
%wheel_bundled_provides
# License manually combined from Python + setuptools + wheel
License: Python and MIT and ASL 2.0 and (ASL 2.0 or BSD)
License: Python-2.0.1 AND MIT AND Apache-2.0 AND (Apache-2.0 OR BSD-2-Clause)
%endif
%unversioned_obsoletes_of_python3_X_if_main test
@ -692,6 +710,12 @@ Requires: %{pkgname}-idle%{?_isa} = %{version}-%{release}
%unversioned_obsoletes_of_python3_X_if_main debug
%if %{with rhel8_compat_shims}
Provides: platform-python-debug = %{version}-%{release}
Provides: platform-python-debug%{?_isa} = %{version}-%{release}
Obsoletes: platform-python-debug < %{pybasever}
%endif
%description -n %{pkgname}-debug
python3-debug provides a version of the Python runtime with numerous debugging
features enabled, aimed at advanced Python users such as developers of Python
@ -746,11 +770,6 @@ rm -r Modules/_decimal/libmpdec
rm configure pyconfig.h.in
# Python 3.12 requires autoconf 2.71 which is not available in RHEL,
# we verified that it builds also with autoconf 2.69 therefore we
# are unpinning it
sed -i 's/AC_PREREQ(\[2.71/AC_PREREQ(\[2.69/' configure.ac
# ======================================================
# Configuring and building the code:
# ======================================================
@ -808,7 +827,6 @@ BuildPython() {
ConfName=$1
ExtraConfigArgs=$2
MoreCFlags=$3
MoreCFlagsNodist=$4
# Each build is done in its own directory
ConfDir=build/$ConfName
@ -848,7 +866,7 @@ BuildPython() {
$ExtraConfigArgs \
%{nil}
%global flags_override EXTRA_CFLAGS="$MoreCFlags" CFLAGS_NODIST="$CFLAGS_NODIST $MoreCFlags $MoreCFlagsNodist"
%global flags_override EXTRA_CFLAGS="$MoreCFlags" CFLAGS_NODIST="$CFLAGS_NODIST $MoreCFlags"
%if %{without bootstrap}
# Regenerate generated files (needs python3)
@ -871,13 +889,11 @@ BuildPython() {
# See also: https://bugzilla.redhat.com/show_bug.cgi?id=1818857
BuildPython debug \
"--without-ensurepip --with-pydebug" \
"%{optflags_debug}" \
""
"%{optflags_debug}"
%endif # with debug_build
BuildPython optimized \
"--without-ensurepip %{optimizations_flag}" \
"" \
"%{optflags_optimized}"
# ======================================================
@ -990,7 +1006,7 @@ InstallPython debug \
# Now the optimized build:
InstallPython optimized \
%{py_INSTSONAME_optimized} \
"" \
"%{optflags_optimized}" \
%{LDVERSION_optimized}
# Install directories for additional packages
@ -1130,6 +1146,25 @@ ln -s ./python3-debug %{buildroot}%{_bindir}/python-debug
%endif
%endif
%if %{with rhel8_compat_shims}
# Provide RHEL8 backwards compatible symbolic links in %%_libexecdir
mkdir -p %{buildroot}%{_libexecdir}
ln -s %{_bindir}/python%{pybasever} %{buildroot}%{_libexecdir}/platform-python
ln -s %{_bindir}/python%{pybasever} %{buildroot}%{_libexecdir}/platform-python%{pybasever}
ln -s %{_bindir}/python%{pybasever}-config %{buildroot}%{_libexecdir}/platform-python-config
ln -s %{_bindir}/python%{pybasever}-config %{buildroot}%{_libexecdir}/platform-python%{pybasever}-config
ln -s %{_bindir}/python%{pybasever}-`uname -m`-config %{buildroot}%{_libexecdir}/platform-python%{pybasever}-`uname -m`-config
# There were also executables with %%{LDVERSION_optimized} in RHEL 8,
# but since Python 3.8 %%{LDVERSION_optimized} == %%{pybasever}.
# We list both in the %%files section to assert this.
%if %{with debug_build}
ln -s %{_bindir}/python%{LDVERSION_debug} %{buildroot}%{_libexecdir}/platform-python-debug
ln -s %{_bindir}/python%{LDVERSION_debug} %{buildroot}%{_libexecdir}/platform-python%{LDVERSION_debug}
ln -s %{_bindir}/python%{LDVERSION_debug}-config %{buildroot}%{_libexecdir}/platform-python%{LDVERSION_debug}-config
ln -s %{_bindir}/python%{LDVERSION_debug}-`uname -m`-config %{buildroot}%{_libexecdir}/platform-python%{LDVERSION_debug}-`uname -m`-config
%endif
%endif
# Remove large, autogenerated sources and keep only the non-optimized pycache
for file in %{buildroot}%{pylibdir}/pydoc_data/topics.py $(grep --include='*.py' -lr %{buildroot}%{pylibdir}/encodings -e 'Python Character Mapping Codec .* from .* with gencodec.py'); do
directory=$(dirname ${file})
@ -1237,6 +1272,11 @@ CheckPython optimized
%{_bindir}/python%{LDVERSION_optimized}
%{_mandir}/*/*3*
%if %{with rhel8_compat_shims}
%{_libexecdir}/platform-python
%{_libexecdir}/platform-python%{pybasever}
%{_libexecdir}/platform-python%{LDVERSION_optimized}
%endif
%if %{with main_python}
%files -n python-unversioned-command
@ -1346,7 +1386,6 @@ CheckPython optimized
%{dynload_dir}/grp.%{SOABI_optimized}.so
%{dynload_dir}/math.%{SOABI_optimized}.so
%{dynload_dir}/mmap.%{SOABI_optimized}.so
%{dynload_dir}/nis.%{SOABI_optimized}.so
%{dynload_dir}/ossaudiodev.%{SOABI_optimized}.so
%{dynload_dir}/_posixshmem.%{SOABI_optimized}.so
%{dynload_dir}/pyexpat.%{SOABI_optimized}.so
@ -1513,6 +1552,14 @@ CheckPython optimized
%{_libdir}/pkgconfig/python-%{pybasever}.pc
%{_libdir}/pkgconfig/python-%{pybasever}-embed.pc
%if %{with rhel8_compat_shims}
%{_libexecdir}/platform-python-config
%{_libexecdir}/platform-python%{pybasever}-config
%{_libexecdir}/platform-python%{LDVERSION_optimized}-config
%{_libexecdir}/platform-python%{pybasever}-*-config
%{_libexecdir}/platform-python%{LDVERSION_optimized}-*-config
%endif
%files -n %{pkgname}-idle
%if %{with main_python}
@ -1632,7 +1679,6 @@ CheckPython optimized
%{dynload_dir}/grp.%{SOABI_debug}.so
%{dynload_dir}/math.%{SOABI_debug}.so
%{dynload_dir}/mmap.%{SOABI_debug}.so
%{dynload_dir}/nis.%{SOABI_debug}.so
%{dynload_dir}/ossaudiodev.%{SOABI_debug}.so
%{dynload_dir}/_posixshmem.%{SOABI_debug}.so
%{dynload_dir}/pyexpat.%{SOABI_debug}.so
@ -1663,6 +1709,13 @@ CheckPython optimized
%{_libdir}/pkgconfig/python-%{LDVERSION_debug}.pc
%{_libdir}/pkgconfig/python-%{LDVERSION_debug}-embed.pc
%if %{with rhel8_compat_shims}
%{_libexecdir}/platform-python-debug
%{_libexecdir}/platform-python%{LDVERSION_debug}
%{_libexecdir}/platform-python%{LDVERSION_debug}-config
%{_libexecdir}/platform-python%{LDVERSION_debug}-*-config
%endif
# Analog of the -tools subpackage's files:
# None for now; we could build precanned versions that have the appropriate
# shebang if needed
@ -1712,35 +1765,62 @@ CheckPython optimized
# ======================================================
%changelog
* Tue Oct 29 2024 Troy Dawson <tdawson@redhat.com> - 3.12.6-2
- Bump release for October 2024 mass rebuild:
Resolves: RHEL-64018
* Mon Sep 09 2024 Tomáš Hrnčiar <thrnciar@redhat.com> - 3.12.6-1
- Update to 3.12.6
Resolves: RHEL-57397
* Fri Aug 23 2024 Charalampos Stratakis <cstratak@redhat.com> - 3.12.5-2
- Security fix for CVE-2024-8088
Resolves: RHEL-55963
Resolves: RHEL-55923
* Wed Aug 07 2024 Tomáš Hrnčiar <thrnciar@redhat.com> - 3.12.5-1
- Update to 3.12.5
- Security fix for CVE-2024-6923
Resolves: RHEL-53041
* Thu Jul 25 2024 Charalampos Stratakis <cstratak@redhat.com> - 3.12.4-3
- Properly propagate the optimization flags to C extensions
Resolves: RHEL-53036
* Wed Jul 17 2024 Charalampos Stratakis <cstratak@redhat.com> - 3.12.4-2
* Wed Jul 17 2024 Charalampos Stratakis <cstratak@redhat.com> - 3.12.4-4
- Build Python with -O3
- https://fedoraproject.org/wiki/Changes/Python_built_with_gcc_O3
* Fri Jun 28 2024 Tomáš Hrnčiar <thrnciar@redhat.com> - 3.12.4-1
* Thu Jul 11 2024 Charalampos Stratakis <cstratak@redhat.com> - 3.12.4-3
- Fix issues uncovered by static analysis
Resolves: RHEL-45021
* Thu Jul 04 2024 Tomáš Hrnčiar <thrnciar@redhat.com> - 3.12.4-2
- Require expat >= 2.6 to prevent errors when creating venvs with older expat
* Wed Jul 03 2024 Tomáš Hrnčiar <thrnciar@redhat.com> - 3.12.4-1
- Update to 3.12.4
Resolves: RHEL-44103
Resolves: RHEL-44054
* Tue Jun 11 2024 Charalampos Stratakis <cstratak@redhat.com> - 3.12.3-2
* Wed Jul 03 2024 Tomáš Hrnčiar <thrnciar@redhat.com> - 3.12.3-1
- Update to 3.12.3
* Mon Jun 24 2024 Troy Dawson <tdawson@redhat.com> - 3.12.2-8
- Bump release for June 2024 mass rebuild
* Tue Jun 11 2024 Charalampos Stratakis <cstratak@redhat.com> - 3.12.2-7
- Enable importing of hash-based .pyc files under FIPS mode
Resolves: RHEL-40772
Resolves: RHEL-40769
* Fri May 03 2024 Lumír Balhar <lbalhar@redhat.com> - 3.12.3-1
- Update to 3.12.3
Related: RHEL-33690
* Tue May 28 2024 Charalampos Stratakis <cstratak@redhat.com> - 3.12.2-6
- Support OpenSSL FIPS mode
- Disable the builtin hashlib hashes except blake2
Resolves: RHEL-39066
* Wed Apr 24 2024 Charalampos Stratakis <cstratak@redhat.com> - 3.12.2-5
- Add Red Hat configuration for CVE-2007-4559
Resolves: RHEL-33847
* Fri May 03 2024 Lumír Balhar <lbalhar@redhat.com> - 3.12.2-3
* Tue Apr 23 2024 Miro Hrončok <mhroncok@redhat.com> - 3.12.2-4
- Remove the nis module, drop the dependency on libnsl2
* Thu Mar 21 2024 Miro Hrončok <mhroncok@redhat.com> - 3.12.2-3
- Fix tests for XMLPullParser with Expat 2.6.0
- Move all test modules to the python3-test package, namely:
- __phello__
- _xxsubinterpreters
@ -1748,66 +1828,104 @@ Related: RHEL-33690
- xxlimited_35
- xxsubtype
* Fri May 03 2024 Lumír Balhar <lbalhar@redhat.com> - 3.12.2-2
- Fix tests for XMLPullParser with Expat with fixed CVE
* Mon Mar 04 2024 Lumír Balhar <lbalhar@redhat.com> - 3.12.2-2
- Add provides and symbolic links for compatibility with platform-python
Resolves: RHEL-27855
* Fri May 03 2024 Lumír Balhar <lbalhar@redhat.com> - 3.12.2-1
* Wed Feb 07 2024 Tomáš Hrnčiar <thrnciar@redhat.com> - 3.12.2-1
- Update to 3.12.2
Resolves: RHEL-33690
* Mon Feb 19 2024 Charalampos Stratakis <cstratak@redhat.com> - 3.12.1-4
- Add Red Hat configuration for CVE-2007-4559
* Fri Jan 26 2024 Fedora Release Engineering <releng@fedoraproject.org> - 3.12.1-4
- Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild
* Thu Jan 18 2024 Charalampos Stratakis <cstratak@redhat.com> - 3.12.1-3
- Support OpenSSL FIPS mode
- Disable the builtin hashlib hashes except blake2
* Mon Jan 22 2024 Fedora Release Engineering <releng@fedoraproject.org> - 3.12.1-3
- Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild
* Mon Dec 18 2023 Lumír Balhar <lbalhar@redhat.com> - 3.12.1-2
- Security fix for CVE-2023-27043 (rhbz#2196190)
* Fri Dec 08 2023 Tomáš Hrnčiar <thrnciar@redhat.com> - 3.12.1-1
- Update to 3.12.1
- Own stray directories in /usr/lib64/python3.12
- Fixes: rhbz#2252143
* Thu Oct 05 2023 Yaakov Selkowitz <yselkowi@redhat.com> - 3.12.0-2
- Use bundled libb2 in RHEL builds
* Mon Oct 02 2023 Miro Hrončok <mhroncok@redhat.com> - 3.12.0-1
- Update to 3.12.0 final
* Tue Sep 19 2023 Miro Hrončok <mhroncok@redhat.com> - 3.12.0~rc3-1
- Update to 3.12.0rc3
* Wed Sep 06 2023 Tomáš Hrnčiar <thrnciar@redhat.com> - 3.12.0~rc2-1
- Update to 3.12.0rc2
* Mon Aug 07 2023 Tomáš Hrnčiar <thrnciar@redhat.com> - 3.12.0~rc1-1
- Update to 3.12.0rc1
* Wed Aug 02 2023 Charalampos Stratakis <cstratak@redhat.com> - 3.12.0~b4-3
- Remove extra distro-applied CFLAGS passed to user built C extensions
- https://fedoraproject.org/wiki/Changes/Python_Extension_Flags_Reduction
* Fri Jul 21 2023 Fedora Release Engineering <releng@fedoraproject.org> - 3.12.0~b4-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_39_Mass_Rebuild
* Wed Jul 12 2023 Miro Hrončok <mhroncok@redhat.com> - 3.12.0~b4-1
- Update to 3.12.0b4
* Wed Jun 21 2023 Tomáš Hrnčiar <thrnciar@redhat.com> - 3.12.0~b3-2
- Backport upstream patch to add PyType_GetDict() function
* Tue Jun 20 2023 Tomáš Hrnčiar <thrnciar@redhat.com> - 3.12.0~b3-1
- Update to 3.12.0b3
* Tue Jun 13 2023 Python Maint <python-maint@redhat.com> - 3.12.0~b2-3
- Rebuilt for Python 3.12
* Tue Jun 13 2023 Python Maint <python-maint@redhat.com> - 3.12.0~b2-2
- Bootstrap for Python 3.12
* Wed Jun 07 2023 Tomáš Hrnčiar <thrnciar@redhat.com> - 3.12.0~b2-1
- Update to 3.12.0b2
* Mon May 29 2023 Miro Hrončok <mhroncok@redhat.com> - 3.12.0~b1-2
- Use wheels from RPMs, at least on Fedora 39+
- On older Fedora releases, declare bundled() provides and a complex License tag
* Tue May 23 2023 Tomáš Hrnčiar <thrnciar@redhat.com> - 3.12.0~b1-1
- Update to 3.12.0b1
* Wed Apr 05 2023 Tomáš Hrnčiar <thrnciar@redhat.com> - 3.12.0~a7-1
- Update to 3.12.0a7
* Thu Mar 23 2023 Miro Hrončok <mhroncok@redhat.com> - 3.12.0~a6-2
- Increase the test timeout during package build
* Wed Mar 08 2023 Tomáš Hrnčiar <thrnciar@redhat.com> - 3.12.0~a6-1
- Update to 3.12.0a6
* Wed Feb 08 2023 Tomáš Hrnčiar <thrnciar@redhat.com> - 3.12.0~a5-1
- Update to 3.12.0a5
* Fri Jan 20 2023 Fedora Release Engineering <releng@fedoraproject.org> - 3.12.0~a4-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_38_Mass_Rebuild
* Wed Jan 11 2023 Tomáš Hrnčiar <thrnciar@redhat.com> - 3.12.0~a4-1
- Update to 3.12.0a4
* Mon Dec 19 2022 Miro Hrončok <mhroncok@redhat.com> - 3.12.0~a3-2
- No longer patch the default bytecode cache invalidation policy
* Wed Dec 07 2022 Tomáš Hrnčiar <thrnciar@redhat.com> - 3.12.0~a3-1
- Update to 3.12.0a3
* Tue Nov 15 2022 Tomáš Hrnčiar <thrnciar@redhat.com> - 3.12.0~a2-1
- Update to 3.12.0a2
- Fixes: rhbz#2133847
* Thu Oct 27 2022 Miro Hrončok <mhroncok@redhat.com> - 3.12.0~a1-2
- Finish initial bootstrap of Python 3.12.0a1
* Wed Dec 20 2023 Charalampos Stratakis <cstratak@redhat.com> - 3.12.1-2
- Disable bootstrap
* Wed Dec 20 2023 Tomáš Hrnčiar <thrnciar@redhat.com> - 3.12.1-1
- Initial package
- Fedora contributions by:
Björn Esser <besser82@fedoraproject.org>
Bohuslav Kabrda <bkabrda@redhat.com>
Charalampos Stratakis <cstratak@redhat.com>
Dan Horák <dan@danny.cz>
David Malcolm <dmalcolm@redhat.com>
Dennis Gilmore <dennis@ausil.us>
Florian Weimer <fweimer@redhat.com>
Gwyn Ciesla <limb@fedoraproject.org>
Igor Gnatenko <ignatenko@redhat.com>
Iryna Shcherbina <shcherbina.iryna@gmail.com>
Jaroslav Škarvada <jskarvad@redhat.com>
Jason ティビツ <tibbs@fedoraproject.org>
Kalev Lember <klember@redhat.com>
Karsten Hopp <karsten@redhat.com>
Lumir Balhar <lbalhar@redhat.com>
Marcel Plch <marcel.plch@protonmail.com>
Matej Stuchlik <mstuchli@redhat.com>
Michal Cyprian <m.cyprian@gmail.com>
Michal Toman <mtoman@fedoraproject.org>
Miro Hrončok <miro@hroncok.cz>
Nicolas Chauvet <kwizart@gmail.com>
Orion Poplawski <orion@cora.nwra.com>
Patrik Kopkan <pkopkan@redhat.com>
Peter Robinson <pbrobinson@gmail.com>
Petr Šplíchal <psplicha@redhat.com>
Petr Viktorin <pviktori@redhat.com>
Rex Dieter <rdieter@fedoraproject.org>
Richard W.M. Jones <rjones@redhat.com>
Robert Kuska <rkuska@gmail.com>
Sahana Prasad <sahana@redhat.com>
Stephen Gallagher <sgallagh@redhat.com>
Than Ngo <than@redhat.com>
Thomas Spura <thomas.spura@gmail.com>
Till Maas <opensource@till.name>
Tomáš Hrnčiar <thrnciar@redhat.com>
Tomas Mraz <tmraz@fedoraproject.org>
Tomas Orsava <torsava@redhat.com>
Tomas Radej <tradej@redhat.com>
Toshio Kuratomi <toshio@fedoraproject.org>
Victor Stinner <vstinner@python.org>
Ville Skyttä <ville.skytta@iki.fi>
Yaakov Selkowitz <yselkowi@redhat.com>
Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
* Wed Oct 26 2022 Tomáš Hrnčiar <thrnciar@redhat.com> - 3.12.0~a1-1
- Initial Python 3.12 package forked from Python 3.11

Loading…
Cancel
Save