aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichał Górny <mgorny@gentoo.org>2021-06-19 20:46:09 +0200
committerMichał Górny <mgorny@gentoo.org>2021-06-19 20:52:56 +0200
commitdae96acef25d8c95aff9673e29aa5ddee862e9b4 (patch)
treeef67ef3d42115d7a2fe4a1ca8170cb469c6289b9
parent[3.9] bpo-43882 - urllib.parse should sanitize urls containing ASCII newline ... (diff)
downloadcpython-dae96acef25d8c95aff9673e29aa5ddee862e9b4.tar.gz
cpython-dae96acef25d8c95aff9673e29aa5ddee862e9b4.tar.bz2
cpython-dae96acef25d8c95aff9673e29aa5ddee862e9b4.zip
Backport bpo-44022: Fix http client infinite line reading (DoS) after a HTTP 100 Continue (GH-25916)
Backport the fix from the following commit: commit 47895e31b6f626bc6ce47d175fe9d43c1098909d Author: Gen Xu <xgbarry@gmail.com> Date: 2021-05-06 00:42:41 +0200 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> Instead of reusing the header reading code, I have just added explicit counter to avoid having to refactor the old code. Plus the improved test from: commit e60ab843cbb016fb6ff8b4f418641ac05a9b2fcc Author: Gregory P. Smith <greg@krypto.org> Date: 2021-06-03 05:43:38 +0200 bpo-44022: Improve the regression test. (GH-26503) It wasn't actually detecting the regression due to the assertion being too lenient.
-rw-r--r--Lib/httplib.py5
-rw-r--r--Lib/test/test_httplib.py13
2 files changed, 17 insertions, 1 deletions
diff --git a/Lib/httplib.py b/Lib/httplib.py
index 81a08d5d714..ebfa59ff93c 100644
--- a/Lib/httplib.py
+++ b/Lib/httplib.py
@@ -453,11 +453,14 @@ class HTTPResponse:
if status != CONTINUE:
break
# skip the header from the 100 response
+ header_count = 0
while True:
skip = self.fp.readline(_MAXLINE + 1)
if len(skip) > _MAXLINE:
raise LineTooLong("header line")
- skip = skip.strip()
+ header_count += 1
+ if header_count > _MAXHEADERS:
+ raise HTTPException("got more than %d headers" % _MAXHEADERS)
if not skip:
break
if self.debuglevel > 0:
diff --git a/Lib/test/test_httplib.py b/Lib/test/test_httplib.py
index e20a0986dce..5f6b1d0b20e 100644
--- a/Lib/test/test_httplib.py
+++ b/Lib/test/test_httplib.py
@@ -675,6 +675,19 @@ 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))
+ with self.assertRaises(httplib.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 = (
'HTTP/1.1 200 OK\r\n'