Skip to content

Commit 93d3f45

Browse files
authored
python3: fix CVE-2021-28861 (#3654)
1 parent c9e2f0f commit 93d3f45

File tree

6 files changed

+158
-27
lines changed

6 files changed

+158
-27
lines changed

SPECS/python3/CVE-2021-28861.patch

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
From 31dbe663f6c9ae68595dde9420381e065016ad6f Mon Sep 17 00:00:00 2001
2+
From: "Gregory P. Smith" <[email protected]>
3+
Date: Tue, 21 Jun 2022 13:16:57 -0700
4+
Subject: [PATCH] gh-87389: Fix an open redirection vulnerability in
5+
http.server. (GH-93879)
6+
7+
Fix an open redirection vulnerability in the `http.server` module when
8+
an URI path starts with `//` that could produce a 301 Location header
9+
with a misleading target. Vulnerability discovered, and logic fix
10+
proposed, by Hamza Avvan (@hamzaavvan).
11+
12+
Test and comments authored by Gregory P. Smith [Google].
13+
(cherry picked from commit 4abab6b603dd38bec1168e9a37c40a48ec89508e)
14+
15+
Co-authored-by: Gregory P. Smith <[email protected]>
16+
---
17+
Lib/http/server.py | 7 +++
18+
Lib/test/test_httpservers.py | 53 ++++++++++++++++++-
19+
...2-06-15-20-09-23.gh-issue-87389.QVaC3f.rst | 3 ++
20+
3 files changed, 61 insertions(+), 2 deletions(-)
21+
create mode 100644 Misc/NEWS.d/next/Security/2022-06-15-20-09-23.gh-issue-87389.QVaC3f.rst
22+
23+
diff --git a/Lib/http/server.py b/Lib/http/server.py
24+
index 2d2300c2aeab..6bf9084341a6 100644
25+
--- a/Lib/http/server.py
26+
+++ b/Lib/http/server.py
27+
@@ -330,6 +330,13 @@ def parse_request(self):
28+
return False
29+
self.command, self.path = command, path
30+
31+
+ # gh-87389: The purpose of replacing '//' with '/' is to protect
32+
+ # against open redirect attacks possibly triggered if the path starts
33+
+ # with '//' because http clients treat //path as an absolute URI
34+
+ # without scheme (similar to http://path) rather than a path.
35+
+ if self.path.startswith('//'):
36+
+ self.path = '/' + self.path.lstrip('/') # Reduce to a single /
37+
+
38+
# Examine the headers and look for a Connection directive.
39+
try:
40+
self.headers = http.client.parse_headers(self.rfile,
41+
diff --git a/Lib/test/test_httpservers.py b/Lib/test/test_httpservers.py
42+
index c1494d29ca87..4acf7a6fea44 100644
43+
--- a/Lib/test/test_httpservers.py
44+
+++ b/Lib/test/test_httpservers.py
45+
@@ -331,7 +331,7 @@ class request_handler(NoLogRequestHandler, SimpleHTTPRequestHandler):
46+
pass
47+
48+
def setUp(self):
49+
- BaseTestCase.setUp(self)
50+
+ super().setUp()
51+
self.cwd = os.getcwd()
52+
basetempdir = tempfile.gettempdir()
53+
os.chdir(basetempdir)
54+
@@ -359,7 +359,7 @@ def tearDown(self):
55+
except:
56+
pass
57+
finally:
58+
- BaseTestCase.tearDown(self)
59+
+ super().tearDown()
60+
61+
def check_status_and_reason(self, response, status, data=None):
62+
def close_conn():
63+
@@ -415,6 +415,55 @@ def test_undecodable_filename(self):
64+
self.check_status_and_reason(response, HTTPStatus.OK,
65+
data=support.TESTFN_UNDECODABLE)
66+
67+
+ def test_get_dir_redirect_location_domain_injection_bug(self):
68+
+ """Ensure //evil.co/..%2f../../X does not put //evil.co/ in Location.
69+
+
70+
+ //netloc/ in a Location header is a redirect to a new host.
71+
+ https://github.com/python/cpython/issues/87389
72+
+
73+
+ This checks that a path resolving to a directory on our server cannot
74+
+ resolve into a redirect to another server.
75+
+ """
76+
+ os.mkdir(os.path.join(self.tempdir, 'existing_directory'))
77+
+ url = f'/python.org/..%2f..%2f..%2f..%2f..%2f../%0a%0d/../{self.tempdir_name}/existing_directory'
78+
+ expected_location = f'{url}/' # /python.org.../ single slash single prefix, trailing slash
79+
+ # Canonicalizes to /tmp/tempdir_name/existing_directory which does
80+
+ # exist and is a dir, triggering the 301 redirect logic.
81+
+ response = self.request(url)
82+
+ self.check_status_and_reason(response, HTTPStatus.MOVED_PERMANENTLY)
83+
+ location = response.getheader('Location')
84+
+ self.assertEqual(location, expected_location, msg='non-attack failed!')
85+
+
86+
+ # //python.org... multi-slash prefix, no trailing slash
87+
+ attack_url = f'/{url}'
88+
+ response = self.request(attack_url)
89+
+ self.check_status_and_reason(response, HTTPStatus.MOVED_PERMANENTLY)
90+
+ location = response.getheader('Location')
91+
+ self.assertFalse(location.startswith('//'), msg=location)
92+
+ self.assertEqual(location, expected_location,
93+
+ msg='Expected Location header to start with a single / and '
94+
+ 'end with a / as this is a directory redirect.')
95+
+
96+
+ # ///python.org... triple-slash prefix, no trailing slash
97+
+ attack3_url = f'//{url}'
98+
+ response = self.request(attack3_url)
99+
+ self.check_status_and_reason(response, HTTPStatus.MOVED_PERMANENTLY)
100+
+ self.assertEqual(response.getheader('Location'), expected_location)
101+
+
102+
+ # If the second word in the http request (Request-URI for the http
103+
+ # method) is a full URI, we don't worry about it, as that'll be parsed
104+
+ # and reassembled as a full URI within BaseHTTPRequestHandler.send_head
105+
+ # so no errant scheme-less //netloc//evil.co/ domain mixup can happen.
106+
+ attack_scheme_netloc_2slash_url = f'https://pypi.org/{url}'
107+
+ expected_scheme_netloc_location = f'{attack_scheme_netloc_2slash_url}/'
108+
+ response = self.request(attack_scheme_netloc_2slash_url)
109+
+ self.check_status_and_reason(response, HTTPStatus.MOVED_PERMANENTLY)
110+
+ location = response.getheader('Location')
111+
+ # We're just ensuring that the scheme and domain make it through, if
112+
+ # there are or aren't multiple slashes at the start of the path that
113+
+ # follows that isn't important in this Location: header.
114+
+ self.assertTrue(location.startswith('https://pypi.org/'), msg=location)
115+
+
116+
def test_get(self):
117+
#constructs the path relative to the root directory of the HTTPServer
118+
response = self.request(self.base_url + '/test')
119+
diff --git a/Misc/NEWS.d/next/Security/2022-06-15-20-09-23.gh-issue-87389.QVaC3f.rst b/Misc/NEWS.d/next/Security/2022-06-15-20-09-23.gh-issue-87389.QVaC3f.rst
120+
new file mode 100644
121+
index 000000000000..029d437190de
122+
--- /dev/null
123+
+++ b/Misc/NEWS.d/next/Security/2022-06-15-20-09-23.gh-issue-87389.QVaC3f.rst
124+
@@ -0,0 +1,3 @@
125+
+:mod:`http.server`: Fix an open redirection vulnerability in the HTTP server
126+
+when an URI path starts with ``//``. Vulnerability discovered, and initial
127+
+fix proposed, by Hamza Avvan.

SPECS/python3/python3.spec

Lines changed: 5 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.13
15-
Release: 4%{?dist}
15+
Release: 5%{?dist}
1616
License: PSF
1717
Vendor: Microsoft Corporation
1818
Distribution: Mariner
@@ -21,6 +21,7 @@ URL: https://www.python.org/
2121
Source0: https://www.python.org/ftp/python/%{version}/Python-%{version}.tar.xz
2222
Patch0: cgi3.patch
2323
Patch1: CVE-2015-20107.patch
24+
Patch2: CVE-2021-28861.patch
2425

2526
BuildRequires: bzip2-devel
2627
BuildRequires: expat-devel >= 2.1.0
@@ -300,6 +301,9 @@ rm -rf %{buildroot}%{_bindir}/__pycache__
300301
%{_libdir}/python%{majmin}/test/*
301302

302303
%changelog
304+
* Wed Aug 31 2022 Henry Beberman <[email protected]> - 3.9.13-5
305+
- Add CVE-2021-28861 patch from upstream
306+
303307
* Tue Aug 30 2022 Henry Beberman <[email protected]> - 3.9.13-4
304308
- Add CVE-2015-20107 patch from upstream
305309

toolkit/resources/manifests/package/pkggen_core_aarch64.txt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -233,10 +233,10 @@ ca-certificates-base-2.0.0-7.cm2.noarch.rpm
233233
ca-certificates-2.0.0-7.cm2.noarch.rpm
234234
dwz-0.14-1.cm2.aarch64.rpm
235235
unzip-6.0-19.cm2.aarch64.rpm
236-
python3-3.9.13-4.cm2.aarch64.rpm
237-
python3-devel-3.9.13-4.cm2.aarch64.rpm
238-
python3-libs-3.9.13-4.cm2.aarch64.rpm
239-
python3-setuptools-3.9.13-4.cm2.noarch.rpm
236+
python3-3.9.13-5.cm2.aarch64.rpm
237+
python3-devel-3.9.13-5.cm2.aarch64.rpm
238+
python3-libs-3.9.13-5.cm2.aarch64.rpm
239+
python3-setuptools-3.9.13-5.cm2.noarch.rpm
240240
which-2.21-8.cm2.aarch64.rpm
241241
libselinux-3.2-1.cm2.aarch64.rpm
242242
slang-2.3.2-4.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
@@ -233,10 +233,10 @@ ca-certificates-base-2.0.0-7.cm2.noarch.rpm
233233
ca-certificates-2.0.0-7.cm2.noarch.rpm
234234
dwz-0.14-1.cm2.x86_64.rpm
235235
unzip-6.0-19.cm2.x86_64.rpm
236-
python3-3.9.13-4.cm2.x86_64.rpm
237-
python3-devel-3.9.13-4.cm2.x86_64.rpm
238-
python3-libs-3.9.13-4.cm2.x86_64.rpm
239-
python3-setuptools-3.9.13-4.cm2.noarch.rpm
236+
python3-3.9.13-5.cm2.x86_64.rpm
237+
python3-devel-3.9.13-5.cm2.x86_64.rpm
238+
python3-libs-3.9.13-5.cm2.x86_64.rpm
239+
python3-setuptools-3.9.13-5.cm2.noarch.rpm
240240
which-2.21-8.cm2.x86_64.rpm
241241
libselinux-3.2-1.cm2.x86_64.rpm
242242
slang-2.3.2-4.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
@@ -499,28 +499,28 @@ procps-ng-devel-3.3.17-1.cm2.aarch64.rpm
499499
procps-ng-lang-3.3.17-1.cm2.aarch64.rpm
500500
pyproject-rpm-macros-1.0.0~rc1-3.cm2.noarch.rpm
501501
python-markupsafe-debuginfo-2.1.0-1.cm2.aarch64.rpm
502-
python3-3.9.13-4.cm2.aarch64.rpm
502+
python3-3.9.13-5.cm2.aarch64.rpm
503503
python3-audit-3.0.6-7.cm2.aarch64.rpm
504504
python3-cracklib-2.9.7-5.cm2.aarch64.rpm
505-
python3-curses-3.9.13-4.cm2.aarch64.rpm
505+
python3-curses-3.9.13-5.cm2.aarch64.rpm
506506
python3-Cython-0.29.26-1.cm2.aarch64.rpm
507-
python3-debuginfo-3.9.13-4.cm2.aarch64.rpm
508-
python3-devel-3.9.13-4.cm2.aarch64.rpm
507+
python3-debuginfo-3.9.13-5.cm2.aarch64.rpm
508+
python3-devel-3.9.13-5.cm2.aarch64.rpm
509509
python3-gpg-1.16.0-1.cm2.aarch64.rpm
510510
python3-jinja2-3.0.3-2.cm2.noarch.rpm
511511
python3-libcap-ng-0.8.2-2.cm2.aarch64.rpm
512-
python3-libs-3.9.13-4.cm2.aarch64.rpm
512+
python3-libs-3.9.13-5.cm2.aarch64.rpm
513513
python3-libxml2-2.10.0-1.cm2.aarch64.rpm
514514
python3-lxml-4.9.1-1.cm2.aarch64.rpm
515515
python3-magic-5.40-2.cm2.noarch.rpm
516516
python3-markupsafe-2.1.0-1.cm2.aarch64.rpm
517517
python3-newt-0.52.21-4.cm2.aarch64.rpm
518-
python3-pip-3.9.13-4.cm2.noarch.rpm
518+
python3-pip-3.9.13-5.cm2.noarch.rpm
519519
python3-pygments-2.4.2-7.cm2.noarch.rpm
520520
python3-rpm-4.17.0-9.cm2.aarch64.rpm
521-
python3-setuptools-3.9.13-4.cm2.noarch.rpm
522-
python3-test-3.9.13-4.cm2.aarch64.rpm
523-
python3-tools-3.9.13-4.cm2.aarch64.rpm
521+
python3-setuptools-3.9.13-5.cm2.noarch.rpm
522+
python3-test-3.9.13-5.cm2.aarch64.rpm
523+
python3-tools-3.9.13-5.cm2.aarch64.rpm
524524
readline-8.1-1.cm2.aarch64.rpm
525525
readline-debuginfo-8.1-1.cm2.aarch64.rpm
526526
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
@@ -499,28 +499,28 @@ procps-ng-devel-3.3.17-1.cm2.x86_64.rpm
499499
procps-ng-lang-3.3.17-1.cm2.x86_64.rpm
500500
pyproject-rpm-macros-1.0.0~rc1-3.cm2.noarch.rpm
501501
python-markupsafe-debuginfo-2.1.0-1.cm2.x86_64.rpm
502-
python3-3.9.13-4.cm2.x86_64.rpm
502+
python3-3.9.13-5.cm2.x86_64.rpm
503503
python3-audit-3.0.6-7.cm2.x86_64.rpm
504504
python3-cracklib-2.9.7-5.cm2.x86_64.rpm
505-
python3-curses-3.9.13-4.cm2.x86_64.rpm
505+
python3-curses-3.9.13-5.cm2.x86_64.rpm
506506
python3-Cython-0.29.26-1.cm2.x86_64.rpm
507-
python3-debuginfo-3.9.13-4.cm2.x86_64.rpm
508-
python3-devel-3.9.13-4.cm2.x86_64.rpm
507+
python3-debuginfo-3.9.13-5.cm2.x86_64.rpm
508+
python3-devel-3.9.13-5.cm2.x86_64.rpm
509509
python3-gpg-1.16.0-1.cm2.x86_64.rpm
510510
python3-jinja2-3.0.3-2.cm2.noarch.rpm
511511
python3-libcap-ng-0.8.2-2.cm2.x86_64.rpm
512-
python3-libs-3.9.13-4.cm2.x86_64.rpm
512+
python3-libs-3.9.13-5.cm2.x86_64.rpm
513513
python3-libxml2-2.10.0-1.cm2.x86_64.rpm
514514
python3-lxml-4.9.1-1.cm2.x86_64.rpm
515515
python3-magic-5.40-2.cm2.noarch.rpm
516516
python3-markupsafe-2.1.0-1.cm2.x86_64.rpm
517517
python3-newt-0.52.21-4.cm2.x86_64.rpm
518-
python3-pip-3.9.13-4.cm2.noarch.rpm
518+
python3-pip-3.9.13-5.cm2.noarch.rpm
519519
python3-pygments-2.4.2-7.cm2.noarch.rpm
520520
python3-rpm-4.17.0-9.cm2.x86_64.rpm
521-
python3-setuptools-3.9.13-4.cm2.noarch.rpm
522-
python3-test-3.9.13-4.cm2.x86_64.rpm
523-
python3-tools-3.9.13-4.cm2.x86_64.rpm
521+
python3-setuptools-3.9.13-5.cm2.noarch.rpm
522+
python3-test-3.9.13-5.cm2.x86_64.rpm
523+
python3-tools-3.9.13-5.cm2.x86_64.rpm
524524
readline-8.1-1.cm2.x86_64.rpm
525525
readline-debuginfo-8.1-1.cm2.x86_64.rpm
526526
readline-devel-8.1-1.cm2.x86_64.rpm

0 commit comments

Comments
 (0)