Skip to content

Commit af0616d

Browse files
[AUTO-CHERRYPICK] Fix CVE-2023-27043 [MEDIUM] in python3 by patching - branch main (#12327)
Co-authored-by: Bala <kumaran.4353@gmail.com>
1 parent e827d1a commit af0616d

6 files changed

Lines changed: 254 additions & 27 deletions

File tree

SPECS/python3/CVE-2023-27043.patch

Lines changed: 222 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
1+
From f79d810ddc98eb7650c6f613cf01b77e2eb7368f Mon Sep 17 00:00:00 2001
2+
From: Balakumaran Kannan <kumaran.4353@gmail.com>
3+
Date: Thu, 30 Jan 2025 05:22:45 +0000
4+
Subject: [PATCH] Return empty tuple to indicate the email parsing error.
5+
6+
Cut short version of original patch taken from below commit
7+
Taking the changes only for Lib/email/utils.py
8+
9+
10+
From ee953f2b8fc12ee9b8209ab60a2f06c603e5a624 Mon Sep 17 00:00:00 2001
11+
From: Petr Viktorin <encukou@gmail.com>
12+
Date: Fri, 6 Sep 2024 13:13:54 +0200
13+
Subject: [PATCH] [3.9] [CVE-2023-27043] gh-102988: Reject malformed addresses
14+
in email.parseaddr() (GH-111116) (#123769)
15+
16+
Detect email address parsing errors and return empty tuple to
17+
indicate the parsing error (old API). Add an optional 'strict'
18+
parameter to getaddresses() and parseaddr() functions. Patch by
19+
Thomas Dwyer.
20+
21+
(cherry picked from commit 4a153a1d3b18803a684cd1bcc2cdf3ede3dbae19)
22+
23+
Co-authored-by: Victor Stinner <vstinner@python.org>
24+
Co-Authored-By: Thomas Dwyer <github@tomd.tel>
25+
26+
Doc/library/email.utils.rst | 19 +-
27+
Doc/whatsnew/3.9.rst | 10 +
28+
Lib/email/utils.py | 151 ++++++++++++-
29+
Lib/test/test_email/test_email.py | 204 +++++++++++++++++-
30+
...-10-20-15-28-08.gh-issue-102988.dStNO7.rst | 8 +
31+
5 files changed, 371 insertions(+), 21 deletions(-)
32+
33+
---
34+
Lib/email/utils.py | 151 ++++++++++++++++++++++++++++++++++++++++++---
35+
1 file changed, 142 insertions(+), 9 deletions(-)
36+
37+
diff --git a/Lib/email/utils.py b/Lib/email/utils.py
38+
index 48d30160aa6..7ca7a7c8867 100644
39+
--- a/Lib/email/utils.py
40+
+++ b/Lib/email/utils.py
41+
@@ -48,6 +48,7 @@ TICK = "'"
42+
specialsre = re.compile(r'[][\\()<>@,:;".]')
43+
escapesre = re.compile(r'[\\"]')
44+
45+
+
46+
def _has_surrogates(s):
47+
"""Return True if s contains surrogate-escaped binary data."""
48+
# This check is based on the fact that unless there are surrogates, utf8
49+
@@ -106,12 +107,127 @@ def formataddr(pair, charset='utf-8'):
50+
return address
51+
52+
53+
+def _iter_escaped_chars(addr):
54+
+ pos = 0
55+
+ escape = False
56+
+ for pos, ch in enumerate(addr):
57+
+ if escape:
58+
+ yield (pos, '\\' + ch)
59+
+ escape = False
60+
+ elif ch == '\\':
61+
+ escape = True
62+
+ else:
63+
+ yield (pos, ch)
64+
+ if escape:
65+
+ yield (pos, '\\')
66+
+
67+
+
68+
+def _strip_quoted_realnames(addr):
69+
+ """Strip real names between quotes."""
70+
+ if '"' not in addr:
71+
+ # Fast path
72+
+ return addr
73+
+
74+
+ start = 0
75+
+ open_pos = None
76+
+ result = []
77+
+ for pos, ch in _iter_escaped_chars(addr):
78+
+ if ch == '"':
79+
+ if open_pos is None:
80+
+ open_pos = pos
81+
+ else:
82+
+ if start != open_pos:
83+
+ result.append(addr[start:open_pos])
84+
+ start = pos + 1
85+
+ open_pos = None
86+
+
87+
+ if start < len(addr):
88+
+ result.append(addr[start:])
89+
+
90+
+ return ''.join(result)
91+
92+
-def getaddresses(fieldvalues):
93+
- """Return a list of (REALNAME, EMAIL) for each fieldvalue."""
94+
- all = COMMASPACE.join(str(v) for v in fieldvalues)
95+
- a = _AddressList(all)
96+
- return a.addresslist
97+
+
98+
+supports_strict_parsing = True
99+
+
100+
+def getaddresses(fieldvalues, *, strict=True):
101+
+ """Return a list of (REALNAME, EMAIL) or ('','') for each fieldvalue.
102+
+
103+
+ When parsing fails for a fieldvalue, a 2-tuple of ('', '') is returned in
104+
+ its place.
105+
+
106+
+ If strict is true, use a strict parser which rejects malformed inputs.
107+
+ """
108+
+
109+
+ # If strict is true, if the resulting list of parsed addresses is greater
110+
+ # than the number of fieldvalues in the input list, a parsing error has
111+
+ # occurred and consequently a list containing a single empty 2-tuple [('',
112+
+ # '')] is returned in its place. This is done to avoid invalid output.
113+
+ #
114+
+ # Malformed input: getaddresses(['alice@example.com <bob@example.com>'])
115+
+ # Invalid output: [('', 'alice@example.com'), ('', 'bob@example.com')]
116+
+ # Safe output: [('', '')]
117+
+
118+
+ if not strict:
119+
+ all = COMMASPACE.join(str(v) for v in fieldvalues)
120+
+ a = _AddressList(all)
121+
+ return a.addresslist
122+
+
123+
+ fieldvalues = [str(v) for v in fieldvalues]
124+
+ fieldvalues = _pre_parse_validation(fieldvalues)
125+
+ addr = COMMASPACE.join(fieldvalues)
126+
+ a = _AddressList(addr)
127+
+ result = _post_parse_validation(a.addresslist)
128+
+
129+
+ # Treat output as invalid if the number of addresses is not equal to the
130+
+ # expected number of addresses.
131+
+ n = 0
132+
+ for v in fieldvalues:
133+
+ # When a comma is used in the Real Name part it is not a deliminator.
134+
+ # So strip those out before counting the commas.
135+
+ v = _strip_quoted_realnames(v)
136+
+ # Expected number of addresses: 1 + number of commas
137+
+ n += 1 + v.count(',')
138+
+ if len(result) != n:
139+
+ return [('', '')]
140+
+
141+
+ return result
142+
+
143+
+
144+
+def _check_parenthesis(addr):
145+
+ # Ignore parenthesis in quoted real names.
146+
+ addr = _strip_quoted_realnames(addr)
147+
+
148+
+ opens = 0
149+
+ for pos, ch in _iter_escaped_chars(addr):
150+
+ if ch == '(':
151+
+ opens += 1
152+
+ elif ch == ')':
153+
+ opens -= 1
154+
+ if opens < 0:
155+
+ return False
156+
+ return (opens == 0)
157+
+
158+
+
159+
+def _pre_parse_validation(email_header_fields):
160+
+ accepted_values = []
161+
+ for v in email_header_fields:
162+
+ if not _check_parenthesis(v):
163+
+ v = "('', '')"
164+
+ accepted_values.append(v)
165+
+
166+
+ return accepted_values
167+
+
168+
+
169+
+def _post_parse_validation(parsed_email_header_tuples):
170+
+ accepted_values = []
171+
+ # The parser would have parsed a correctly formatted domain-literal
172+
+ # The existence of an [ after parsing indicates a parsing failure
173+
+ for v in parsed_email_header_tuples:
174+
+ if '[' in v[1]:
175+
+ v = ('', '')
176+
+ accepted_values.append(v)
177+
+
178+
+ return accepted_values
179+
180+
181+
def _format_timetuple_and_zone(timetuple, zone):
182+
@@ -202,16 +318,33 @@ def parsedate_to_datetime(data):
183+
tzinfo=datetime.timezone(datetime.timedelta(seconds=tz)))
184+
185+
186+
-def parseaddr(addr):
187+
+def parseaddr(addr, *, strict=True):
188+
"""
189+
Parse addr into its constituent realname and email address parts.
190+
191+
Return a tuple of realname and email address, unless the parse fails, in
192+
which case return a 2-tuple of ('', '').
193+
+
194+
+ If strict is True, use a strict parser which rejects malformed inputs.
195+
"""
196+
- addrs = _AddressList(addr).addresslist
197+
- if not addrs:
198+
- return '', ''
199+
+ if not strict:
200+
+ addrs = _AddressList(addr).addresslist
201+
+ if not addrs:
202+
+ return ('', '')
203+
+ return addrs[0]
204+
+
205+
+ if isinstance(addr, list):
206+
+ addr = addr[0]
207+
+
208+
+ if not isinstance(addr, str):
209+
+ return ('', '')
210+
+
211+
+ addr = _pre_parse_validation([addr])[0]
212+
+ addrs = _post_parse_validation(_AddressList(addr).addresslist)
213+
+
214+
+ if not addrs or len(addrs) > 1:
215+
+ return ('', '')
216+
+
217+
return addrs[0]
218+
219+
220+
--
221+
2.39.4
222+

SPECS/python3/python3.spec

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
Summary: A high-level scripting language
1313
Name: python3
1414
Version: 3.9.19
15-
Release: 8%{?dist}
15+
Release: 9%{?dist}
1616
License: PSF
1717
Vendor: Microsoft Corporation
1818
Distribution: Mariner
@@ -29,6 +29,7 @@ Patch5: CVE-2024-8088.patch
2929
Patch6: CVE-2024-4032.patch
3030
Patch7: CVE-2024-11168.patch
3131
Patch8: CVE-2024-6923.patch
32+
Patch9: CVE-2023-27043.patch
3233
# Patch for setuptools, resolved in 65.5.1
3334
Patch1000: CVE-2022-40897.patch
3435
Patch1001: CVE-2024-6345.patch
@@ -175,6 +176,7 @@ The test package contains all regression tests for Python as well as the modules
175176
%patch6 -p1
176177
%patch7 -p1
177178
%patch8 -p1
179+
%patch9 -p1
178180

179181
%build
180182
# Remove GCC specs and build environment linker scripts
@@ -330,6 +332,9 @@ rm -rf %{buildroot}%{_bindir}/__pycache__
330332
%{_libdir}/python%{majmin}/test/*
331333

332334
%changelog
335+
* Mon Feb 03 2024 Bala <balakumaran.kannan@microsoft.com> - 3.9.19-9
336+
- Address CVE-2023-27043 by patching
337+
333338
* Thu Nov 28 2024 Kanishk Bansal <kanbansal@microsoft.com> - 3.9.19-8
334339
- Address CVE-2024-6923
335340

toolkit/resources/manifests/package/pkggen_core_aarch64.txt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -237,10 +237,10 @@ ca-certificates-base-2.0.0-19.cm2.noarch.rpm
237237
ca-certificates-2.0.0-19.cm2.noarch.rpm
238238
dwz-0.14-2.cm2.aarch64.rpm
239239
unzip-6.0-21.cm2.aarch64.rpm
240-
python3-3.9.19-8.cm2.aarch64.rpm
241-
python3-devel-3.9.19-8.cm2.aarch64.rpm
242-
python3-libs-3.9.19-8.cm2.aarch64.rpm
243-
python3-setuptools-3.9.19-8.cm2.noarch.rpm
240+
python3-3.9.19-9.cm2.aarch64.rpm
241+
python3-devel-3.9.19-9.cm2.aarch64.rpm
242+
python3-libs-3.9.19-9.cm2.aarch64.rpm
243+
python3-setuptools-3.9.19-9.cm2.noarch.rpm
244244
python3-pygments-2.4.2-7.cm2.noarch.rpm
245245
which-2.21-8.cm2.aarch64.rpm
246246
libselinux-3.2-1.cm2.aarch64.rpm

toolkit/resources/manifests/package/pkggen_core_x86_64.txt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -237,10 +237,10 @@ ca-certificates-base-2.0.0-19.cm2.noarch.rpm
237237
ca-certificates-2.0.0-19.cm2.noarch.rpm
238238
dwz-0.14-2.cm2.x86_64.rpm
239239
unzip-6.0-21.cm2.x86_64.rpm
240-
python3-3.9.19-8.cm2.x86_64.rpm
241-
python3-devel-3.9.19-8.cm2.x86_64.rpm
242-
python3-libs-3.9.19-8.cm2.x86_64.rpm
243-
python3-setuptools-3.9.19-8.cm2.noarch.rpm
240+
python3-3.9.19-9.cm2.x86_64.rpm
241+
python3-devel-3.9.19-9.cm2.x86_64.rpm
242+
python3-libs-3.9.19-9.cm2.x86_64.rpm
243+
python3-setuptools-3.9.19-9.cm2.noarch.rpm
244244
python3-pygments-2.4.2-7.cm2.noarch.rpm
245245
which-2.21-8.cm2.x86_64.rpm
246246
libselinux-3.2-1.cm2.x86_64.rpm

toolkit/resources/manifests/package/toolchain_aarch64.txt

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -510,28 +510,28 @@ procps-ng-devel-3.3.17-2.cm2.aarch64.rpm
510510
procps-ng-lang-3.3.17-2.cm2.aarch64.rpm
511511
pyproject-rpm-macros-1.0.0~rc1-4.cm2.noarch.rpm
512512
python-markupsafe-debuginfo-2.1.0-1.cm2.aarch64.rpm
513-
python3-3.9.19-8.cm2.aarch64.rpm
513+
python3-3.9.19-9.cm2.aarch64.rpm
514514
python3-audit-3.0.6-8.cm2.aarch64.rpm
515515
python3-cracklib-2.9.7-5.cm2.aarch64.rpm
516-
python3-curses-3.9.19-8.cm2.aarch64.rpm
516+
python3-curses-3.9.19-9.cm2.aarch64.rpm
517517
python3-Cython-0.29.33-2.cm2.aarch64.rpm
518-
python3-debuginfo-3.9.19-8.cm2.aarch64.rpm
519-
python3-devel-3.9.19-8.cm2.aarch64.rpm
518+
python3-debuginfo-3.9.19-9.cm2.aarch64.rpm
519+
python3-devel-3.9.19-9.cm2.aarch64.rpm
520520
python3-gpg-1.16.0-2.cm2.aarch64.rpm
521521
python3-jinja2-3.0.3-5.cm2.noarch.rpm
522522
python3-libcap-ng-0.8.2-2.cm2.aarch64.rpm
523-
python3-libs-3.9.19-8.cm2.aarch64.rpm
523+
python3-libs-3.9.19-9.cm2.aarch64.rpm
524524
python3-libxml2-2.10.4-5.cm2.aarch64.rpm
525525
python3-lxml-4.9.1-1.cm2.aarch64.rpm
526526
python3-magic-5.40-3.cm2.noarch.rpm
527527
python3-markupsafe-2.1.0-1.cm2.aarch64.rpm
528528
python3-newt-0.52.21-5.cm2.aarch64.rpm
529-
python3-pip-3.9.19-8.cm2.noarch.rpm
529+
python3-pip-3.9.19-9.cm2.noarch.rpm
530530
python3-pygments-2.4.2-7.cm2.noarch.rpm
531531
python3-rpm-4.18.0-4.cm2.aarch64.rpm
532-
python3-setuptools-3.9.19-8.cm2.noarch.rpm
533-
python3-test-3.9.19-8.cm2.aarch64.rpm
534-
python3-tools-3.9.19-8.cm2.aarch64.rpm
532+
python3-setuptools-3.9.19-9.cm2.noarch.rpm
533+
python3-test-3.9.19-9.cm2.aarch64.rpm
534+
python3-tools-3.9.19-9.cm2.aarch64.rpm
535535
readline-8.1-1.cm2.aarch64.rpm
536536
readline-debuginfo-8.1-1.cm2.aarch64.rpm
537537
readline-devel-8.1-1.cm2.aarch64.rpm

toolkit/resources/manifests/package/toolchain_x86_64.txt

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -516,28 +516,28 @@ procps-ng-devel-3.3.17-2.cm2.x86_64.rpm
516516
procps-ng-lang-3.3.17-2.cm2.x86_64.rpm
517517
pyproject-rpm-macros-1.0.0~rc1-4.cm2.noarch.rpm
518518
python-markupsafe-debuginfo-2.1.0-1.cm2.x86_64.rpm
519-
python3-3.9.19-8.cm2.x86_64.rpm
519+
python3-3.9.19-9.cm2.x86_64.rpm
520520
python3-audit-3.0.6-8.cm2.x86_64.rpm
521521
python3-cracklib-2.9.7-5.cm2.x86_64.rpm
522-
python3-curses-3.9.19-8.cm2.x86_64.rpm
522+
python3-curses-3.9.19-9.cm2.x86_64.rpm
523523
python3-Cython-0.29.33-2.cm2.x86_64.rpm
524-
python3-debuginfo-3.9.19-8.cm2.x86_64.rpm
525-
python3-devel-3.9.19-8.cm2.x86_64.rpm
524+
python3-debuginfo-3.9.19-9.cm2.x86_64.rpm
525+
python3-devel-3.9.19-9.cm2.x86_64.rpm
526526
python3-gpg-1.16.0-2.cm2.x86_64.rpm
527527
python3-jinja2-3.0.3-5.cm2.noarch.rpm
528528
python3-libcap-ng-0.8.2-2.cm2.x86_64.rpm
529-
python3-libs-3.9.19-8.cm2.x86_64.rpm
529+
python3-libs-3.9.19-9.cm2.x86_64.rpm
530530
python3-libxml2-2.10.4-5.cm2.x86_64.rpm
531531
python3-lxml-4.9.1-1.cm2.x86_64.rpm
532532
python3-magic-5.40-3.cm2.noarch.rpm
533533
python3-markupsafe-2.1.0-1.cm2.x86_64.rpm
534534
python3-newt-0.52.21-5.cm2.x86_64.rpm
535-
python3-pip-3.9.19-8.cm2.noarch.rpm
535+
python3-pip-3.9.19-9.cm2.noarch.rpm
536536
python3-pygments-2.4.2-7.cm2.noarch.rpm
537537
python3-rpm-4.18.0-4.cm2.x86_64.rpm
538-
python3-setuptools-3.9.19-8.cm2.noarch.rpm
539-
python3-test-3.9.19-8.cm2.x86_64.rpm
540-
python3-tools-3.9.19-8.cm2.x86_64.rpm
538+
python3-setuptools-3.9.19-9.cm2.noarch.rpm
539+
python3-test-3.9.19-9.cm2.x86_64.rpm
540+
python3-tools-3.9.19-9.cm2.x86_64.rpm
541541
readline-8.1-1.cm2.x86_64.rpm
542542
readline-debuginfo-8.1-1.cm2.x86_64.rpm
543543
readline-devel-8.1-1.cm2.x86_64.rpm

0 commit comments

Comments
 (0)