From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Lumir Balhar Date: Fri, 17 Sep 2021 07:56:50 +0200 Subject: [PATCH] 00368-CVE-2021-3737.patch 00368 # CVE-2021-3737: http client infinite line reading (DoS) after a HTTP 100 Continue Fixes http.client potential denial of service where it could get stuck reading lines from a malicious server after a 100 Continue response. Backported from Python 3. Co-authored-by: Gregory P. Smith Co-authored-by: Gen Xu --- Lib/httplib.py | 32 +++++++++++++++++++++++--------- Lib/test/test_httplib.py | 8 ++++++++ 2 files changed, 31 insertions(+), 9 deletions(-) diff --git a/Lib/httplib.py b/Lib/httplib.py index a63677477d5..f9a27619e62 100644 --- a/Lib/httplib.py +++ b/Lib/httplib.py @@ -365,6 +365,25 @@ class HTTPMessage(mimetools.Message): # It's not a header line; skip it and try the next line. self.status = 'Non-header line where header expected' + +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: + line = fp.readline(_MAXLINE + 1) + if len(line) > _MAXLINE: + raise LineTooLong("header line") + headers.append(line) + if len(headers) > _MAXHEADERS: + raise HTTPException("got more than %d headers" % _MAXHEADERS) + if line in (b'\r\n', b'\n', b''): + break + return headers + + class HTTPResponse: # strict: If true, raise BadStatusLine if the status line can't be @@ -453,15 +472,10 @@ class HTTPResponse: 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.status = status self.reason = reason.strip() diff --git a/Lib/test/test_httplib.py b/Lib/test/test_httplib.py index b5fec9aa1ec..d05c0fc28d2 100644 --- a/Lib/test/test_httplib.py +++ b/Lib/test/test_httplib.py @@ -700,6 +700,14 @@ class BasicTest(TestCase): resp = httplib.HTTPResponse(FakeSocket(body)) self.assertRaises(httplib.LineTooLong, resp.begin) + def test_overflowing_header_limit_after_100(self): + body = ( + 'HTTP/1.1 100 OK\r\n' + 'r\n' * 32768 + ) + resp = httplib.HTTPResponse(FakeSocket(body)) + self.assertRaises(httplib.HTTPException, resp.begin) + def test_overflowing_chunked_line(self): body = ( 'HTTP/1.1 200 OK\r\n'