fix CVE-2021-3733 CVE-2021-3737

This commit is contained in:
sxt1001 2021-09-24 17:53:51 +08:00
parent f3aa015cb0
commit 82f2e5d35e
4 changed files with 207 additions and 1 deletions

View File

@ -0,0 +1,41 @@
From ada14995870abddc277addf57dd690a2af04c2da Mon Sep 17 00:00:00 2001
From: "Miss Islington (bot)"
<31488909+miss-islington@users.noreply.github.com>
Date: Tue, 4 May 2021 05:46:40 -0700
Subject: [PATCH] bpo-43075: Fix ReDoS in urllib AbstractBasicAuthHandler
(GH-24391) (#25249)
Fix Regular Expression Denial of Service (ReDoS) vulnerability in
urllib.request.AbstractBasicAuthHandler. The ReDoS-vulnerable regex
has quadratic worst-case complexity and it allows cause a denial of
service when identifying crafted invalid RFCs. This ReDoS issue is on
the client side and needs remote attackers to control the HTTP server.
(cherry picked from commit 7215d1ae25525c92b026166f9d5cac85fb1defe1)
Co-authored-by: Yeting Li <liyt@ios.ac.cn>
---
Lib/urllib/request.py | 2 +-
.../next/Security/2021-01-31-05-28-14.bpo-43075.DoAXqO.rst | 1 +
2 files changed, 2 insertions(+), 1 deletion(-)
create mode 100644 Misc/NEWS.d/next/Security/2021-01-31-05-28-14.bpo-43075.DoAXqO.rst
diff --git a/Lib/urllib/request.py b/Lib/urllib/request.py
index 4f42919b09eae..16b7e1c50985d 100644
--- a/Lib/urllib/request.py
+++ b/Lib/urllib/request.py
@@ -946,7 +946,7 @@ class AbstractBasicAuthHandler:
# (single quotes are a violation of the RFC, but appear in the wild)
rx = re.compile('(?:^|,)' # start of the string or ','
'[ \t]*' # optional whitespaces
- '([^ \t]+)' # scheme like "Basic"
+ '([^ \t,]+)' # scheme like "Basic"
'[ \t]+' # mandatory whitespaces
# realm=xxx
# realm='xxx'
diff --git a/Misc/NEWS.d/next/Security/2021-01-31-05-28-14.bpo-43075.DoAXqO.rst b/Misc/NEWS.d/next/Security/2021-01-31-05-28-14.bpo-43075.DoAXqO.rst
new file mode 100644
index 0000000000000..1c9f727e965fb
--- /dev/null
+++ b/Misc/NEWS.d/next/Security/2021-01-31-05-28-14.bpo-43075.DoAXqO.rst
@@ -0,0 +1 @@
+Fix Regular Expression Denial of Service (ReDoS) vulnerability in :class:`urllib.request.AbstractBasicAuthHandler`. The ReDoS-vulnerable regex has quadratic worst-case complexity and it allows cause a denial of service when identifying crafted invalid RFCs. This ReDoS issue is on the client side and needs remote attackers to control the HTTP server.

View File

@ -0,0 +1,120 @@
From 078b146f062d212919d0ba25e34e658a8234aa63 Mon Sep 17 00:00:00 2001
From: "Miss Islington (bot)"
<31488909+miss-islington@users.noreply.github.com>
Date: Thu, 6 May 2021 10:10:13 -0700
Subject: [PATCH] bpo-44022: Fix http client infinite line reading (DoS) after
a HTTP 100 Continue (GH-25916) (GH-25934)
Fixes http.client potential denial of service where it could get stuck reading lines from a malicious server after a 100 Continue response.
Co-authored-by: Gregory P. Smith <greg@krypto.org>
(cherry picked from commit 47895e31b6f626bc6ce47d175fe9d43c1098909d)
Co-authored-by: Gen Xu <xgbarry@gmail.com>
---
Lib/http/client.py | 38 ++++++++++---------
Lib/test/test_httplib.py | 10 ++++-
.../2021-05-05-17-37-04.bpo-44022.bS3XJ9.rst | 2 +
3 files changed, 32 insertions(+), 18 deletions(-)
create mode 100644 Misc/NEWS.d/next/Security/2021-05-05-17-37-04.bpo-44022.bS3XJ9.rst
diff --git a/Lib/http/client.py b/Lib/http/client.py
index 04cd8f7d84986..b756f607d344e 100644
--- a/Lib/http/client.py
+++ b/Lib/http/client.py
@@ -204,15 +204,11 @@ def getallmatchingheaders(self, name):
lst.append(line)
return lst
-def parse_headers(fp, _class=HTTPMessage):
- """Parses only RFC2822 headers from a file pointer.
-
- email Parser wants to see strings rather than bytes.
- But a TextIOWrapper around self.rfile would buffer too many bytes
- from the stream, bytes which we later need to read as bytes.
- So we read the correct bytes here, as bytes, for email Parser
- to parse.
+def _read_headers(fp):
+ """Reads potential header lines into a list from a file pointer.
+ Length of line is limited by _MAXLINE, and number of
+ headers is limited by _MAXHEADERS.
"""
headers = []
while True:
@@ -224,6 +220,19 @@ def parse_headers(fp, _class=HTTPMessage):
raise HTTPException("got more than %d headers" % _MAXHEADERS)
if line in (b'\r\n', b'\n', b''):
break
+ return headers
+
+def parse_headers(fp, _class=HTTPMessage):
+ """Parses only RFC2822 headers from a file pointer.
+
+ email Parser wants to see strings rather than bytes.
+ But a TextIOWrapper around self.rfile would buffer too many bytes
+ from the stream, bytes which we later need to read as bytes.
+ So we read the correct bytes here, as bytes, for email Parser
+ to parse.
+
+ """
+ headers = _read_headers(fp)
hstring = b''.join(headers).decode('iso-8859-1')
return email.parser.Parser(_class=_class).parsestr(hstring)
@@ -311,15 +320,10 @@ def begin(self):
if status != CONTINUE:
break
# skip the header from the 100 response
- while True:
- skip = self.fp.readline(_MAXLINE + 1)
- if len(skip) > _MAXLINE:
- raise LineTooLong("header line")
- skip = skip.strip()
- if not skip:
- break
- if self.debuglevel > 0:
- print("header:", skip)
+ skipped_headers = _read_headers(self.fp)
+ if self.debuglevel > 0:
+ print("headers:", skipped_headers)
+ del skipped_headers
self.code = self.status = status
self.reason = reason.strip()
diff --git a/Lib/test/test_httplib.py b/Lib/test/test_httplib.py
index 3fa0691d3ad8f..8333aa0eeef6a 100644
--- a/Lib/test/test_httplib.py
+++ b/Lib/test/test_httplib.py
@@ -998,6 +998,14 @@ def test_overflowing_header_line(self):
resp = client.HTTPResponse(FakeSocket(body))
self.assertRaises(client.LineTooLong, resp.begin)
+ def test_overflowing_header_limit_after_100(self):
+ body = (
+ 'HTTP/1.1 100 OK\r\n'
+ 'r\n' * 32768
+ )
+ resp = client.HTTPResponse(FakeSocket(body))
+ self.assertRaises(client.HTTPException, resp.begin)
+
def test_overflowing_chunked_line(self):
body = (
'HTTP/1.1 200 OK\r\n'
@@ -1402,7 +1410,7 @@ def readline(self, limit):
class OfflineTest(TestCase):
def test_all(self):
# Documented objects defined in the module should be in __all__
- expected = {"responses"} # White-list documented dict() object
+ expected = {"responses"} # Allowlist documented dict() object
# HTTPMessage, parse_headers(), and the HTTP status code constants are
# intentionally omitted for simplicity
blacklist = {"HTTPMessage", "parse_headers"}
diff --git a/Misc/NEWS.d/next/Security/2021-05-05-17-37-04.bpo-44022.bS3XJ9.rst b/Misc/NEWS.d/next/Security/2021-05-05-17-37-04.bpo-44022.bS3XJ9.rst
new file mode 100644
index 0000000000000..cf6b63e396155
--- /dev/null
+++ b/Misc/NEWS.d/next/Security/2021-05-05-17-37-04.bpo-44022.bS3XJ9.rst
@@ -0,0 +1,2 @@
+mod:`http.client` now avoids infinitely reading potential HTTP headers after a
+``100 Continue`` status response from the server.

View File

@ -0,0 +1,33 @@
From fee96422e6f0056561cf74fef2012cc066c9db86 Mon Sep 17 00:00:00 2001
From: "Miss Islington (bot)"
<31488909+miss-islington@users.noreply.github.com>
Date: Wed, 2 Jun 2021 21:23:40 -0700
Subject: [PATCH] bpo-44022: Improve the regression test. (GH-26503) (GH-26507)
It wasn't actually detecting the regression due to the
assertion being too lenient.
(cherry picked from commit e60ab843cbb016fb6ff8b4f418641ac05a9b2fcc)
Co-authored-by: Gregory P. Smith <greg@krypto.org>
---
Lib/test/test_httplib.py | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/Lib/test/test_httplib.py b/Lib/test/test_httplib.py
index 8333aa0eeef6a..a65044eea60dc 100644
--- a/Lib/test/test_httplib.py
+++ b/Lib/test/test_httplib.py
@@ -1004,7 +1004,12 @@ def test_overflowing_header_limit_after_100(self):
'r\n' * 32768
)
resp = client.HTTPResponse(FakeSocket(body))
- self.assertRaises(client.HTTPException, resp.begin)
+ with self.assertRaises(client.HTTPException) as cm:
+ resp.begin()
+ # We must assert more because other reasonable errors that we
+ # do not want can also be HTTPException derived.
+ self.assertIn('got more than ', str(cm.exception))
+ self.assertIn('headers', str(cm.exception))
def test_overflowing_chunked_line(self):
body = (

View File

@ -3,7 +3,7 @@ Summary: Interpreter of the Python3 programming language
URL: https://www.python.org/
Version: 3.7.9
Release: 16
Release: 17
License: Python
%global branchversion 3.7
@ -149,6 +149,9 @@ Patch6039: backport-37169-Rewrite-_PyObject_IsFreed-unit-tests-GH-13.patch
Patch6040: backport-44363-Get-test_capi-passing-with-address-sanitiz.patch
Patch6041: backport-36253-Remove-use-after-free-reference-in-ctypes-.patch
Patch6042: backport-36356-Fix-memory-leak-in-_asynciomodule.c-GH-165.patch
Patch6043: backport-CVE-2021-3733.patch
Patch6044: backport-CVE-2021-3737.patch
Patch6045: backport-bpo-44022-Improve-the-regression-test.patch
patch9000: Don-t-override-PYTHONPATH-which-is-already-set.patch
@ -285,6 +288,9 @@ rm Lib/ensurepip/_bundled/*.whl
%patch6040 -p1
%patch6041 -p1
%patch6042 -p1
%patch6043 -p1
%patch6044 -p1
%patch6045 -p1
%patch9000 -p1
sed -i "s/generic_os/%{_vendor}/g" Lib/platform.py
@ -887,6 +893,12 @@ export BEP_GTDLIST="$BEP_GTDLIST_TMP"
%{_mandir}/*/*
%changelog
* Fri Sep 24 2021 shixuantong<shixuantong@huawei.com> - 3.7.9-17
- Type:CVE
- CVE:CVE-2021-3733 CVE-2021-3737
- SUG:NA
- DESC:fix CVE-2021-3733 CVE-2021-3737
* Thu Aug 19 2021 hehuazhen<hehuazhen@huawei.com> - 3.7.9-16
- Type:bugfix
- CVE:NA