Skip to content

Commit 54b7e86

Browse files
[AUTO-CHERRYPICK] python3: CVE-2024-7592 (mariner 2) - branch main (#10223)
Co-authored-by: bfjelds <bfjelds@microsoft.com>
1 parent f056ffd commit 54b7e86

6 files changed

Lines changed: 258 additions & 27 deletions

File tree

SPECS/python3/CVE-2024-7592.patch

Lines changed: 226 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,226 @@
1+
From 04ac47b343b10f2182c4b3730d4be241b2397a4d Mon Sep 17 00:00:00 2001
2+
From: Serhiy Storchaka <storchaka@gmail.com>
3+
Date: Fri, 16 Aug 2024 19:13:37 +0300
4+
Subject: [PATCH 1/4] gh-123067: Fix quadratic complexity in parsing cookies
5+
with backslashes
6+
7+
This fixes CVE-2024-7592.
8+
---
9+
Lib/http/cookies.py | 34 ++++-------------
10+
Lib/test/test_http_cookies.py | 38 +++++++++++++++++++
11+
...-08-16-19-13-21.gh-issue-123067.Nx9O4R.rst | 1 +
12+
3 files changed, 47 insertions(+), 26 deletions(-)
13+
create mode 100644 Misc/NEWS.d/next/Library/2024-08-16-19-13-21.gh-issue-123067.Nx9O4R.rst
14+
15+
diff --git a/Lib/http/cookies.py b/Lib/http/cookies.py
16+
index 351faf428a20cd..11a67e8a2e008b 100644
17+
--- a/Lib/http/cookies.py
18+
+++ b/Lib/http/cookies.py
19+
@@ -184,8 +184,12 @@ def _quote(str):
20+
return '"' + str.translate(_Translator) + '"'
21+
22+
23+
-_OctalPatt = re.compile(r"\\[0-3][0-7][0-7]")
24+
-_QuotePatt = re.compile(r"[\\].")
25+
+_unquote_re = re.compile(r'\\(?:([0-3][0-7][0-7])|(["\\]))')
26+
+def _unquote_replace(m):
27+
+ if m[1]:
28+
+ return chr(int(m[1], 8))
29+
+ else:
30+
+ return m[2]
31+
32+
def _unquote(str):
33+
# If there aren't any doublequotes,
34+
@@ -205,30 +209,8 @@ def _unquote(str):
35+
# \012 --> \n
36+
# \" --> "
37+
#
38+
- i = 0
39+
- n = len(str)
40+
- res = []
41+
- while 0 <= i < n:
42+
- o_match = _OctalPatt.search(str, i)
43+
- q_match = _QuotePatt.search(str, i)
44+
- if not o_match and not q_match: # Neither matched
45+
- res.append(str[i:])
46+
- break
47+
- # else:
48+
- j = k = -1
49+
- if o_match:
50+
- j = o_match.start(0)
51+
- if q_match:
52+
- k = q_match.start(0)
53+
- if q_match and (not o_match or k < j): # QuotePatt matched
54+
- res.append(str[i:k])
55+
- res.append(str[k+1])
56+
- i = k + 2
57+
- else: # OctalPatt matched
58+
- res.append(str[i:j])
59+
- res.append(chr(int(str[j+1:j+4], 8)))
60+
- i = j + 4
61+
- return _nulljoin(res)
62+
+
63+
+ return _unquote_re.sub(_unquote_replace, str)
64+
65+
# The _getdate() routine is used to set the expiration time in the cookie's HTTP
66+
# header. By default, _getdate() returns the current time in the appropriate
67+
diff --git a/Lib/test/test_http_cookies.py b/Lib/test/test_http_cookies.py
68+
index 925c8697f60de6..13b526d49b0856 100644
69+
--- a/Lib/test/test_http_cookies.py
70+
+++ b/Lib/test/test_http_cookies.py
71+
@@ -5,6 +5,7 @@
72+
import unittest
73+
from http import cookies
74+
import pickle
75+
+from test import support
76+
77+
78+
class CookieTests(unittest.TestCase):
79+
@@ -58,6 +59,43 @@ def test_basic(self):
80+
for k, v in sorted(case['dict'].items()):
81+
self.assertEqual(C[k].value, v)
82+
83+
+ def test_unquote(self):
84+
+ cases = [
85+
+ (r'a="b=\""', 'b="'),
86+
+ (r'a="b=\\"', 'b=\\'),
87+
+ (r'a="b=\="', 'b=\\='),
88+
+ (r'a="b=\n"', 'b=\\n'),
89+
+ (r'a="b=\042"', 'b="'),
90+
+ (r'a="b=\134"', 'b=\\'),
91+
+ (r'a="b=\377"', 'b=\xff'),
92+
+ (r'a="b=\400"', 'b=\\400'),
93+
+ (r'a="b=\42"', 'b=\\42'),
94+
+ (r'a="b=\\042"', 'b=\\042'),
95+
+ (r'a="b=\\134"', 'b=\\134'),
96+
+ (r'a="b=\\\""', 'b=\\"'),
97+
+ (r'a="b=\\\042"', 'b=\\"'),
98+
+ (r'a="b=\134\""', 'b=\\"'),
99+
+ (r'a="b=\134\042"', 'b=\\"'),
100+
+ ]
101+
+ for encoded, decoded in cases:
102+
+ with self.subTest(encoded):
103+
+ C = cookies.SimpleCookie()
104+
+ C.load(encoded)
105+
+ self.assertEqual(C['a'].value, decoded)
106+
+
107+
+ @support.requires_resource('cpu')
108+
+ def test_unquote_large(self):
109+
+ n = 10**6
110+
+ for encoded in r'\\', r'\134':
111+
+ with self.subTest(encoded):
112+
+ data = 'a="b=' + encoded*n + ';"'
113+
+ C = cookies.SimpleCookie()
114+
+ C.load(data)
115+
+ value = C['a'].value
116+
+ self.assertEqual(value[:3], 'b=\\')
117+
+ self.assertEqual(value[-2:], '\\;')
118+
+ self.assertEqual(len(value), n + 3)
119+
+
120+
def test_load(self):
121+
C = cookies.SimpleCookie()
122+
C.load('Customer="WILE_E_COYOTE"; Version=1; Path=/acme')
123+
diff --git a/Misc/NEWS.d/next/Library/2024-08-16-19-13-21.gh-issue-123067.Nx9O4R.rst b/Misc/NEWS.d/next/Library/2024-08-16-19-13-21.gh-issue-123067.Nx9O4R.rst
124+
new file mode 100644
125+
index 00000000000000..158b938a65a2d4
126+
--- /dev/null
127+
+++ b/Misc/NEWS.d/next/Library/2024-08-16-19-13-21.gh-issue-123067.Nx9O4R.rst
128+
@@ -0,0 +1 @@
129+
+Fix quadratic complexity in parsing cookies with backslashes.
130+
131+
From ab87c992c2d4cd28560178048915bc9636d6566e Mon Sep 17 00:00:00 2001
132+
From: Serhiy Storchaka <storchaka@gmail.com>
133+
Date: Fri, 16 Aug 2024 19:38:20 +0300
134+
Subject: [PATCH 2/4] Restore the current behavior for backslash-escaping.
135+
136+
---
137+
Lib/http/cookies.py | 2 +-
138+
Lib/test/test_http_cookies.py | 8 ++++----
139+
2 files changed, 5 insertions(+), 5 deletions(-)
140+
141+
diff --git a/Lib/http/cookies.py b/Lib/http/cookies.py
142+
index 11a67e8a2e008b..464abeb0fb253a 100644
143+
--- a/Lib/http/cookies.py
144+
+++ b/Lib/http/cookies.py
145+
@@ -184,7 +184,7 @@ def _quote(str):
146+
return '"' + str.translate(_Translator) + '"'
147+
148+
149+
-_unquote_re = re.compile(r'\\(?:([0-3][0-7][0-7])|(["\\]))')
150+
+_unquote_re = re.compile(r'\\(?:([0-3][0-7][0-7])|(.))')
151+
def _unquote_replace(m):
152+
if m[1]:
153+
return chr(int(m[1], 8))
154+
diff --git a/Lib/test/test_http_cookies.py b/Lib/test/test_http_cookies.py
155+
index 13b526d49b0856..8879902a6e2f41 100644
156+
--- a/Lib/test/test_http_cookies.py
157+
+++ b/Lib/test/test_http_cookies.py
158+
@@ -63,13 +63,13 @@ def test_unquote(self):
159+
cases = [
160+
(r'a="b=\""', 'b="'),
161+
(r'a="b=\\"', 'b=\\'),
162+
- (r'a="b=\="', 'b=\\='),
163+
- (r'a="b=\n"', 'b=\\n'),
164+
+ (r'a="b=\="', 'b=='),
165+
+ (r'a="b=\n"', 'b=n'),
166+
(r'a="b=\042"', 'b="'),
167+
(r'a="b=\134"', 'b=\\'),
168+
(r'a="b=\377"', 'b=\xff'),
169+
- (r'a="b=\400"', 'b=\\400'),
170+
- (r'a="b=\42"', 'b=\\42'),
171+
+ (r'a="b=\400"', 'b=400'),
172+
+ (r'a="b=\42"', 'b=42'),
173+
(r'a="b=\\042"', 'b=\\042'),
174+
(r'a="b=\\134"', 'b=\\134'),
175+
(r'a="b=\\\""', 'b=\\"'),
176+
177+
From 1fe24921da4c6c547da82e11c9703f3588dc5fab Mon Sep 17 00:00:00 2001
178+
From: Serhiy Storchaka <storchaka@gmail.com>
179+
Date: Sat, 17 Aug 2024 12:40:11 +0300
180+
Subject: [PATCH 3/4] Cache the sub() method, not the compiled pattern object.
181+
182+
---
183+
Lib/http/cookies.py | 6 +++---
184+
1 file changed, 3 insertions(+), 3 deletions(-)
185+
186+
diff --git a/Lib/http/cookies.py b/Lib/http/cookies.py
187+
index 464abeb0fb253a..6b9ed24ad8ec78 100644
188+
--- a/Lib/http/cookies.py
189+
+++ b/Lib/http/cookies.py
190+
@@ -184,7 +184,8 @@ def _quote(str):
191+
return '"' + str.translate(_Translator) + '"'
192+
193+
194+
-_unquote_re = re.compile(r'\\(?:([0-3][0-7][0-7])|(.))')
195+
+_unquote_sub = re.compile(r'\\(?:([0-3][0-7][0-7])|(.))').sub
196+
+
197+
def _unquote_replace(m):
198+
if m[1]:
199+
return chr(int(m[1], 8))
200+
@@ -209,8 +210,7 @@ def _unquote(str):
201+
# \012 --> \n
202+
# \" --> "
203+
#
204+
-
205+
- return _unquote_re.sub(_unquote_replace, str)
206+
+ return _unquote_sub(_unquote_replace, str)
207+
208+
# The _getdate() routine is used to set the expiration time in the cookie's HTTP
209+
# header. By default, _getdate() returns the current time in the appropriate
210+
211+
From 8256ed2228137c87d4b20747db84a9cdf0fa1d34 Mon Sep 17 00:00:00 2001
212+
From: Serhiy Storchaka <storchaka@gmail.com>
213+
Date: Sat, 17 Aug 2024 13:08:20 +0300
214+
Subject: [PATCH 4/4] Add a reference to the module in NEWS.
215+
216+
---
217+
.../next/Library/2024-08-16-19-13-21.gh-issue-123067.Nx9O4R.rst | 2 +-
218+
1 file changed, 1 insertion(+), 1 deletion(-)
219+
220+
diff --git a/Misc/NEWS.d/next/Library/2024-08-16-19-13-21.gh-issue-123067.Nx9O4R.rst b/Misc/NEWS.d/next/Library/2024-08-16-19-13-21.gh-issue-123067.Nx9O4R.rst
221+
index 158b938a65a2d4..6a234561fe31a3 100644
222+
--- a/Misc/NEWS.d/next/Library/2024-08-16-19-13-21.gh-issue-123067.Nx9O4R.rst
223+
+++ b/Misc/NEWS.d/next/Library/2024-08-16-19-13-21.gh-issue-123067.Nx9O4R.rst
224+
@@ -1 +1 @@
225+
-Fix quadratic complexity in parsing cookies with backslashes.
226+
+Fix quadratic complexity in parsing ``"``-quoted cookie values with backslashes by :mod:`http.cookies`.

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: 3%{?dist}
15+
Release: 4%{?dist}
1616
License: PSF
1717
Vendor: Microsoft Corporation
1818
Distribution: Mariner
@@ -23,6 +23,7 @@ Patch0: cgi3.patch
2323
# Backport https://github.com/python/cpython/commit/069fefdaf42490f1e00243614fb5f3d5d2614b81 from 3.10 to 3.9
2424
Patch1: 0001-gh-95231-Disable-md5-crypt-modules-if-FIPS-is-enable.patch
2525
Patch2: CVE-2024-0397.patch
26+
Patch3: CVE-2024-7592.patch
2627
# Patch for setuptools, resolved in 65.5.1
2728
Patch1000: CVE-2022-40897.patch
2829
Patch1001: CVE-2024-6345.patch
@@ -163,6 +164,7 @@ The test package contains all regression tests for Python as well as the modules
163164
%patch0 -p1
164165
%patch1 -p1
165166
%patch2 -p1
167+
%patch3 -p1
166168

167169
%build
168170
# Remove GCC specs and build environment linker scripts
@@ -318,6 +320,9 @@ rm -rf %{buildroot}%{_bindir}/__pycache__
318320
%{_libdir}/python%{majmin}/test/*
319321

320322
%changelog
323+
* Wed Aug 21 2024 Brian Fjeldstad <bfjelds@microsoft.com> - 3.9.19-4
324+
- Patch for CVE-2024-7592
325+
321326
* Tue Jul 23 2024 Rohit Rawat <rohitrawat@microsoft.com> - 3.9.19-3
322327
- Patch for CVE-2024-0397
323328

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-18.cm2.noarch.rpm
237237
ca-certificates-2.0.0-18.cm2.noarch.rpm
238238
dwz-0.14-2.cm2.aarch64.rpm
239239
unzip-6.0-20.cm2.aarch64.rpm
240-
python3-3.9.19-3.cm2.aarch64.rpm
241-
python3-devel-3.9.19-3.cm2.aarch64.rpm
242-
python3-libs-3.9.19-3.cm2.aarch64.rpm
243-
python3-setuptools-3.9.19-3.cm2.noarch.rpm
240+
python3-3.9.19-4.cm2.aarch64.rpm
241+
python3-devel-3.9.19-4.cm2.aarch64.rpm
242+
python3-libs-3.9.19-4.cm2.aarch64.rpm
243+
python3-setuptools-3.9.19-4.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-18.cm2.noarch.rpm
237237
ca-certificates-2.0.0-18.cm2.noarch.rpm
238238
dwz-0.14-2.cm2.x86_64.rpm
239239
unzip-6.0-20.cm2.x86_64.rpm
240-
python3-3.9.19-3.cm2.x86_64.rpm
241-
python3-devel-3.9.19-3.cm2.x86_64.rpm
242-
python3-libs-3.9.19-3.cm2.x86_64.rpm
243-
python3-setuptools-3.9.19-3.cm2.noarch.rpm
240+
python3-3.9.19-4.cm2.x86_64.rpm
241+
python3-devel-3.9.19-4.cm2.x86_64.rpm
242+
python3-libs-3.9.19-4.cm2.x86_64.rpm
243+
python3-setuptools-3.9.19-4.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-3.cm2.aarch64.rpm
513+
python3-3.9.19-4.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-3.cm2.aarch64.rpm
516+
python3-curses-3.9.19-4.cm2.aarch64.rpm
517517
python3-Cython-0.29.33-2.cm2.aarch64.rpm
518-
python3-debuginfo-3.9.19-3.cm2.aarch64.rpm
519-
python3-devel-3.9.19-3.cm2.aarch64.rpm
518+
python3-debuginfo-3.9.19-4.cm2.aarch64.rpm
519+
python3-devel-3.9.19-4.cm2.aarch64.rpm
520520
python3-gpg-1.16.0-2.cm2.aarch64.rpm
521521
python3-jinja2-3.0.3-4.cm2.noarch.rpm
522522
python3-libcap-ng-0.8.2-2.cm2.aarch64.rpm
523-
python3-libs-3.9.19-3.cm2.aarch64.rpm
523+
python3-libs-3.9.19-4.cm2.aarch64.rpm
524524
python3-libxml2-2.10.4-3.cm2.aarch64.rpm
525525
python3-lxml-4.9.1-1.cm2.aarch64.rpm
526526
python3-magic-5.40-2.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-3.cm2.noarch.rpm
529+
python3-pip-3.9.19-4.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-3.cm2.noarch.rpm
533-
python3-test-3.9.19-3.cm2.aarch64.rpm
534-
python3-tools-3.9.19-3.cm2.aarch64.rpm
532+
python3-setuptools-3.9.19-4.cm2.noarch.rpm
533+
python3-test-3.9.19-4.cm2.aarch64.rpm
534+
python3-tools-3.9.19-4.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-3.cm2.x86_64.rpm
519+
python3-3.9.19-4.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-3.cm2.x86_64.rpm
522+
python3-curses-3.9.19-4.cm2.x86_64.rpm
523523
python3-Cython-0.29.33-2.cm2.x86_64.rpm
524-
python3-debuginfo-3.9.19-3.cm2.x86_64.rpm
525-
python3-devel-3.9.19-3.cm2.x86_64.rpm
524+
python3-debuginfo-3.9.19-4.cm2.x86_64.rpm
525+
python3-devel-3.9.19-4.cm2.x86_64.rpm
526526
python3-gpg-1.16.0-2.cm2.x86_64.rpm
527527
python3-jinja2-3.0.3-4.cm2.noarch.rpm
528528
python3-libcap-ng-0.8.2-2.cm2.x86_64.rpm
529-
python3-libs-3.9.19-3.cm2.x86_64.rpm
529+
python3-libs-3.9.19-4.cm2.x86_64.rpm
530530
python3-libxml2-2.10.4-3.cm2.x86_64.rpm
531531
python3-lxml-4.9.1-1.cm2.x86_64.rpm
532532
python3-magic-5.40-2.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-3.cm2.noarch.rpm
535+
python3-pip-3.9.19-4.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-3.cm2.noarch.rpm
539-
python3-test-3.9.19-3.cm2.x86_64.rpm
540-
python3-tools-3.9.19-3.cm2.x86_64.rpm
538+
python3-setuptools-3.9.19-4.cm2.noarch.rpm
539+
python3-test-3.9.19-4.cm2.x86_64.rpm
540+
python3-tools-3.9.19-4.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)