Compare commits

...

25 Commits

Author SHA1 Message Date
David Abdurachmanov b9aa19325a
Merge remote-tracking branch 'up/main' into main-riscv64
Signed-off-by: David Abdurachmanov <davidlt@rivosinc.com>
2024-02-21 13:23:53 +02:00
Tomáš Hrnčiar d3e4f80070 Update to 3.12.2 2024-02-08 16:33:19 +01:00
Fedora Release Engineering ff956d27be Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild 2024-01-26 13:32:50 +00:00
David Abdurachmanov 3e5fc8ca46
Merge commit '7a094a057183ba49527fcac7e9e5c863f74bc55a' into main-riscv64 2024-01-23 16:19:20 +02:00
Fedora Release Engineering c604248608 Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild 2024-01-22 09:22:06 +00:00
Tomáš Hrnčiar 90929e6c2e Require python3-rpm-generators even when bootstrapping non-main Pythons 2024-01-05 11:51:54 +01:00
Lumir Balhar 7a094a0571 Security fix for CVE-2023-27043 (rhbz#2196190) 2023-12-18 13:17:51 +01:00
Miro Hrončok 3c67985ace Own stray directories in /usr/lib64/python3.12
Fixes https://bugzilla.redhat.com/2252143
2023-12-08 20:15:03 +01:00
Tomáš Hrnčiar cc458c9fb3 Update to 3.12.1 2023-12-08 14:38:32 +01:00
David Abdurachmanov b735fa02e0
Disable bootstrap (riscv64)
Signed-off-by: David Abdurachmanov <davidlt@rivosinc.com>
2023-10-20 14:18:31 +03:00
Miro Hrončok c41c6b28ff CI: Run smoke test with cython 2023-10-18 11:23:30 +02:00
David Abdurachmanov 7ea22f20d4
Bootstrap for Python 3.12 (riscv64)
Signed-off-by: David Abdurachmanov <davidlt@rivosinc.com>
2023-10-16 11:11:12 +03:00
David Abdurachmanov bde278d98e
Disable test_peg_generator test on riscv64
Signed-off-by: David Abdurachmanov <davidlt@rivosinc.com>
2023-10-14 09:22:40 +03:00
David Abdurachmanov 8b902d984a
Add support for riscv64
Increase tests timeout by 10x and disable test_eintr test for now.

Signed-off-by: David Abdurachmanov <davidlt@rivosinc.com>
2023-10-13 11:39:35 +03:00
Yaakov Selkowitz 261b6e48d6 Use bundled libb2 in RHEL builds
Standalone libb2 is unwanted in RHEL.
2023-10-04 23:18:39 -04:00
Miro Hrončok 187d5c28b8 Update to 3.12.0 final 2023-10-02 18:40:13 +02:00
Miro Hrončok fb0049bb7a Update to 3.12.0rc3 2023-09-19 23:20:46 +02:00
Tomáš Hrnčiar 614cafc400 Update to 3.12.0rc2 2023-09-06 14:15:23 +02:00
Tomáš Hrnčiar 67ba754f51 Temporarily skip test_check_probes in CI tests
See: https://github.com/python/cpython/issues/104280#issuecomment-1669249980
2023-08-29 16:20:07 +02:00
Tomáš Hrnčiar 0483fca31a Update to 3.12.0rc1 2023-08-08 16:16:05 +02:00
Charalampos Stratakis 1f830e372b Remove extra distro-applied CFLAGS passed to user-built C extensions
Only -fexceptions and -fcf-protection are preserved for binary
compatibility with user-built python C extension.

https://fedoraproject.org/wiki/Changes/Python_Extension_Flags_Reduction
2023-08-04 16:06:57 +02:00
Fedora Release Engineering 88668cf1f4 Rebuilt for https://fedoraproject.org/wiki/Fedora_39_Mass_Rebuild
Signed-off-by: Fedora Release Engineering <releng@fedoraproject.org>
2023-07-21 15:42:31 +00:00
Miro Hrončok bc99d88db7 Update to 3.12.0b4
Patch 402 is part of this release.
2023-07-12 07:01:20 +02:00
Tomáš Hrnčiar 2d8f888430 Backport upstream patch to add PyType_GetDict() function 2023-06-21 10:04:34 +02:00
Tomáš Hrnčiar 8522651180 Update to 3.12.0b3 2023-06-20 18:45:12 +02:00
9 changed files with 668 additions and 104 deletions

View File

@ -30,10 +30,10 @@ Co-authored-by: Lumír Balhar <frenzy.madness@gmail.com>
3 files changed, 71 insertions(+), 4 deletions(-)
diff --git a/Lib/site.py b/Lib/site.py
index 672fa7b000..0a9c5be53e 100644
index 924b2460d9..51b5baca93 100644
--- a/Lib/site.py
+++ b/Lib/site.py
@@ -377,8 +377,15 @@ def getsitepackages(prefixes=None):
@@ -387,8 +387,15 @@ def getsitepackages(prefixes=None):
return sitepackages
def addsitepackages(known_paths, prefixes=None):

View File

@ -16,10 +16,10 @@ https://github.com/GrahamDumpleton/mod_wsgi/issues/730
2 files changed, 8 insertions(+), 50 deletions(-)
diff --git a/Lib/test/test_threading.py b/Lib/test/test_threading.py
index 9e4972ecb6..6f081d8f38 100644
index 00d9e591c7..3314319fec 100644
--- a/Lib/test/test_threading.py
+++ b/Lib/test/test_threading.py
@@ -987,39 +987,6 @@ def noop(): pass
@@ -1089,39 +1089,6 @@ def noop(): pass
threading.Thread(target=noop).start()
# Thread.join() is not called
@ -60,10 +60,10 @@ index 9e4972ecb6..6f081d8f38 100644
code = """if 1:
import atexit
diff --git a/Lib/threading.py b/Lib/threading.py
index df273870fa..eba297776d 100644
index 98cb43c697..ee647f8549 100644
--- a/Lib/threading.py
+++ b/Lib/threading.py
@@ -1565,29 +1565,20 @@ def _shutdown():
@@ -1585,29 +1585,20 @@ def _shutdown():
global _SHUTTING_DOWN
_SHUTTING_DOWN = True

View File

@ -1,58 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= <miro@hroncok.cz>
Date: Mon, 29 May 2023 15:51:16 +0200
Subject: [PATCH] 00401: Tests: Use setuptools+wheel from
sysconfig.get_config_var('WHEEL_PKG_DIR') if set
Proposed upstream https://github.com/python/cpython/pull/105056
---
Lib/test/support/__init__.py | 21 +++++++++++++++++++++
Lib/test/test_cppext.py | 4 ++--
2 files changed, 23 insertions(+), 2 deletions(-)
diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py
index d555c53fee..adc3f5901d 100644
--- a/Lib/test/support/__init__.py
+++ b/Lib/test/support/__init__.py
@@ -2398,5 +2398,26 @@ def adjust_int_max_str_digits(max_digits):
finally:
sys.set_int_max_str_digits(current)
+
+@functools.cache
+def _findwheel(pkgname):
+ """Try to find a wheel with the package specified as pkgname.
+
+ If set, the wheels are searched for in WHEEL_PKG_DIR (see ensurepip).
+ Otherwise, they are searched for in the test directory.
+ """
+ wheel_dir = sysconfig.get_config_var('WHEEL_PKG_DIR') or TEST_HOME_DIR
+ filenames = os.listdir(wheel_dir)
+ filenames = sorted(filenames) # sort this like ensurepip does it
+ for filename in filenames:
+ # filename is like 'pip-21.2.4-py3-none-any.whl'
+ if not filename.endswith(".whl"):
+ continue
+ prefix = pkgname + '-'
+ if filename.startswith(prefix):
+ return os.path.join(wheel_dir, filename)
+ raise FileNotFoundError(f"No wheel for {pkgname} found in {wheel_dir}")
+
+
#For recursion tests, easily exceeds default recursion limit
EXCEEDS_RECURSION_LIMIT = 5000
diff --git a/Lib/test/test_cppext.py b/Lib/test/test_cppext.py
index 4fb62d87e8..d124220dac 100644
--- a/Lib/test/test_cppext.py
+++ b/Lib/test/test_cppext.py
@@ -83,8 +83,8 @@ def run_cmd(operation, cmd):
cmd = [python, '-X', 'dev',
'-m', 'pip', 'install',
- support.findfile('setuptools-67.6.1-py3-none-any.whl'),
- support.findfile('wheel-0.40.0-py3-none-any.whl')]
+ support._findwheel('setuptools'),
+ support._findwheel('wheel')]
run_cmd('Install build dependencies', cmd)
# Build and install the C++ extension

View File

@ -0,0 +1,483 @@
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 345b64001c..d693a9bc39 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 aa949aa933..af2fb14754 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 2a237095b9..4672b790d8 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
@@ -3337,15 +3338,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"""
@@ -3536,6 +3659,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.

View File

@ -0,0 +1,36 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Karolina Surma <ksurma@redhat.com>
Date: Thu, 8 Feb 2024 15:53:26 +0100
Subject: [PATCH] 00418: Don't generate sbom in make regen-all
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The script and make target, added in Python 3.12.2, assumes a fixed
location of pip wheel and other bundled libraries, resulting in an
error and failed build when not found.
Reported upstream: https://github.com/python/cpython/issues/114240
and https://github.com/python/cpython/issues/114244
Co-Authored-By: Tomáš Hrnčiar <thrnciar@redhat.com>
---
Makefile.pre.in | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/Makefile.pre.in b/Makefile.pre.in
index dd5e69f7ab..40097647b5 100644
--- a/Makefile.pre.in
+++ b/Makefile.pre.in
@@ -1320,9 +1320,10 @@ regen-limited-abi: all
regen-all: regen-cases regen-opcode regen-opcode-targets regen-typeslots \
regen-token regen-ast regen-keyword regen-sre regen-frozen \
regen-pegen-metaparser regen-pegen regen-test-frozenmain \
- regen-test-levenshtein regen-global-objects regen-sbom
+ regen-test-levenshtein regen-global-objects
@echo
- @echo "Note: make regen-stdlib-module-names and make regen-configure should be run manually"
+ @echo "Note: make regen-stdlib-module-names, make regen-configure and make regen-sbom "
+ @echo "should be run manually"
############################################################################
# Special rules for object files

View File

@ -16,9 +16,11 @@ LEVELS = (None, 1, 2)
# list of globs of test and other files that we expect not to have bytecode
not_compiled = [
'/usr/bin/*',
'*/test/bad_coding.py',
'*/test/bad_coding2.py',
'*/test/badsyntax_*.py',
'*/tokenizedata/bad_coding.py',
'*/tokenizedata/bad_coding2.py',
'*/tokenizedata/badsyntax_*.py',
'*/test_future_stmt/badsyntax_*.py',
'*/test_lib2to3/data/*.py',
'*/test_lib2to3/data/*/*.py',
'*/test_lib2to3/data/*/*/*.py',

View File

@ -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}.0
%global prerel b2
%global general_version %{pybasever}.2
#global prerel ...
%global upstream_version %{general_version}%{?prerel}
Version: %{general_version}%{?prerel:~%{prerel}}
Release: 3%{?dist}
Release: 1.0.riscv64%{?dist}
License: Python-2.0.1
@ -71,35 +71,36 @@ License: Python-2.0.1
# If the rpmwheels condition is disabled, we use the bundled wheel packages
# from Python with the versions below.
# This needs to be manually updated when we update Python.
%global pip_version 23.1.2
%global pip_version 24.0
%global setuptools_version 67.6.1
%global wheel_version 0.40.0
# All of those also include a list of indirect bundled libs:
# pip
# $ %%{_rpmconfigdir}/pythonbundles.py <(unzip -p Lib/ensurepip/_bundled/pip-*.whl pip/_vendor/vendor.txt)
%global pip_bundled_provides %{expand:
Provides: bundled(python3dist(cachecontrol)) = 0.12.11
Provides: bundled(python3dist(certifi)) = 2022.12.7
Provides: bundled(python3dist(cachecontrol)) = 0.13.1
Provides: bundled(python3dist(certifi)) = 2023.7.22
Provides: bundled(python3dist(chardet)) = 5.1
Provides: bundled(python3dist(colorama)) = 0.4.6
Provides: bundled(python3dist(distlib)) = 0.3.6
Provides: bundled(python3dist(distlib)) = 0.3.8
Provides: bundled(python3dist(distro)) = 1.8
Provides: bundled(python3dist(idna)) = 3.4
Provides: bundled(python3dist(msgpack)) = 1.0.5
Provides: bundled(python3dist(packaging)) = 21.3
Provides: bundled(python3dist(platformdirs)) = 3.2
Provides: bundled(python3dist(pygments)) = 2.14
Provides: bundled(python3dist(pyparsing)) = 3.0.9
Provides: bundled(python3dist(platformdirs)) = 3.8.1
Provides: bundled(python3dist(pygments)) = 2.15.1
Provides: bundled(python3dist(pyparsing)) = 3.1
Provides: bundled(python3dist(pyproject-hooks)) = 1
Provides: bundled(python3dist(requests)) = 2.28.2
Provides: bundled(python3dist(requests)) = 2.31
Provides: bundled(python3dist(resolvelib)) = 1.0.1
Provides: bundled(python3dist(rich)) = 13.3.3
Provides: bundled(python3dist(setuptools)) = 67.7.2
Provides: bundled(python3dist(rich)) = 13.4.2
Provides: bundled(python3dist(setuptools)) = 68
Provides: bundled(python3dist(six)) = 1.16
Provides: bundled(python3dist(tenacity)) = 8.2.2
Provides: bundled(python3dist(tomli)) = 2.0.1
Provides: bundled(python3dist(typing-extensions)) = 4.5
Provides: bundled(python3dist(urllib3)) = 1.26.15
Provides: bundled(python3dist(truststore)) = 0.8
Provides: bundled(python3dist(typing-extensions)) = 4.7.1
Provides: bundled(python3dist(urllib3)) = 1.26.17
Provides: bundled(python3dist(webencodings)) = 0.5.1
}
# setuptools
@ -121,7 +122,7 @@ Provides: bundled(python3dist(typing-extensions)) = 4.4
Provides: bundled(python3dist(zipp)) = 3.7
}
# wheel
# $ %%{_rpmconfigdir}/pythonbundles.py <(unzip -p Lib/test/wheel-*.whl wheel/vendored/vendor.txt)
# $ %%{_rpmconfigdir}/pythonbundles.py <(unzip -p Lib/test/wheeldata/wheel-*.whl wheel/vendored/vendor.txt)
%global wheel_bundled_provides %{expand:
Provides: bundled(python3dist(packaging)) = 23
}
@ -255,7 +256,9 @@ BuildRequires: glibc-devel
BuildRequires: gmp-devel
BuildRequires: gnupg2
BuildRequires: libappstream-glib
%if %{undefined rhel}
BuildRequires: libb2-devel
%endif
BuildRequires: libffi-devel
BuildRequires: libnsl2-devel
BuildRequires: libtirpc-devel
@ -308,6 +311,9 @@ BuildRequires: %{python_wheel_pkg_prefix}-wheel-wheel
# upgrading the main python3 to a new Python version, this would pull in the
# old version instead.
BuildRequires: python%{pybasever}
%endif
%if %{without bootstrap} || %{without main_python}
# for proper automatic provides
BuildRequires: python3-rpm-generators
%endif
@ -362,11 +368,24 @@ Patch251: 00251-change-user-install-location.patch
# https://github.com/GrahamDumpleton/mod_wsgi/issues/730
Patch371: 00371-revert-bpo-1596321-fix-threading-_shutdown-for-the-main-thread-gh-28549-gh-28589.patch
# 00401 # 48310af24b090719553bf0e9c965d80524e0b40e
# Tests: Use setuptools+wheel from sysconfig.get_config_var('WHEEL_PKG_DIR') if set
# 00415 # 5b830b814be638d1a167802780b5f498a4a5e97c
# [CVE-2023-27043] gh-102988: Reject malformed addresses in email.parseaddr() (#111116)
#
# Proposed upstream https://github.com/python/cpython/pull/105056
Patch401: 00401-tests-use-setuptools-wheel-from-sysconfig-get_config_var-wheel_pkg_dir-if-set.patch
# 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
# 00418 # 153905265371131e1227ace0dfef34a5c5efde59
# Don't generate sbom in make regen-all
#
# The script and make target, added in Python 3.12.2, assumes a fixed
# location of pip wheel and other bundled libraries, resulting in an
# error and failed build when not found.
# Reported upstream: https://github.com/python/cpython/issues/114240
# and https://github.com/python/cpython/issues/114244
Patch418: 00418-don-t-generate-sbom-in-make-regen-all.patch
# (New patches go here ^^^)
#
@ -490,15 +509,21 @@ 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-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-2.0.1 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)
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
# Bundled internal headers are used even when building with system libb2
# last updated by https://github.com/python/cpython/pull/6286
Provides: bundled(libb2) = 0.98.1
# There are files in the standard library that have python shebang.
# We've filtered the automatic requirement out so libs are installable without
# the main package. This however makes it pulled in by default.
@ -544,7 +569,8 @@ Recommends: %{pkgname}-pip
# tox users are likely to need the devel subpackage
Supplements: tox
%if %{without bootstrap}
%if %{without bootstrap} || %{without main_python}
# Generators run on the main Python 3 so we cannot require them when bootstrapping it
Requires: (python3-rpm-generators if rpm-build)
%endif
@ -682,13 +708,13 @@ The debug runtime additionally supports debug builds of C-API extensions
# setuptools.whl does not contain the vendored.txt files
if [ -f %{_rpmconfigdir}/pythonbundles.py ]; then
%{_rpmconfigdir}/pythonbundles.py <(unzip -p Lib/ensurepip/_bundled/pip-*.whl pip/_vendor/vendor.txt) --compare-with '%pip_bundled_provides'
%{_rpmconfigdir}/pythonbundles.py <(unzip -p Lib/test/wheel-*.whl wheel/vendored/vendor.txt) --compare-with '%wheel_bundled_provides'
%{_rpmconfigdir}/pythonbundles.py <(unzip -p Lib/test/wheeldata/wheel-*.whl wheel/vendored/vendor.txt) --compare-with '%wheel_bundled_provides'
fi
%if %{with rpmwheels}
rm Lib/ensurepip/_bundled/pip-%{pip_version}-py3-none-any.whl
rm Lib/test/setuptools-%{setuptools_version}-py3-none-any.whl
rm Lib/test/wheel-%{wheel_version}-py3-none-any.whl
rm Lib/test/wheeldata/setuptools-%{setuptools_version}-py3-none-any.whl
rm Lib/test/wheeldata/wheel-%{wheel_version}-py3-none-any.whl
%endif
# Remove all exe files to ensure we are not shipping prebuilt binaries
@ -745,14 +771,15 @@ topdir=$(pwd)
# Standard library built here will still use the %%build_...flags,
# Fedora packages utilizing %%py3_build will use them as well
# https://fedoraproject.org/wiki/Changes/Python_Extension_Flags
export CFLAGS="%{extension_cflags} -D_GNU_SOURCE -fPIC -fwrapv"
# https://fedoraproject.org/wiki/Changes/Python_Extension_Flags_Reduction
export CFLAGS="%{extension_cflags}"
export CFLAGS_NODIST="%{build_cflags} -D_GNU_SOURCE -fPIC -fwrapv"
export CXXFLAGS="%{extension_cxxflags} -D_GNU_SOURCE -fPIC -fwrapv"
export CXXFLAGS="%{extension_cxxflags}"
export CPPFLAGS="$(pkg-config --cflags-only-I libffi)"
export OPT="%{extension_cflags} -D_GNU_SOURCE -fPIC -fwrapv"
export OPT="%{extension_cflags}"
export LINKCC="gcc"
export CFLAGS="$CFLAGS $(pkg-config --cflags openssl)"
export LDFLAGS="%{extension_ldflags} -g $(pkg-config --libs-only-L openssl)"
export LDFLAGS="%{extension_ldflags} $(pkg-config --libs-only-L openssl)"
export LDFLAGS_NODIST="%{build_ldflags} -g $(pkg-config --libs-only-L openssl)"
# We can build several different configurations of Python: regular and debug.
@ -1145,10 +1172,23 @@ CheckPython() {
# test_freeze_simple_script is skipped, because it fails without bundled libs.
# the freeze tool is only usable from the source checkout anyway,
# we don't ship it in the RPM package.
# test_check_probes is failing since it was introduced in 3.12.0rc1,
# the test is skipped until it is fixed in upstream.
# see: https://github.com/python/cpython/issues/104280#issuecomment-1669249980
LD_LIBRARY_PATH=$ConfDir $ConfDir/python -m test.regrtest \
-wW --slowest %{_smp_mflags} --timeout=2700 \
-wW --slowest %{_smp_mflags} \
%ifnarch riscv64
--timeout=2700 \
%else
--timeout=27000 \
%endif
-i test_freeze_simple_script \
-i test_check_probes \
%ifarch riscv64
-x test_eintr \
-x test_peg_generator \
%endif
%ifarch %{mips64}
-x test_ctypes \
%endif
@ -1381,6 +1421,7 @@ CheckPython optimized
%{pylibdir}/multiprocessing
%dir %{pylibdir}/re/
%dir %{pylibdir}/re/__pycache__/
%{pylibdir}/re/*.py
%{pylibdir}/re/__pycache__/*%{bytecode_suffixes}
@ -1390,6 +1431,7 @@ CheckPython optimized
%{pylibdir}/sqlite3/__pycache__/*%{bytecode_suffixes}
%dir %{pylibdir}/tomllib/
%dir %{pylibdir}/tomllib/__pycache__/
%{pylibdir}/tomllib/*.py
%{pylibdir}/tomllib/__pycache__/*%{bytecode_suffixes}
%exclude %{pylibdir}/turtle.py
@ -1399,12 +1441,18 @@ CheckPython optimized
%{pylibdir}/xml
%dir %{pylibdir}/zipfile/
%dir %{pylibdir}/zipfile/__pycache__/
%{pylibdir}/zipfile/*.py
%{pylibdir}/zipfile/__pycache__/*%{bytecode_suffixes}
%dir %{pylibdir}/zipfile/_path/
%dir %{pylibdir}/zipfile/_path/__pycache__/
%{pylibdir}/zipfile/_path/*.py
%{pylibdir}/zipfile/_path/__pycache__/*%{bytecode_suffixes}
%{pylibdir}/zoneinfo
%dir %{pylibdir}/__phello__
%dir %{pylibdir}/__phello__/
%dir %{pylibdir}/__phello__/__pycache__/
%{pylibdir}/__phello__/__init__.py
%{pylibdir}/__phello__/spam.py
%{pylibdir}/__phello__/__pycache__/*%{bytecode_suffixes}
@ -1657,6 +1705,59 @@ CheckPython optimized
# ======================================================
%changelog
* Wed Feb 21 2024 David Abdurachmanov <davidlt@rivosinc.com> - 3.12.2-2.3.riscv64
- Disable test_peg_generator test on riscv64.
- Increase tests timeout on riscv64 by 10x.
- Disable test_eintr test on riscv64.
* Wed Feb 07 2024 Tomáš Hrnčiar <thrnciar@redhat.com> - 3.12.2-1
- Update to 3.12.2
* Fri Jan 26 2024 Fedora Release Engineering <releng@fedoraproject.org> - 3.12.1-4
- Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild
* 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

View File

@ -1,2 +1,2 @@
SHA512 (Python-3.12.0b2.tar.xz) = 9bfac70f2ccc1f6798bc63a55d92f0b162e3a9077624a2e37448002ea310cb7b1da64ad2aceda795b45de91f60eb4d95dde85984900e54906d814625b42143b5
SHA512 (Python-3.12.0b2.tar.xz.asc) = 22a1f2c3335bc428cfee0ce2e081aeed24474d3cd877fac1cc4cf92b4a2bee70f85aed0068a71600cddef9c8b46bbde257a92c57bd494ad820c0686ab7c8c0f0
SHA512 (Python-3.12.2.tar.xz) = 2ccfae7b9f95d8e15ea85d3f66eea5f6a8fdcaffc0b405095fecb33efc0df50b831c1215542910ced948b54e6de1f7242b0b8b9afc5f89079451c552430d7d9f
SHA512 (Python-3.12.2.tar.xz.asc) = fb477acb49864a662b1586db79e80fd8ebab85d4e5e14acd3bfb5afc3dbe8d6b9bf97eb518dfb77662e27040d400f451ed7575fe1264a6cc0d9feb06e4f2dc84

View File

@ -21,19 +21,19 @@
run: rpm -qa
- smoke:
dir: python/smoke
run: "VERSION={{ pybasever }} CYTHON=false ./venv.sh"
run: "VERSION={{ pybasever }} ./venv.sh"
- smoke_virtualenv:
dir: python/smoke
run: "VERSION={{ pybasever }} METHOD=virtualenv CYTHON=false ./venv.sh"
run: "VERSION={{ pybasever }} METHOD=virtualenv ./venv.sh"
- debugsmoke:
dir: python/smoke
run: "PYTHON=python{{ pybasever }}d TOX=false VERSION={{ pybasever }} CYTHON=false ./venv.sh"
run: "PYTHON=python{{ pybasever }}d TOX=false VERSION={{ pybasever }} ./venv.sh"
- selftest:
dir: python/selftest
run: "VERSION={{ pybasever }} X='' ./parallel.sh"
run: "VERSION={{ pybasever }} X='-i test_check_probes' ./parallel.sh"
- debugtest:
dir: python/selftest
run: "VERSION={{ pybasever }} PYTHON=python{{ pybasever }}d X='' ./parallel.sh"
run: "VERSION={{ pybasever }} PYTHON=python{{ pybasever }}d X='-i test_check_probes' ./parallel.sh"
- debugflags:
dir: python/flags
run: "python{{ pybasever }}d ./assertflags.py -O0"