Skip to content

Commit 3749dca

Browse files
committed
python-3.11 - Address CVE-2023-27043
1 parent 0e91b4e commit 3749dca

File tree

4 files changed

+704
-0
lines changed

4 files changed

+704
-0
lines changed

python-3.11.yaml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,14 @@ pipeline:
4141
Modules/_ctypes/darwin* \
4242
Modules/_ctypes/libffi*
4343
44+
- uses: patch
45+
with:
46+
patches: CVE-2023-27043.patch
47+
48+
- uses: patch
49+
with:
50+
patches: CVE-2023-27043-enable-disable.patch
51+
4452
- name: Configure
4553
runs: |
4654
./configure \
@@ -79,6 +87,11 @@ pipeline:
7987
8088
- uses: strip
8189

90+
test:
91+
pipeline:
92+
- runs: |
93+
python3.12 CVE-2023-27043-unittest.py
94+
8295
subpackages:
8396
- name: "python-3.11-doc"
8497
description: "python3 documentation"
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
From 9e6732965b10ef8c0abfe799c208f14a23861340 Mon Sep 17 00:00:00 2001
2+
From: Scott Moser <smoser@chainguard.dev>
3+
Date: Tue, 27 Feb 2024 17:13:23 +0000
4+
Subject: [PATCH 2/2] Change default value for strict to be dependent on
5+
environment var
6+
7+
This follows the general solution described at:
8+
https://access.redhat.com/articles/7051467
9+
10+
The differences are:
11+
1. it does not support /etc/python/email.cfg
12+
2. environment variable is named PYTHON_EMAIL_STRICT_PARSING_DEFAULT
13+
It loosely controls the default 'strict' value of getaddresses and
14+
parseaddr.
15+
16+
If the variable is unset or set to any value other than 'false'
17+
or '0', then strict=True is used.
18+
19+
To opt out of this security fix, set the environment variable
20+
21+
PYTHON_EMAIL_STRICT_PARSING_DEFAULT=false
22+
---
23+
Lib/email/utils.py | 29 ++++++++++++++--
24+
Lib/test/test_email/test_email_notstrict.py | 38 +++++++++++++++++++++
25+
2 files changed, 65 insertions(+), 2 deletions(-)
26+
create mode 100644 Lib/test/test_email/test_email_notstrict.py
27+
28+
diff --git a/Lib/email/utils.py b/Lib/email/utils.py
29+
index 94ead0e91f..ce34122a83 100644
30+
--- a/Lib/email/utils.py
31+
+++ b/Lib/email/utils.py
32+
@@ -48,6 +48,8 @@
33+
specialsre = re.compile(r'[][\\()<>@,:;".]')
34+
escapesre = re.compile(r'[\\"]')
35+
36+
+_parseaddr_strict_default = None
37+
+
38+
39+
def _has_surrogates(s):
40+
"""Return True if s may contain surrogate-escaped binary data."""
41+
@@ -149,7 +151,7 @@ def _strip_quoted_realnames(addr):
42+
43+
supports_strict_parsing = True
44+
45+
-def getaddresses(fieldvalues, *, strict=True):
46+
+def getaddresses(fieldvalues, *, strict=None):
47+
"""Return a list of (REALNAME, EMAIL) or ('','') for each fieldvalue.
48+
49+
When parsing fails for a fieldvalue, a 2-tuple of ('', '') is returned in
50+
@@ -157,6 +159,7 @@ def getaddresses(fieldvalues, *, strict=True):
51+
52+
If strict is true, use a strict parser which rejects malformed inputs.
53+
"""
54+
+ strict = _get_default_parseaddr_strict(strict)
55+
56+
# If strict is true, if the resulting list of parsed addresses is greater
57+
# than the number of fieldvalues in the input list, a parsing error has
58+
@@ -321,7 +324,7 @@ def parsedate_to_datetime(data):
59+
tzinfo=datetime.timezone(datetime.timedelta(seconds=tz)))
60+
61+
62+
-def parseaddr(addr, *, strict=True):
63+
+def parseaddr(addr, *, strict=None):
64+
"""
65+
Parse addr into its constituent realname and email address parts.
66+
67+
@@ -330,6 +333,8 @@ def parseaddr(addr, *, strict=True):
68+
69+
If strict is True, use a strict parser which rejects malformed inputs.
70+
"""
71+
+ strict = _get_default_parseaddr_strict(strict)
72+
+
73+
if not strict:
74+
addrs = _AddressList(addr).addresslist
75+
if not addrs:
76+
@@ -351,6 +356,26 @@ def parseaddr(addr, *, strict=True):
77+
return addrs[0]
78+
79+
80+
+# get default value for strict parameter in parseaddr and getaddresses
81+
+def _get_default_parseaddr_strict(val):
82+
+ # non-None value passed into function, use it.
83+
+ if val is not None:
84+
+ return val
85+
+
86+
+ # consult or update the cached global.
87+
+ global _parseaddr_strict_default
88+
+
89+
+ if _parseaddr_strict_default is None:
90+
+ val = os.environ.get("PYTHON_EMAIL_STRICT_PARSING_DEFAULT", "true")
91+
+ # env var with 'false' explicitly disables the disabling (meaning strict=true)
92+
+ if val in ("false", "0"):
93+
+ _parseaddr_strict_default = False
94+
+ else:
95+
+ _parseaddr_strict_default = True
96+
+
97+
+ return _parseaddr_strict_default
98+
+
99+
+
100+
# rfc822.unquote() doesn't properly de-backslash-ify in Python pre-2.3.
101+
def unquote(str):
102+
"""Remove quotes from a string."""
103+
diff --git a/Lib/test/test_email/test_email_notstrict.py b/Lib/test/test_email/test_email_notstrict.py
104+
new file mode 100644
105+
index 0000000000..fe8617cfcb
106+
--- /dev/null
107+
+++ b/Lib/test/test_email/test_email_notstrict.py
108+
@@ -0,0 +1,38 @@
109+
+"""
110+
+This is the test_getaddresses_nasty function with the triggering
111+
+test case that was added for this fix. We test that
112+
+setting PYTHON_EMAIL_STRICT_PARSING_DEFAULT to false gives
113+
+the old behavior and to true gives new behavior
114+
+"""
115+
+
116+
+import unittest
117+
+
118+
+from unittest.mock import patch
119+
+
120+
+from email import utils
121+
+
122+
+expected_strict = [('', '')]
123+
+expected_nonstrict = [('', ''), ('', ''), ('', '*--')]
124+
+
125+
+@patch('os.environ', {"PYTHON_EMAIL_STRICT_PARSING_DEFAULT": "false"})
126+
+@patch('email.utils._parseaddr_strict_default', None)
127+
+class TestNonstrictParsing(unittest.TestCase):
128+
+ def test_getaddresses_nasty(self):
129+
+ self.assertEqual(utils.getaddresses(
130+
+ ['[]*-- =~$']), expected_nonstrict)
131+
+
132+
+@patch('os.environ', {"PYTHON_EMAIL_STRICT_PARSING_DEFAULT": "true"})
133+
+@patch('email.utils._parseaddr_strict_default', None)
134+
+class TestStrictParsing(unittest.TestCase):
135+
+ def test_getaddresses_nasty(self):
136+
+ self.assertEqual(utils.getaddresses(
137+
+ ['[]*-- =~$']), expected_strict)
138+
+
139+
+"""This test would fail if env had PYTHON_EMAIL_STRICT_PARSING_DEFAULT=false"""
140+
+class TestStrictNoEnvParsing(unittest.TestCase):
141+
+ def test_getaddresses_nasty(self):
142+
+ self.assertEqual(utils.getaddresses(
143+
+ ['[]*-- =~$']), expected_strict)
144+
+
145+
+if __name__ == '__main__':
146+
+ unittest.main()
147+
--
148+
2.44.0
149+
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
"""
2+
This is the test_getaddresses_nasty function with the triggering
3+
test case that was added for this fix. We test that
4+
setting PYTHON_EMAIL_STRICT_PARSING_DEFAULT to false gives
5+
the old behavior and to true gives new behavior
6+
"""
7+
8+
import unittest
9+
10+
from unittest.mock import patch
11+
12+
from email import utils
13+
14+
expected_strict = [('', '')]
15+
expected_nonstrict = [('', ''), ('', ''), ('', '*--')]
16+
17+
@patch('os.environ', {"PYTHON_EMAIL_STRICT_PARSING_DEFAULT": "false"})
18+
@patch('email.utils._parseaddr_strict_default', None)
19+
class TestNonstrictParsing(unittest.TestCase):
20+
def test_getaddresses_nasty(self):
21+
self.assertEqual(utils.getaddresses(
22+
['[]*-- =~$']), expected_nonstrict)
23+
24+
@patch('os.environ', {"PYTHON_EMAIL_STRICT_PARSING_DEFAULT": "true"})
25+
@patch('email.utils._parseaddr_strict_default', None)
26+
class TestStrictParsing(unittest.TestCase):
27+
def test_getaddresses_nasty(self):
28+
self.assertEqual(utils.getaddresses(
29+
['[]*-- =~$']), expected_strict)
30+
31+
"""This test would fail if env had PYTHON_EMAIL_STRICT_PARSING_DEFAULT=false"""
32+
class TestStrictNoEnvParsing(unittest.TestCase):
33+
def test_getaddresses_nasty(self):
34+
self.assertEqual(utils.getaddresses(
35+
['[]*-- =~$']), expected_strict)
36+
37+
if __name__ == '__main__':
38+
unittest.main()

0 commit comments

Comments
 (0)