fix CVE-2021-3733 CVE-2021-3737

This commit is contained in:
shixuantong 2021-09-27 16:38:39 +08:00
parent 572be03893
commit 86bdf6beb6
4 changed files with 205 additions and 1 deletions

View File

@ -0,0 +1,40 @@
From 7215d1ae25525c92b026166f9d5cac85fb1defe1 Mon Sep 17 00:00:00 2001
From: Yeting Li <liyt@ios.ac.cn>
Date: Wed, 7 Apr 2021 19:27:41 +0800
Subject: [PATCH] bpo-43075: Fix ReDoS in urllib AbstractBasicAuthHandler
(GH-24391)
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.
---
Lib/urllib/request.py | 2 +-
Misc/NEWS.d/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 e440738..f6ec148 100644
--- a/Lib/urllib/request.py
+++ b/Lib/urllib/request.py
@@ -947,7 +947,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 0000000..1c9f727
--- /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.
--
1.8.3.1

View File

@ -0,0 +1,120 @@
From 47895e31b6f626bc6ce47d175fe9d43c1098909d Mon Sep 17 00:00:00 2001
From: Gen Xu <xgbarry@gmail.com>
Date: Wed, 5 May 2021 15:42:41 -0700
Subject: [PATCH] bpo-44022: Fix http client infinite line reading (DoS) after
a HTTP 100 Continue (GH-25916)
Fixes http.client potential denial of service where it could get stuck reading lines from a malicious server after a 100 Cont
inue response.
Co-authored-by: Gregory P. Smith <greg@krypto.org>
---
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 c2ad047..2b88d43 100644
--- a/Lib/http/client.py
+++ b/Lib/http/client.py
@@ -201,15 +201,11 @@ class HTTPMessage(email.message.Message):
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:
@@ -221,6 +217,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)
@@ -308,15 +317,10 @@ class HTTPResponse(io.BufferedIOBase):
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 5a5fcec..2777969 100644
--- a/Lib/test/test_httplib.py
+++ b/Lib/test/test_httplib.py
@@ -999,6 +999,14 @@ class BasicTest(TestCase):
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'
@@ -1400,7 +1408,7 @@ class Readliner:
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 0000000..cf6b63e
--- /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.
--
1.8.3.1

View File

@ -0,0 +1,32 @@
From e60ab843cbb016fb6ff8b4f418641ac05a9b2fcc Mon Sep 17 00:00:00 2001
From: "Gregory P. Smith" <greg@krypto.org>
Date: Wed, 2 Jun 2021 20:43:38 -0700
Subject: [PATCH] bpo-44022: Improve the regression test. (GH-26503)
It wasn't actually detecting the regression due to the
assertion being too lenient.
---
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 2777969..419904d 100644
--- a/Lib/test/test_httplib.py
+++ b/Lib/test/test_httplib.py
@@ -1005,7 +1005,12 @@ class BasicTest(TestCase):
'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 = (
--
1.8.3.1

View File

@ -3,7 +3,7 @@ Summary: Interpreter of the Python3 programming language
URL: https://www.python.org/
Version: 3.8.5
Release: 12
Release: 13
License: Python
%global branchversion 3.8
@ -101,6 +101,9 @@ Patch256: backport-Remove-thread-objects-which-finished-process-its-request.patc
Patch257: backport-Fix-reference-leak-when-Thread-is-never-joined.patch
Patch6000: backport-CVE-2021-3426.patch
Patch6001: backport-CVE-2021-29921.patch
Patch6002: backport-CVE-2021-3733.patch
Patch6003: backport-CVE-2021-3737.patch
Patch6004: backport-bpo-44022-Improve-the-regression-test.patch
Provides: python%{branchversion} = %{version}-%{release}
Provides: python(abi) = %{branchversion}
@ -200,6 +203,9 @@ rm Lib/ensurepip/_bundled/*.whl
%patch257 -p1
%patch6000 -p1
%patch6001 -p1
%patch6002 -p1
%patch6003 -p1
%patch6004 -p1
rm configure pyconfig.h.in
@ -807,6 +813,12 @@ export BEP_GTDLIST="$BEP_GTDLIST_TMP"
%{_mandir}/*/*
%changelog
* Mon Sep 27 2021 shixuantong<shixuantong@huawei.com> - 3.8.5-13
- Type:CVE
- CVE:CVE-2021-3733 CVE-2021-3737
- SUG:NA
- DESC:fix CVE-2021-3733 CVE-2021-3737
* Thu Jul 22 2021 liudabo<liudabo1@huawei.com> - 3.8.5-12
- Type:bugfix
- ID:NA