python rebuild python3 ver.bum
This commit is contained in:
+133
@@ -0,0 +1,133 @@
|
||||
From 117bd40b3844733e96a8f5ccc9460900698cffbe Mon Sep 17 00:00:00 2001
|
||||
From: "Miss Islington (bot)"
|
||||
<31488909+miss-islington@users.noreply.github.com>
|
||||
Date: Tue, 16 Mar 2021 14:08:30 -0700
|
||||
Subject: [PATCH 26/30] [3.6] bpo-43285 Make ftplib not trust the PASV
|
||||
response. (GH-24838) (GH-24881) (GH-24882)
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
The IPv4 address value returned from the server in response to the PASV command
|
||||
should not be trusted. This prevents a malicious FTP server from using the
|
||||
response to probe IPv4 address and port combinations on the client network.
|
||||
|
||||
Instead of using the returned address, we use the IP address we're
|
||||
already connected to. This is the strategy other ftp clients adopted,
|
||||
and matches the only strategy available for the modern IPv6 EPSV command
|
||||
where the server response must return a port number and nothing else.
|
||||
|
||||
For the rare user who _wants_ this ugly behavior, set a `trust_server_pasv_ipv4_address`
|
||||
attribute on your `ftplib.FTP` instance to True..
|
||||
(cherry picked from commit 0ab152c6b5d95caa2dc1a30fa96e10258b5f188e)
|
||||
|
||||
Co-authored-by: Gregory P. Smith <greg@krypto.org>
|
||||
(cherry picked from commit 664d1d16274b47eea6ec92572e1ebf3939a6fa0c)
|
||||
|
||||
Rebased for Python 2.7 by Michał Górny <mgorny@gentoo.org>
|
||||
---
|
||||
Lib/ftplib.py | 9 +++++-
|
||||
Lib/test/test_ftplib.py | 29 +++++++++++++++++--
|
||||
.../2021-03-13-03-48-14.bpo-43285.g-Hah3.rst | 8 +++++
|
||||
3 files changed, 43 insertions(+), 3 deletions(-)
|
||||
create mode 100644 Misc/NEWS.d/next/Security/2021-03-13-03-48-14.bpo-43285.g-Hah3.rst
|
||||
|
||||
diff --git a/Lib/ftplib.py b/Lib/ftplib.py
|
||||
index 6644554792..0550f0ab9f 100644
|
||||
--- a/Lib/ftplib.py
|
||||
+++ b/Lib/ftplib.py
|
||||
@@ -108,6 +108,8 @@ class FTP:
|
||||
file = None
|
||||
welcome = None
|
||||
passiveserver = 1
|
||||
+ # Disables https://bugs.python.org/issue43285 security if set to True.
|
||||
+ trust_server_pasv_ipv4_address = False
|
||||
|
||||
# Initialization method (called by class instantiation).
|
||||
# Initialize host to localhost, port to standard ftp port
|
||||
@@ -310,8 +312,13 @@ class FTP:
|
||||
return sock
|
||||
|
||||
def makepasv(self):
|
||||
+ """Internal: Does the PASV or EPSV handshake -> (address, port)"""
|
||||
if self.af == socket.AF_INET:
|
||||
- host, port = parse227(self.sendcmd('PASV'))
|
||||
+ untrusted_host, port = parse227(self.sendcmd('PASV'))
|
||||
+ if self.trust_server_pasv_ipv4_address:
|
||||
+ host = untrusted_host
|
||||
+ else:
|
||||
+ host = self.sock.getpeername()[0]
|
||||
else:
|
||||
host, port = parse229(self.sendcmd('EPSV'), self.sock.getpeername())
|
||||
return host, port
|
||||
diff --git a/Lib/test/test_ftplib.py b/Lib/test/test_ftplib.py
|
||||
index 8a3eb067a4..f3217d686d 100644
|
||||
--- a/Lib/test/test_ftplib.py
|
||||
+++ b/Lib/test/test_ftplib.py
|
||||
@@ -67,6 +67,10 @@ class DummyFTPHandler(asynchat.async_chat):
|
||||
self.rest = None
|
||||
self.next_retr_data = RETR_DATA
|
||||
self.push('220 welcome')
|
||||
+ # We use this as the string IPv4 address to direct the client
|
||||
+ # to in response to a PASV command. To test security behavior.
|
||||
+ # https://bugs.python.org/issue43285/.
|
||||
+ self.fake_pasv_server_ip = '252.253.254.255'
|
||||
|
||||
def collect_incoming_data(self, data):
|
||||
self.in_buffer.append(data)
|
||||
@@ -109,8 +113,9 @@ class DummyFTPHandler(asynchat.async_chat):
|
||||
sock.bind((self.socket.getsockname()[0], 0))
|
||||
sock.listen(5)
|
||||
sock.settimeout(10)
|
||||
- ip, port = sock.getsockname()[:2]
|
||||
- ip = ip.replace('.', ',')
|
||||
+ port = sock.getsockname()[1]
|
||||
+ ip = self.fake_pasv_server_ip
|
||||
+ ip = ip.replace('.', ','); p1 = port // 256; p2 = port % 256
|
||||
p1, p2 = divmod(port, 256)
|
||||
self.push('227 entering passive mode (%s,%d,%d)' %(ip, p1, p2))
|
||||
conn, addr = sock.accept()
|
||||
@@ -577,6 +582,26 @@ class TestFTPClass(TestCase):
|
||||
# IPv4 is in use, just make sure send_epsv has not been used
|
||||
self.assertEqual(self.server.handler_instance.last_received_cmd, 'pasv')
|
||||
|
||||
+ def test_makepasv_issue43285_security_disabled(self):
|
||||
+ """Test the opt-in to the old vulnerable behavior."""
|
||||
+ self.client.trust_server_pasv_ipv4_address = True
|
||||
+ bad_host, port = self.client.makepasv()
|
||||
+ self.assertEqual(
|
||||
+ bad_host, self.server.handler_instance.fake_pasv_server_ip)
|
||||
+ # Opening and closing a connection keeps the dummy server happy
|
||||
+ # instead of timing out on accept.
|
||||
+ socket.create_connection((self.client.sock.getpeername()[0], port),
|
||||
+ timeout=TIMEOUT).close()
|
||||
+
|
||||
+ def test_makepasv_issue43285_security_enabled_default(self):
|
||||
+ self.assertFalse(self.client.trust_server_pasv_ipv4_address)
|
||||
+ trusted_host, port = self.client.makepasv()
|
||||
+ self.assertNotEqual(
|
||||
+ trusted_host, self.server.handler_instance.fake_pasv_server_ip)
|
||||
+ # Opening and closing a connection keeps the dummy server happy
|
||||
+ # instead of timing out on accept.
|
||||
+ socket.create_connection((trusted_host, port), timeout=TIMEOUT).close()
|
||||
+
|
||||
def test_line_too_long(self):
|
||||
self.assertRaises(ftplib.Error, self.client.sendcmd,
|
||||
'x' * self.client.maxline * 2)
|
||||
diff --git a/Misc/NEWS.d/next/Security/2021-03-13-03-48-14.bpo-43285.g-Hah3.rst b/Misc/NEWS.d/next/Security/2021-03-13-03-48-14.bpo-43285.g-Hah3.rst
|
||||
new file mode 100644
|
||||
index 0000000000..8312b7e885
|
||||
--- /dev/null
|
||||
+++ b/Misc/NEWS.d/next/Security/2021-03-13-03-48-14.bpo-43285.g-Hah3.rst
|
||||
@@ -0,0 +1,8 @@
|
||||
+:mod:`ftplib` no longer trusts the IP address value returned from the server
|
||||
+in response to the PASV command by default. This prevents a malicious FTP
|
||||
+server from using the response to probe IPv4 address and port combinations
|
||||
+on the client network.
|
||||
+
|
||||
+Code that requires the former vulnerable behavior may set a
|
||||
+``trust_server_pasv_ipv4_address`` attribute on their
|
||||
+:class:`ftplib.FTP` instances to ``True`` to re-enable it.
|
||||
--
|
||||
2.32.0
|
||||
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
From 93742fbb8de75c036b552294fc2bd73eafa47592 Mon Sep 17 00:00:00 2001
|
||||
From: "Miss Islington (bot)"
|
||||
<31488909+miss-islington@users.noreply.github.com>
|
||||
Date: Wed, 7 Apr 2021 04:45:05 -0700
|
||||
Subject: [PATCH 27/30] bpo-43075: Fix ReDoS in urllib AbstractBasicAuthHandler
|
||||
(GH-24391)
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
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>
|
||||
(backported to Python 2.7 by Michał Górny)
|
||||
---
|
||||
Lib/urllib2.py | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/Lib/urllib2.py b/Lib/urllib2.py
|
||||
index b2d1fad6f2..c92fb6afb8 100644
|
||||
--- a/Lib/urllib2.py
|
||||
+++ b/Lib/urllib2.py
|
||||
@@ -858,7 +858,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'
|
||||
--
|
||||
2.32.0
|
||||
|
||||
+150
@@ -0,0 +1,150 @@
|
||||
From 429f40abd4dfc8d8b795de68ff9e268a43b12c25 Mon Sep 17 00:00:00 2001
|
||||
From: "Miss Islington (bot)"
|
||||
<31488909+miss-islington@users.noreply.github.com>
|
||||
Date: Thu, 29 Apr 2021 10:57:31 -0700
|
||||
Subject: [PATCH 28/30] [3.9] bpo-43882 - urllib.parse should sanitize urls
|
||||
containing ASCII newline and tabs. (GH-25595) (GH-25725)
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
* bpo-43882 - urllib.parse should sanitize urls containing ASCII newline and tabs. (GH-25595)
|
||||
|
||||
Co-authored-by: Gregory P. Smith <greg@krypto.org>
|
||||
Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
|
||||
(cherry picked from commit 76cd81d60310d65d01f9d7b48a8985d8ab89c8b4)
|
||||
Co-authored-by: Senthil Kumaran <skumaran@gatech.edu>
|
||||
(backported to Python 2.7 by Michał Górny)
|
||||
---
|
||||
Doc/library/urlparse.rst | 13 +++++++++
|
||||
Lib/test/test_urlparse.py | 29 +++++++++++++++++++
|
||||
Lib/urlparse.py | 7 +++++
|
||||
.../2021-04-25-07-46-37.bpo-43882.Jpwx85.rst | 6 ++++
|
||||
4 files changed, 55 insertions(+)
|
||||
create mode 100644 Misc/NEWS.d/next/Security/2021-04-25-07-46-37.bpo-43882.Jpwx85.rst
|
||||
|
||||
diff --git a/Doc/library/urlparse.rst b/Doc/library/urlparse.rst
|
||||
index 2f8e4c5a44..0546dcae8c 100644
|
||||
--- a/Doc/library/urlparse.rst
|
||||
+++ b/Doc/library/urlparse.rst
|
||||
@@ -267,6 +267,9 @@ The :mod:`urlparse` module defines the following functions:
|
||||
decomposed before parsing, or is not a Unicode string, no error will be
|
||||
raised.
|
||||
|
||||
+ Following the `WHATWG spec`_ that updates RFC 3986, ASCII newline
|
||||
+ ``\n``, ``\r`` and tab ``\t`` characters are stripped from the URL.
|
||||
+
|
||||
.. versionadded:: 2.2
|
||||
|
||||
.. versionchanged:: 2.5
|
||||
@@ -276,6 +279,10 @@ The :mod:`urlparse` module defines the following functions:
|
||||
Characters that affect netloc parsing under NFKC normalization will
|
||||
now raise :exc:`ValueError`.
|
||||
|
||||
+ .. versionchanged:: 2.7.18_p9 (Gentoo)
|
||||
+ ASCII newline and tab characters are stripped from the URL.
|
||||
+
|
||||
+.. _WHATWG spec: https://url.spec.whatwg.org/#concept-basic-url-parser
|
||||
|
||||
.. function:: urlunsplit(parts)
|
||||
|
||||
@@ -327,6 +334,10 @@ The :mod:`urlparse` module defines the following functions:
|
||||
|
||||
.. seealso::
|
||||
|
||||
+ `WHATWG`_ - URL Living standard
|
||||
+ Working Group for the URL Standard that defines URLs, domains, IP addresses, the
|
||||
+ application/x-www-form-urlencoded format, and their API.
|
||||
+
|
||||
:rfc:`3986` - Uniform Resource Identifiers
|
||||
This is the current standard (STD66). Any changes to urlparse module
|
||||
should conform to this. Certain deviations could be observed, which are
|
||||
@@ -351,6 +362,8 @@ The :mod:`urlparse` module defines the following functions:
|
||||
:rfc:`1738` - Uniform Resource Locators (URL)
|
||||
This specifies the formal syntax and semantics of absolute URLs.
|
||||
|
||||
+.. _WHATWG: https://url.spec.whatwg.org/
|
||||
+
|
||||
|
||||
.. _urlparse-result-object:
|
||||
|
||||
diff --git a/Lib/test/test_urlparse.py b/Lib/test/test_urlparse.py
|
||||
index 0b2107339a..9912fe2888 100644
|
||||
--- a/Lib/test/test_urlparse.py
|
||||
+++ b/Lib/test/test_urlparse.py
|
||||
@@ -543,6 +543,35 @@ class UrlParseTestCase(unittest.TestCase):
|
||||
self.assertEqual(p1.params, 'phone-context=+1-914-555')
|
||||
|
||||
|
||||
+ def test_urlsplit_remove_unsafe_bytes(self):
|
||||
+ # Remove ASCII tabs and newlines from input
|
||||
+ url = "http://www.python.org/java\nscript:\talert('msg\r\n')/#frag"
|
||||
+ p = urlparse.urlsplit(url)
|
||||
+ self.assertEqual(p.scheme, "http")
|
||||
+ self.assertEqual(p.netloc, "www.python.org")
|
||||
+ self.assertEqual(p.path, "/javascript:alert('msg')/")
|
||||
+ self.assertEqual(p.query, "")
|
||||
+ self.assertEqual(p.fragment, "frag")
|
||||
+ self.assertEqual(p.username, None)
|
||||
+ self.assertEqual(p.password, None)
|
||||
+ self.assertEqual(p.hostname, "www.python.org")
|
||||
+ self.assertEqual(p.port, None)
|
||||
+ self.assertEqual(p.geturl(), "http://www.python.org/javascript:alert('msg')/#frag")
|
||||
+
|
||||
+ # Remove ASCII tabs and newlines from input as bytes.
|
||||
+ url = b"http://www.python.org/java\nscript:\talert('msg\r\n')/#frag"
|
||||
+ p = urlparse.urlsplit(url)
|
||||
+ self.assertEqual(p.scheme, b"http")
|
||||
+ self.assertEqual(p.netloc, b"www.python.org")
|
||||
+ self.assertEqual(p.path, b"/javascript:alert('msg')/")
|
||||
+ self.assertEqual(p.query, b"")
|
||||
+ self.assertEqual(p.fragment, b"frag")
|
||||
+ self.assertEqual(p.username, None)
|
||||
+ self.assertEqual(p.password, None)
|
||||
+ self.assertEqual(p.hostname, b"www.python.org")
|
||||
+ self.assertEqual(p.port, None)
|
||||
+ self.assertEqual(p.geturl(), b"http://www.python.org/javascript:alert('msg')/#frag")
|
||||
+
|
||||
def test_attributes_bad_port(self):
|
||||
"""Check handling of non-integer ports."""
|
||||
p = urlparse.urlsplit("http://www.example.net:foo")
|
||||
diff --git a/Lib/urlparse.py b/Lib/urlparse.py
|
||||
index 6c32727fce..4f24cc12c6 100644
|
||||
--- a/Lib/urlparse.py
|
||||
+++ b/Lib/urlparse.py
|
||||
@@ -62,6 +62,9 @@ scheme_chars = ('abcdefghijklmnopqrstuvwxyz'
|
||||
'0123456789'
|
||||
'+-.')
|
||||
|
||||
+# Unsafe bytes to be removed per WHATWG spec
|
||||
+_UNSAFE_URL_BYTES_TO_REMOVE = ['\t', '\r', '\n']
|
||||
+
|
||||
MAX_CACHE_SIZE = 20
|
||||
_parse_cache = {}
|
||||
|
||||
@@ -198,6 +201,10 @@ def urlsplit(url, scheme='', allow_fragments=True):
|
||||
if len(_parse_cache) >= MAX_CACHE_SIZE: # avoid runaway growth
|
||||
clear_cache()
|
||||
netloc = query = fragment = ''
|
||||
+
|
||||
+ for b in _UNSAFE_URL_BYTES_TO_REMOVE:
|
||||
+ url = url.replace(b, "")
|
||||
+
|
||||
i = url.find(':')
|
||||
if i > 0:
|
||||
if url[:i] == 'http': # optimize the common case
|
||||
diff --git a/Misc/NEWS.d/next/Security/2021-04-25-07-46-37.bpo-43882.Jpwx85.rst b/Misc/NEWS.d/next/Security/2021-04-25-07-46-37.bpo-43882.Jpwx85.rst
|
||||
new file mode 100644
|
||||
index 0000000000..a326d079df
|
||||
--- /dev/null
|
||||
+++ b/Misc/NEWS.d/next/Security/2021-04-25-07-46-37.bpo-43882.Jpwx85.rst
|
||||
@@ -0,0 +1,6 @@
|
||||
+The presence of newline or tab characters in parts of a URL could allow
|
||||
+some forms of attacks.
|
||||
+
|
||||
+Following the controlling specification for URLs defined by WHATWG
|
||||
+:func:`urllib.parse` now removes ASCII newlines and tabs from URLs,
|
||||
+preventing such attacks.
|
||||
--
|
||||
2.32.0
|
||||
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
From e1a42c83c6cae70dd42c6ecf1261049edce5ce63 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Micha=C5=82=20G=C3=B3rny?= <mgorny@gentoo.org>
|
||||
Date: Sat, 19 Jun 2021 20:46:09 +0200
|
||||
Subject: [PATCH 30/30] 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.
|
||||
---
|
||||
Lib/httplib.py | 5 ++++-
|
||||
Lib/test/test_httplib.py | 13 +++++++++++++
|
||||
2 files changed, 17 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/Lib/httplib.py b/Lib/httplib.py
|
||||
index 81a08d5d71..ebfa59ff93 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 e20a0986dc..5f6b1d0b20 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'
|
||||
--
|
||||
2.32.0
|
||||
|
||||
Reference in New Issue
Block a user