From f429fecdd7bc8b6ab331843683921458258e1ef1 Mon Sep 17 00:00:00 2001 From: Lumir Balhar Date: Mon, 10 Oct 2022 18:00:52 +0200 Subject: [PATCH] Backport fix for CVE-2021-28861 --- 386-cve-2021-28861.patch | 98 ++++++++++++++++++++++++++++++++++++++++ pypy3.9.spec | 12 ++++- 2 files changed, 109 insertions(+), 1 deletion(-) create mode 100644 386-cve-2021-28861.patch diff --git a/386-cve-2021-28861.patch b/386-cve-2021-28861.patch new file mode 100644 index 0000000..dfa9969 --- /dev/null +++ b/386-cve-2021-28861.patch @@ -0,0 +1,98 @@ +From e42be9b593f1d5e83a947f73058b919395398424 Mon Sep 17 00:00:00 2001 +From: Julian Berman +Date: Fri, 23 Sep 2022 11:30:55 +0200 +Subject: [PATCH] Pull in the http.server vulnerability fix from + python/cpython#87389 + +Fixes an open redirection vulnerability for paths starting with `//`. + +Closes: #3812 + +--HG-- +branch : http_server_vuln_fix +--- + lib-python/3/http/server.py | 7 ++++ + lib-python/3/test/test_httpservers.py | 49 +++++++++++++++++++++++++++ + 2 files changed, 56 insertions(+) + +diff --git a/lib-python/3/http/server.py b/lib-python/3/http/server.py +index 38f7accad7..39de35458c 100644 +--- a/lib-python/3/http/server.py ++++ b/lib-python/3/http/server.py +@@ -332,6 +332,13 @@ class BaseHTTPRequestHandler(socketserver.StreamRequestHandler): + return False + self.command, self.path = command, path + ++ # gh-87389: The purpose of replacing '//' with '/' is to protect ++ # against open redirect attacks possibly triggered if the path starts ++ # with '//' because http clients treat //path as an absolute URI ++ # without scheme (similar to http://path) rather than a path. ++ if self.path.startswith('//'): ++ self.path = '/' + self.path.lstrip('/') # Reduce to a single / ++ + # Examine the headers and look for a Connection directive. + try: + self.headers = http.client.parse_headers(self.rfile, +diff --git a/lib-python/3/test/test_httpservers.py b/lib-python/3/test/test_httpservers.py +index c5b833723e..97dae7a7ce 100644 +--- a/lib-python/3/test/test_httpservers.py ++++ b/lib-python/3/test/test_httpservers.py +@@ -416,6 +416,55 @@ class SimpleHTTPServerTestCase(BaseTestCase): + self.check_status_and_reason(response, HTTPStatus.OK, + data=support.TESTFN_UNDECODABLE) + ++ def test_get_dir_redirect_location_domain_injection_bug(self): ++ """Ensure //evil.co/..%2f../../X does not put //evil.co/ in Location. ++ ++ //netloc/ in a Location header is a redirect to a new host. ++ https://github.com/python/cpython/issues/87389 ++ ++ This checks that a path resolving to a directory on our server cannot ++ resolve into a redirect to another server. ++ """ ++ os.mkdir(os.path.join(self.tempdir, 'existing_directory')) ++ url = f'/python.org/..%2f..%2f..%2f..%2f..%2f../%0a%0d/../{self.tempdir_name}/existing_directory' ++ expected_location = f'{url}/' # /python.org.../ single slash single prefix, trailing slash ++ # Canonicalizes to /tmp/tempdir_name/existing_directory which does ++ # exist and is a dir, triggering the 301 redirect logic. ++ response = self.request(url) ++ self.check_status_and_reason(response, HTTPStatus.MOVED_PERMANENTLY) ++ location = response.getheader('Location') ++ self.assertEqual(location, expected_location, msg='non-attack failed!') ++ ++ # //python.org... multi-slash prefix, no trailing slash ++ attack_url = f'/{url}' ++ response = self.request(attack_url) ++ self.check_status_and_reason(response, HTTPStatus.MOVED_PERMANENTLY) ++ location = response.getheader('Location') ++ self.assertFalse(location.startswith('//'), msg=location) ++ self.assertEqual(location, expected_location, ++ msg='Expected Location header to start with a single / and ' ++ 'end with a / as this is a directory redirect.') ++ ++ # ///python.org... triple-slash prefix, no trailing slash ++ attack3_url = f'//{url}' ++ response = self.request(attack3_url) ++ self.check_status_and_reason(response, HTTPStatus.MOVED_PERMANENTLY) ++ self.assertEqual(response.getheader('Location'), expected_location) ++ ++ # If the second word in the http request (Request-URI for the http ++ # method) is a full URI, we don't worry about it, as that'll be parsed ++ # and reassembled as a full URI within BaseHTTPRequestHandler.send_head ++ # so no errant scheme-less //netloc//evil.co/ domain mixup can happen. ++ attack_scheme_netloc_2slash_url = f'https://pypi.org/{url}' ++ expected_scheme_netloc_location = f'{attack_scheme_netloc_2slash_url}/' ++ response = self.request(attack_scheme_netloc_2slash_url) ++ self.check_status_and_reason(response, HTTPStatus.MOVED_PERMANENTLY) ++ location = response.getheader('Location') ++ # We're just ensuring that the scheme and domain make it through, if ++ # there are or aren't multiple slashes at the start of the path that ++ # follows that isn't important in this Location: header. ++ self.assertTrue(location.startswith('https://pypi.org/'), msg=location) ++ + def test_get(self): + #constructs the path relative to the root directory of the HTTPServer + response = self.request(self.base_url + '/test') +-- +GitLab + diff --git a/pypy3.9.spec b/pypy3.9.spec index 14623b6..59e55d6 100644 --- a/pypy3.9.spec +++ b/pypy3.9.spec @@ -10,7 +10,7 @@ Version: %{basever}.%{micro}%{?pre:~%{pre}} # by Python version as well. # This potentially allows tags like Obsoletes: pypy3 < %%{version}-%%{release}. # https://bugzilla.redhat.com/2053880 -%global baserelease 3 +%global baserelease 4 Release: %{baserelease}.%{pyversion}%{?dist} Summary: Python %{pyversion} implementation with a Just-In-Time compiler @@ -130,6 +130,12 @@ Source189: 189-use-rpm-wheels.patch # Tracker bug: https://bugzilla.redhat.com/show_bug.cgi?id=2075390 Patch382: 382-cve-2015-20107.patch +# 00386 # +# CVE-2021-28861: open redirection in http.server +# Upstream: https://foss.heptapod.net/pypy/pypy/-/commit/e42be9b593f1d5e83a947f73058b919395398424.patch +# Tracker bug: https://bugzilla.redhat.com/show_bug.cgi?id=2120642 +Patch386: 386-cve-2021-28861.patch + # Build-time requirements: # pypy's can be rebuilt using pypy2, rather than with CPython 2; doing so @@ -836,6 +842,10 @@ CheckPyPy pypy%{pyversion}-c %changelog +* Mon Oct 10 2022 Lumír Balhar - 7.3.9-4.3.9 +- Backport fix for CVE-2021-28861 +Resolves: rhbz#2120789 + * Fri Jul 22 2022 Fedora Release Engineering - 7.3.9-3.3.9 - Rebuilt for https://fedoraproject.org/wiki/Fedora_37_Mass_Rebuild