import python3-3.6.8-42.el8

This commit is contained in:
CentOS Sources 2021-09-22 10:21:55 +00:00 committed by root
parent be68a5416f
commit f6693e83a5
2 changed files with 131 additions and 1 deletions

View File

@ -0,0 +1,119 @@
From f7fb35b563a9182c22fbdd03c72ec3724dafe918 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 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 53581eca20587..07e675fac5981 100644
--- a/Lib/http/client.py
+++ b/Lib/http/client.py
@@ -205,15 +205,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:
@@ -225,6 +221,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)
@@ -312,15 +321,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 03e049b13fd21..0db287507c7bf 100644
--- a/Lib/test/test_httplib.py
+++ b/Lib/test/test_httplib.py
@@ -971,6 +971,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'
@@ -1377,7 +1385,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

@ -14,7 +14,7 @@ URL: https://www.python.org/
# WARNING When rebasing to a new Python version,
# remember to update the python3-docs package as well
Version: %{pybasever}.8
Release: 41%{?dist}
Release: 42%{?dist}
License: Python
@ -616,6 +616,12 @@ Patch364: 00364-thread-exit.patch
# Tracking bug: https://bugzilla.redhat.com/show_bug.cgi?id=1995234
Patch366: 00366-CVE-2021-3733.patch
# 00368 #
# CVE-2021-3737: client can enter an infinite loop on a 100 Continue response from the server
# Upstream: https://bugs.python.org/issue44022
# Tracking bug: https://bugzilla.redhat.com/show_bug.cgi?id=1995162
Patch368: 00368-CVE-2021-3737.patch
# (New patches go here ^^^)
#
# When adding new patches to "python" and "python3" in Fedora, EL, etc.,
@ -950,6 +956,7 @@ git apply %{PATCH351}
%patch362 -p1
%patch364 -p1
%patch366 -p1
%patch368 -p1
# Remove files that should be generated by the build
# (This is after patching, so that we can use patches directly from upstream)
@ -1875,6 +1882,10 @@ fi
# ======================================================
%changelog
* Fri Sep 17 2021 Lumír Balhar <lbalhar@redhat.com> - 3.6.8-42
- Security fix for CVE-2021-3737
Resolves: rhbz#1995162
* Thu Sep 09 2021 Lumír Balhar <lbalhar@redhat.com> - 3.6.8-41
- Security fix for CVE-2021-3733: Denial of service when identifying crafted invalid RFCs
Resolves: rhbz#1995234