diff -Nru python3.6-3.6.8/debian/changelog python3.6-3.6.9/debian/changelog --- python3.6-3.6.8/debian/changelog 2019-10-07 12:59:55.000000000 +0000 +++ python3.6-3.6.9/debian/changelog 2020-04-18 01:56:04.000000000 +0000 @@ -1,3 +1,32 @@ +python3.6 (3.6.9-1~18.04ubuntu1) bionic-security; urgency=medium + + * SECURITY UPDATE: CRLF injection + - debian/patches/CVE-2019-18348.patch: disallow control characters + in hostnames in http.client in Lib/http/client.py, Lib/test/test_urllib.py. + - CVE-2019-18348 + * SECURITY UPDATE: Denial of service + - debian/patches/CVE-2020-8492.patch: fix the regex to prevent + the regex denial of service in Lib/urllib/request.py, + - CVE-2020-8492 + + -- Leonidas S. Barbosa Fri, 17 Apr 2020 22:56:04 -0300 + +python3.6 (3.6.9-1~18.04) bionic-proposed; urgency=medium + + * SRU: LP: #1835738, backport 3.6.9 to 18.04. + * Python 3.6.9 release. + * Remove patches applied upstream: + - CVE-2018-20852.patch + - CVE-2019-5010.patch + - CVE-2019-9636.patch + - CVE-2019-9740.patch + - CVE-2019-9948.patch + - CVE-2019-10160-1.patch + - CVE-2019-10160-2.patch + * Enable the lto build on arm64. + + -- Matthias Klose Thu, 07 Nov 2019 11:44:02 +0100 + python3.6 (3.6.8-1~18.04.3) bionic-security; urgency=medium * SECURITY UPDATE: incorrect email address parsing @@ -72,6 +101,12 @@ -- Matthias Klose Wed, 12 Dec 2018 07:12:40 +0100 +python3.6 (3.6.7-1~18.10) cosmic-proposed; urgency=medium + + * SRU: LP: #1799206. + + -- Matthias Klose Mon, 22 Oct 2018 13:32:17 +0200 + python3.6 (3.6.7-1) unstable; urgency=medium * Python 3.6.7 release. diff -Nru python3.6-3.6.8/debian/patches/arm-alignment.diff python3.6-3.6.9/debian/patches/arm-alignment.diff --- python3.6-3.6.8/debian/patches/arm-alignment.diff 1970-01-01 00:00:00.000000000 +0000 +++ python3.6-3.6.9/debian/patches/arm-alignment.diff 2019-04-03 05:36:11.000000000 +0000 @@ -0,0 +1,17 @@ +Author: Dave Jones +Description: Use aligned access for _sha3 module on ARM. +--- a/Modules/_sha3/sha3module.c ++++ b/Modules/_sha3/sha3module.c +@@ -64,6 +64,12 @@ + #define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN + #endif + ++/* Bus error on 32-bit ARM due to un-aligned memory accesses; 64-bit ARM ++ * doesn't complain but un-aligned memory accesses are sub-optimal */ ++#if defined(__arm__) || defined(__aarch64__) ++#define NO_MISALIGNED_ACCESSES ++#endif ++ + /* mangle names */ + #define KeccakF1600_FastLoop_Absorb _PySHA3_KeccakF1600_FastLoop_Absorb + #define Keccak_HashFinal _PySHA3_Keccak_HashFinal diff -Nru python3.6-3.6.8/debian/patches/CVE-2018-20852.patch python3.6-3.6.9/debian/patches/CVE-2018-20852.patch --- python3.6-3.6.8/debian/patches/CVE-2018-20852.patch 2019-08-20 17:10:32.000000000 +0000 +++ python3.6-3.6.9/debian/patches/CVE-2018-20852.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,111 +0,0 @@ -From b241af861b37e20ad30533bc0b7e2e5491cc470f Mon Sep 17 00:00:00 2001 -From: "Miss Islington (bot)" - <31488909+miss-islington@users.noreply.github.com> -Date: Sat, 9 Mar 2019 18:59:28 -0800 -Subject: [PATCH] bpo-35121: prefix dot in domain for proper subdomain - validation (GH-10258) (GH-12260) - -Don't send cookies of domain A without Domain attribute to domain B when domain A is a suffix match of domain B while using a cookiejar with `http.cookiejar.DefaultCookiePolicy` policy. Patch by Karthikeyan Singaravelan. -(cherry picked from commit ca7fe5063593958e5efdf90f068582837f07bd14) - -Co-authored-by: Xtreak ---- - Lib/http/cookiejar.py | 13 ++++++-- - Lib/test/test_http_cookiejar.py | 30 +++++++++++++++++++ - .../2018-10-31-15-39-17.bpo-35121.EgHv9k.rst | 4 +++ - 3 files changed, 45 insertions(+), 2 deletions(-) - create mode 100644 Misc/NEWS.d/next/Security/2018-10-31-15-39-17.bpo-35121.EgHv9k.rst - -diff --git a/Lib/http/cookiejar.py b/Lib/http/cookiejar.py -index adf956d66a07..97599d48d8e0 100644 ---- a/Lib/http/cookiejar.py -+++ b/Lib/http/cookiejar.py -@@ -1148,6 +1148,11 @@ def return_ok_domain(self, cookie, request): - req_host, erhn = eff_request_host(request) - domain = cookie.domain - -+ if domain and not domain.startswith("."): -+ dotdomain = "." + domain -+ else: -+ dotdomain = domain -+ - # strict check of non-domain cookies: Mozilla does this, MSIE5 doesn't - if (cookie.version == 0 and - (self.strict_ns_domain & self.DomainStrictNonDomain) and -@@ -1160,7 +1165,7 @@ def return_ok_domain(self, cookie, request): - _debug(" effective request-host name %s does not domain-match " - "RFC 2965 cookie domain %s", erhn, domain) - return False -- if cookie.version == 0 and not ("."+erhn).endswith(domain): -+ if cookie.version == 0 and not ("."+erhn).endswith(dotdomain): - _debug(" request-host %s does not match Netscape cookie domain " - "%s", req_host, domain) - return False -@@ -1174,7 +1179,11 @@ def domain_return_ok(self, domain, request): - req_host = "."+req_host - if not erhn.startswith("."): - erhn = "."+erhn -- if not (req_host.endswith(domain) or erhn.endswith(domain)): -+ if domain and not domain.startswith("."): -+ dotdomain = "." + domain -+ else: -+ dotdomain = domain -+ if not (req_host.endswith(dotdomain) or erhn.endswith(dotdomain)): - #_debug(" request domain %s does not match cookie domain %s", - # req_host, domain) - return False -diff --git a/Lib/test/test_http_cookiejar.py b/Lib/test/test_http_cookiejar.py -index abc625d672a7..6e1b30881310 100644 ---- a/Lib/test/test_http_cookiejar.py -+++ b/Lib/test/test_http_cookiejar.py -@@ -415,6 +415,7 @@ def test_domain_return_ok(self): - ("http://foo.bar.com/", ".foo.bar.com", True), - ("http://foo.bar.com/", "foo.bar.com", True), - ("http://foo.bar.com/", ".bar.com", True), -+ ("http://foo.bar.com/", "bar.com", True), - ("http://foo.bar.com/", "com", True), - ("http://foo.com/", "rhubarb.foo.com", False), - ("http://foo.com/", ".foo.com", True), -@@ -425,6 +426,8 @@ def test_domain_return_ok(self): - ("http://foo/", "foo", True), - ("http://foo/", "foo.local", True), - ("http://foo/", ".local", True), -+ ("http://barfoo.com", ".foo.com", False), -+ ("http://barfoo.com", "foo.com", False), - ]: - request = urllib.request.Request(url) - r = pol.domain_return_ok(domain, request) -@@ -959,6 +962,33 @@ def test_domain_block(self): - c.add_cookie_header(req) - self.assertFalse(req.has_header("Cookie")) - -+ c.clear() -+ -+ pol.set_blocked_domains([]) -+ req = urllib.request.Request("http://acme.com/") -+ res = FakeResponse(headers, "http://acme.com/") -+ cookies = c.make_cookies(res, req) -+ c.extract_cookies(res, req) -+ self.assertEqual(len(c), 1) -+ -+ req = urllib.request.Request("http://acme.com/") -+ c.add_cookie_header(req) -+ self.assertTrue(req.has_header("Cookie")) -+ -+ req = urllib.request.Request("http://badacme.com/") -+ c.add_cookie_header(req) -+ self.assertFalse(pol.return_ok(cookies[0], req)) -+ self.assertFalse(req.has_header("Cookie")) -+ -+ p = pol.set_blocked_domains(["acme.com"]) -+ req = urllib.request.Request("http://acme.com/") -+ c.add_cookie_header(req) -+ self.assertFalse(req.has_header("Cookie")) -+ -+ req = urllib.request.Request("http://badacme.com/") -+ c.add_cookie_header(req) -+ self.assertFalse(req.has_header("Cookie")) -+ - def test_secure(self): - for ns in True, False: - for whitespace in " ", "": diff -Nru python3.6-3.6.8/debian/patches/CVE-2019-10160-1.patch python3.6-3.6.9/debian/patches/CVE-2019-10160-1.patch --- python3.6-3.6.8/debian/patches/CVE-2019-10160-1.patch 2019-08-20 17:12:36.000000000 +0000 +++ python3.6-3.6.9/debian/patches/CVE-2019-10160-1.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,59 +0,0 @@ -From e5f9f4adb95233c66578e6f7ea176687af2f78ca Mon Sep 17 00:00:00 2001 -From: "Miss Islington (bot)" - <31488909+miss-islington@users.noreply.github.com> -Date: Thu, 2 May 2019 09:02:35 -0700 -Subject: [PATCH] bpo-36742: Fixes handling of pre-normalization characters in - urlsplit() (GH-13017) (GH-13024) - -(cherry picked from commit d537ab0ff9767ef024f26246899728f0116b1ec3) - -Co-authored-by: Steve Dower ---- - Lib/test/test_urlparse.py | 6 ++++++ - Lib/urllib/parse.py | 11 +++++++---- - .../Security/2019-04-29-15-34-59.bpo-36742.QCUY0i.rst | 1 + - 3 files changed, 14 insertions(+), 4 deletions(-) - create mode 100644 Misc/NEWS.d/next/Security/2019-04-29-15-34-59.bpo-36742.QCUY0i.rst - -diff --git a/Lib/test/test_urlparse.py b/Lib/test/test_urlparse.py -index e6638aee2244..c26235449461 100644 ---- a/Lib/test/test_urlparse.py -+++ b/Lib/test/test_urlparse.py -@@ -1001,6 +1001,12 @@ def test_urlsplit_normalization(self): - self.assertIn('\u2100', denorm_chars) - self.assertIn('\uFF03', denorm_chars) - -+ # bpo-36742: Verify port separators are ignored when they -+ # existed prior to decomposition -+ urllib.parse.urlsplit('http://\u30d5\u309a:80') -+ with self.assertRaises(ValueError): -+ urllib.parse.urlsplit('http://\u30d5\u309a\ufe1380') -+ - for scheme in ["http", "https", "ftp"]: - for c in denorm_chars: - url = "{}://netloc{}false.netloc/path".format(scheme, c) -diff --git a/Lib/urllib/parse.py b/Lib/urllib/parse.py -index 7b06f4d71d67..791b457bfb8a 100644 ---- a/Lib/urllib/parse.py -+++ b/Lib/urllib/parse.py -@@ -397,13 +397,16 @@ def _checknetloc(netloc): - # looking for characters like \u2100 that expand to 'a/c' - # IDNA uses NFKC equivalence, so normalize for this check - import unicodedata -- netloc2 = unicodedata.normalize('NFKC', netloc) -- if netloc == netloc2: -+ n = netloc.rpartition('@')[2] # ignore anything to the left of '@' -+ n = n.replace(':', '') # ignore characters already included -+ n = n.replace('#', '') # but not the surrounding text -+ n = n.replace('?', '') -+ netloc2 = unicodedata.normalize('NFKC', n) -+ if n == netloc2: - return -- _, _, netloc = netloc.rpartition('@') # anything to the left of '@' is okay - for c in '/?#@:': - if c in netloc2: -- raise ValueError("netloc '" + netloc2 + "' contains invalid " + -+ raise ValueError("netloc '" + netloc + "' contains invalid " + - "characters under NFKC normalization") - - def urlsplit(url, scheme='', allow_fragments=True): diff -Nru python3.6-3.6.8/debian/patches/CVE-2019-10160-2.patch python3.6-3.6.9/debian/patches/CVE-2019-10160-2.patch --- python3.6-3.6.8/debian/patches/CVE-2019-10160-2.patch 2019-08-20 17:12:40.000000000 +0000 +++ python3.6-3.6.9/debian/patches/CVE-2019-10160-2.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,54 +0,0 @@ -From fd1771dbdd28709716bd531580c40ae5ed814468 Mon Sep 17 00:00:00 2001 -From: "Miss Islington (bot)" - <31488909+miss-islington@users.noreply.github.com> -Date: Tue, 4 Jun 2019 11:43:52 -0700 -Subject: [PATCH] bpo-36742: Corrects fix to handle decomposition in usernames - (GH-13812) (GH-13814) - -(cherry picked from commit 8d0ef0b5edeae52960c7ed05ae8a12388324f87e) - -Co-authored-by: Steve Dower ---- - Lib/test/test_urlparse.py | 11 ++++++----- - Lib/urllib/parse.py | 6 +++--- - 2 files changed, 9 insertions(+), 8 deletions(-) - -diff --git a/Lib/test/test_urlparse.py b/Lib/test/test_urlparse.py -index c26235449461..68f633ca3a7d 100644 ---- a/Lib/test/test_urlparse.py -+++ b/Lib/test/test_urlparse.py -@@ -1008,11 +1008,12 @@ def test_urlsplit_normalization(self): - urllib.parse.urlsplit('http://\u30d5\u309a\ufe1380') - - for scheme in ["http", "https", "ftp"]: -- for c in denorm_chars: -- url = "{}://netloc{}false.netloc/path".format(scheme, c) -- with self.subTest(url=url, char='{:04X}'.format(ord(c))): -- with self.assertRaises(ValueError): -- urllib.parse.urlsplit(url) -+ for netloc in ["netloc{}false.netloc", "n{}user@netloc"]: -+ for c in denorm_chars: -+ url = "{}://{}/path".format(scheme, netloc.format(c)) -+ with self.subTest(url=url, char='{:04X}'.format(ord(c))): -+ with self.assertRaises(ValueError): -+ urllib.parse.urlsplit(url) - - class Utility_Tests(unittest.TestCase): - """Testcase to test the various utility functions in the urllib.""" -diff --git a/Lib/urllib/parse.py b/Lib/urllib/parse.py -index 791b457bfb8a..fa8827a9fa79 100644 ---- a/Lib/urllib/parse.py -+++ b/Lib/urllib/parse.py -@@ -397,9 +397,9 @@ def _checknetloc(netloc): - # looking for characters like \u2100 that expand to 'a/c' - # IDNA uses NFKC equivalence, so normalize for this check - import unicodedata -- n = netloc.rpartition('@')[2] # ignore anything to the left of '@' -- n = n.replace(':', '') # ignore characters already included -- n = n.replace('#', '') # but not the surrounding text -+ n = netloc.replace('@', '') # ignore characters already included -+ n = n.replace(':', '') # but not the surrounding text -+ n = n.replace('#', '') - n = n.replace('?', '') - netloc2 = unicodedata.normalize('NFKC', n) - if n == netloc2: diff -Nru python3.6-3.6.8/debian/patches/CVE-2019-18348.patch python3.6-3.6.9/debian/patches/CVE-2019-18348.patch --- python3.6-3.6.8/debian/patches/CVE-2019-18348.patch 1970-01-01 00:00:00.000000000 +0000 +++ python3.6-3.6.9/debian/patches/CVE-2019-18348.patch 2020-04-18 01:55:24.000000000 +0000 @@ -0,0 +1,100 @@ +From 83fc70159b24f5b11a5ef87c9b05c2cf4c7faeba Mon Sep 17 00:00:00 2001 +From: "Miss Islington (bot)" + <31488909+miss-islington@users.noreply.github.com> +Date: Sat, 14 Mar 2020 15:35:52 -0700 +Subject: [PATCH] bpo-38576: Disallow control characters in hostnames in + http.client (GH-18995) (GH-19002) + +Add host validation for control characters for more CVE-2019-18348 protection. +(cherry picked from commit 9165addc22d05e776a54319a8531ebd0b2fe01ef) + +Co-authored-by: Ashwin Ramaswami +diff --git a/Lib/http/client.py b/Lib/http/client.py +index 1a6bd8a..cb1e15e 100644 +--- a/Lib/http/client.py ++++ b/Lib/http/client.py +@@ -858,6 +858,8 @@ class HTTPConnection: + + (self.host, self.port) = self._get_hostport(host, port) + ++ self._validate_host(self.host) ++ + # This is stored as an instance variable to allow unit + # tests to replace it with a suitable mockup + self._create_connection = socket.create_connection +@@ -1207,6 +1209,14 @@ class HTTPConnection: + # For HTTP/1.0, the server will assume "not chunked" + pass + ++ def _validate_host(self, host): ++ """Validate a host so it doesn't contain control characters.""" ++ # Prevent CVE-2019-18348. ++ match = _contains_disallowed_url_pchar_re.search(host) ++ if match: ++ raise InvalidURL(f"URL can't contain control characters. {host!r} " ++ f"(found at least {match.group()!r})") ++ + def putheader(self, header, *values): + """Send a request header line to the server. + +diff --git a/Lib/test/test_urllib.py b/Lib/test/test_urllib.py +index 0061a52..ddf425f 100644 +--- a/Lib/test/test_urllib.py ++++ b/Lib/test/test_urllib.py +@@ -331,7 +331,7 @@ class urlopen_HttpTests(unittest.TestCase, FakeHTTPMixin, FakeFTPMixin): + self.unfakehttp() + + @unittest.skipUnless(ssl, "ssl module required") +- def test_url_with_control_char_rejected(self): ++ def test_url_path_with_control_char_rejected(self): + for char_no in list(range(0, 0x21)) + [0x7f]: + char = chr(char_no) + schemeless_url = f"//localhost:7777/test{char}/" +@@ -358,7 +358,7 @@ class urlopen_HttpTests(unittest.TestCase, FakeHTTPMixin, FakeFTPMixin): + self.unfakehttp() + + @unittest.skipUnless(ssl, "ssl module required") +- def test_url_with_newline_header_injection_rejected(self): ++ def test_url_path_with_newline_header_injection_rejected(self): + self.fakehttp(b"HTTP/1.1 200 OK\r\n\r\nHello.") + host = "localhost:7777?a=1 HTTP/1.1\r\nX-injected: header\r\nTEST: 123" + schemeless_url = "//" + host + ":8080/test/?test=a" +@@ -383,6 +383,38 @@ class urlopen_HttpTests(unittest.TestCase, FakeHTTPMixin, FakeFTPMixin): + finally: + self.unfakehttp() + ++ @unittest.skipUnless(ssl, "ssl module required") ++ def test_url_host_with_control_char_rejected(self): ++ for char_no in list(range(0, 0x21)) + [0x7f]: ++ char = chr(char_no) ++ schemeless_url = f"//localhost{char}/test/" ++ self.fakehttp(b"HTTP/1.1 200 OK\r\n\r\nHello.") ++ try: ++ escaped_char_repr = repr(char).replace('\\', r'\\') ++ InvalidURL = http.client.InvalidURL ++ with self.assertRaisesRegex( ++ InvalidURL, f"contain control.*{escaped_char_repr}"): ++ urlopen(f"http:{schemeless_url}") ++ with self.assertRaisesRegex(InvalidURL, f"contain control.*{escaped_char_repr}"): ++ urlopen(f"https:{schemeless_url}") ++ finally: ++ self.unfakehttp() ++ ++ @unittest.skipUnless(ssl, "ssl module required") ++ def test_url_host_with_newline_header_injection_rejected(self): ++ self.fakehttp(b"HTTP/1.1 200 OK\r\n\r\nHello.") ++ host = "localhost\r\nX-injected: header\r\n" ++ schemeless_url = "//" + host + ":8080/test/?test=a" ++ try: ++ InvalidURL = http.client.InvalidURL ++ with self.assertRaisesRegex( ++ InvalidURL, r"contain control.*\\r"): ++ urlopen(f"http:{schemeless_url}") ++ with self.assertRaisesRegex(InvalidURL, r"contain control.*\\n"): ++ urlopen(f"https:{schemeless_url}") ++ finally: ++ self.unfakehttp() ++ + def test_read_0_9(self): + # "0.9" response accepted (but not "simple responses" without + # a status line) diff -Nru python3.6-3.6.8/debian/patches/CVE-2019-5010.patch python3.6-3.6.9/debian/patches/CVE-2019-5010.patch --- python3.6-3.6.8/debian/patches/CVE-2019-5010.patch 2019-08-20 17:11:49.000000000 +0000 +++ python3.6-3.6.9/debian/patches/CVE-2019-5010.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,108 +0,0 @@ -From 216a4d83c3b72f4fdcd81b588dc3f42cc461739a Mon Sep 17 00:00:00 2001 -From: "Miss Islington (bot)" - <31488909+miss-islington@users.noreply.github.com> -Date: Tue, 15 Jan 2019 17:16:36 -0800 -Subject: [PATCH] bpo-35746: Fix segfault in ssl's cert parser (GH-11569) - (GH-11573) - -Fix a NULL pointer deref in ssl module. The cert parser did not handle CRL -distribution points with empty DP or URI correctly. A malicious or buggy -certificate can result into segfault. - -Signed-off-by: Christian Heimes - -https://bugs.python.org/issue35746 -(cherry picked from commit a37f52436f9aa4b9292878b72f3ff1480e2606c3) - -Co-authored-by: Christian Heimes ---- - Lib/test/talos-2019-0758.pem | 22 +++++++++++++++++++ - Lib/test/test_ssl.py | 22 +++++++++++++++++++ - .../2019-01-15-18-16-05.bpo-35746.nMSd0j.rst | 3 +++ - Modules/_ssl.c | 4 ++++ - 4 files changed, 51 insertions(+) - create mode 100644 Lib/test/talos-2019-0758.pem - create mode 100644 Misc/NEWS.d/next/Security/2019-01-15-18-16-05.bpo-35746.nMSd0j.rst - -Index: python3.6-3.6.8/Lib/test/talos-2019-0758.pem -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ python3.6-3.6.8/Lib/test/talos-2019-0758.pem 2019-07-10 07:48:58.975692529 -0400 -@@ -0,0 +1,22 @@ -+-----BEGIN CERTIFICATE----- -+MIIDqDCCApKgAwIBAgIBAjALBgkqhkiG9w0BAQswHzELMAkGA1UEBhMCVUsxEDAO -+BgNVBAMTB2NvZHktY2EwHhcNMTgwNjE4MTgwMDU4WhcNMjgwNjE0MTgwMDU4WjA7 -+MQswCQYDVQQGEwJVSzEsMCoGA1UEAxMjY29kZW5vbWljb24tdm0tMi50ZXN0Lmxh -+bC5jaXNjby5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC63fGB -+J80A9Av1GB0bptslKRIUtJm8EeEu34HkDWbL6AJY0P8WfDtlXjlPaLqFa6sqH6ES -+V48prSm1ZUbDSVL8R6BYVYpOlK8/48xk4pGTgRzv69gf5SGtQLwHy8UPBKgjSZoD -+5a5k5wJXGswhKFFNqyyxqCvWmMnJWxXTt2XDCiWc4g4YAWi4O4+6SeeHVAV9rV7C -+1wxqjzKovVe2uZOHjKEzJbbIU6JBPb6TRfMdRdYOw98n1VXDcKVgdX2DuuqjCzHP -+WhU4Tw050M9NaK3eXp4Mh69VuiKoBGOLSOcS8reqHIU46Reg0hqeL8LIL6OhFHIF -+j7HR6V1X6F+BfRS/AgMBAAGjgdYwgdMwCQYDVR0TBAIwADAdBgNVHQ4EFgQUOktp -+HQjxDXXUg8prleY9jeLKeQ4wTwYDVR0jBEgwRoAUx6zgPygZ0ZErF9sPC4+5e2Io -+UU+hI6QhMB8xCzAJBgNVBAYTAlVLMRAwDgYDVQQDEwdjb2R5LWNhggkA1QEAuwb7 -+2s0wCQYDVR0SBAIwADAuBgNVHREEJzAlgiNjb2Rlbm9taWNvbi12bS0yLnRlc3Qu -+bGFsLmNpc2NvLmNvbTAOBgNVHQ8BAf8EBAMCBaAwCwYDVR0fBAQwAjAAMAsGCSqG -+SIb3DQEBCwOCAQEAvqantx2yBlM11RoFiCfi+AfSblXPdrIrHvccepV4pYc/yO6p -+t1f2dxHQb8rWH3i6cWag/EgIZx+HJQvo0rgPY1BFJsX1WnYf1/znZpkUBGbVmlJr -+t/dW1gSkNS6sPsM0Q+7HPgEv8CPDNK5eo7vU2seE0iWOkxSyVUuiCEY9ZVGaLVit -+p0C78nZ35Pdv4I+1cosmHl28+es1WI22rrnmdBpH8J1eY6WvUw2xuZHLeNVN0TzV -+Q3qq53AaCWuLOD1AjESWuUCxMZTK9DPS4JKXTK8RLyDeqOvJGjsSWp3kL0y3GaQ+ -+10T1rfkKJub2+m9A9duin1fn6tHc2wSvB7m3DA== -+-----END CERTIFICATE----- -Index: python3.6-3.6.8/Lib/test/test_ssl.py -=================================================================== ---- python3.6-3.6.8.orig/Lib/test/test_ssl.py 2019-07-10 07:48:58.987692562 -0400 -+++ python3.6-3.6.8/Lib/test/test_ssl.py 2019-07-10 07:48:58.975692529 -0400 -@@ -79,6 +79,7 @@ NONEXISTINGCERT = data_file("XXXnonexist - BADKEY = data_file("badkey.pem") - NOKIACERT = data_file("nokia.pem") - NULLBYTECERT = data_file("nullbytecert.pem") -+TALOS_INVALID_CRLDP = data_file("talos-2019-0758.pem") - - DHFILE = data_file("ffdh3072.pem") - BYTES_DHFILE = os.fsencode(DHFILE) -@@ -293,6 +294,27 @@ class BasicSocketTests(unittest.TestCase - self.assertEqual(p['crlDistributionPoints'], - ('http://SVRIntl-G3-crl.verisign.com/SVRIntlG3.crl',)) - -+ def test_parse_cert_CVE_2019_5010(self): -+ p = ssl._ssl._test_decode_cert(TALOS_INVALID_CRLDP) -+ if support.verbose: -+ sys.stdout.write("\n" + pprint.pformat(p) + "\n") -+ self.assertEqual( -+ p, -+ { -+ 'issuer': ( -+ (('countryName', 'UK'),), (('commonName', 'cody-ca'),)), -+ 'notAfter': 'Jun 14 18:00:58 2028 GMT', -+ 'notBefore': 'Jun 18 18:00:58 2018 GMT', -+ 'serialNumber': '02', -+ 'subject': ((('countryName', 'UK'),), -+ (('commonName', -+ 'codenomicon-vm-2.test.lal.cisco.com'),)), -+ 'subjectAltName': ( -+ ('DNS', 'codenomicon-vm-2.test.lal.cisco.com'),), -+ 'version': 3 -+ } -+ ) -+ - def test_parse_cert_CVE_2013_4238(self): - p = ssl._ssl._test_decode_cert(NULLBYTECERT) - if support.verbose: -Index: python3.6-3.6.8/Modules/_ssl.c -=================================================================== ---- python3.6-3.6.8.orig/Modules/_ssl.c 2019-07-10 07:48:58.987692562 -0400 -+++ python3.6-3.6.8/Modules/_ssl.c 2019-07-10 07:48:58.979692540 -0400 -@@ -1338,6 +1338,10 @@ _get_crl_dp(X509 *certificate) { - STACK_OF(GENERAL_NAME) *gns; - - dp = sk_DIST_POINT_value(dps, i); -+ if (dp->distpoint == NULL) { -+ /* Ignore empty DP value, CVE-2019-5010 */ -+ continue; -+ } - gns = dp->distpoint->name.fullname; - - for (j=0; j < sk_GENERAL_NAME_num(gns); j++) { diff -Nru python3.6-3.6.8/debian/patches/CVE-2019-9636.patch python3.6-3.6.9/debian/patches/CVE-2019-9636.patch --- python3.6-3.6.8/debian/patches/CVE-2019-9636.patch 2019-08-20 17:11:57.000000000 +0000 +++ python3.6-3.6.9/debian/patches/CVE-2019-9636.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,141 +0,0 @@ -From 23fc0416454c4ad5b9b23d520fbe6d89be3efc24 Mon Sep 17 00:00:00 2001 -From: Steve Dower -Date: Mon, 11 Mar 2019 21:34:03 -0700 -Subject: [PATCH] [3.6] bpo-36216: Add check for characters in netloc that - normalize to separators (GH-12201) (GH-12215) - ---- - Doc/library/urllib.parse.rst | 18 +++++++++++++++ - Lib/test/test_urlparse.py | 23 +++++++++++++++++++ - Lib/urllib/parse.py | 17 ++++++++++++++ - .../2019-03-06-09-38-40.bpo-36216.6q1m4a.rst | 3 +++ - 4 files changed, 61 insertions(+) - create mode 100644 Misc/NEWS.d/next/Security/2019-03-06-09-38-40.bpo-36216.6q1m4a.rst - -Index: python3.6-3.6.8/Doc/library/urllib.parse.rst -=================================================================== ---- python3.6-3.6.8.orig/Doc/library/urllib.parse.rst 2019-07-10 07:49:06.243712682 -0400 -+++ python3.6-3.6.8/Doc/library/urllib.parse.rst 2019-07-10 07:49:06.235712659 -0400 -@@ -121,6 +121,11 @@ or on combining URL components into a UR - Unmatched square brackets in the :attr:`netloc` attribute will raise a - :exc:`ValueError`. - -+ Characters in the :attr:`netloc` attribute that decompose under NFKC -+ normalization (as used by the IDNA encoding) into any of ``/``, ``?``, -+ ``#``, ``@``, or ``:`` will raise a :exc:`ValueError`. If the URL is -+ decomposed before parsing, no error will be raised. -+ - .. versionchanged:: 3.2 - Added IPv6 URL parsing capabilities. - -@@ -133,6 +138,10 @@ or on combining URL components into a UR - Out-of-range port numbers now raise :exc:`ValueError`, instead of - returning :const:`None`. - -+ .. versionchanged:: 3.6.9 -+ Characters that affect netloc parsing under NFKC normalization will -+ now raise :exc:`ValueError`. -+ - - .. function:: parse_qs(qs, keep_blank_values=False, strict_parsing=False, encoding='utf-8', errors='replace', max_num_fields=None) - -@@ -256,10 +265,19 @@ or on combining URL components into a UR - Unmatched square brackets in the :attr:`netloc` attribute will raise a - :exc:`ValueError`. - -+ Characters in the :attr:`netloc` attribute that decompose under NFKC -+ normalization (as used by the IDNA encoding) into any of ``/``, ``?``, -+ ``#``, ``@``, or ``:`` will raise a :exc:`ValueError`. If the URL is -+ decomposed before parsing, no error will be raised. -+ - .. versionchanged:: 3.6 - Out-of-range port numbers now raise :exc:`ValueError`, instead of - returning :const:`None`. - -+ .. versionchanged:: 3.6.9 -+ Characters that affect netloc parsing under NFKC normalization will -+ now raise :exc:`ValueError`. -+ - - .. function:: urlunsplit(parts) - -Index: python3.6-3.6.8/Lib/test/test_urlparse.py -=================================================================== ---- python3.6-3.6.8.orig/Lib/test/test_urlparse.py 2019-07-10 07:49:06.243712682 -0400 -+++ python3.6-3.6.8/Lib/test/test_urlparse.py 2019-07-10 07:49:06.239712671 -0400 -@@ -1,3 +1,5 @@ -+import sys -+import unicodedata - import unittest - import urllib.parse - -@@ -984,6 +986,27 @@ class UrlParseTestCase(unittest.TestCase - expected.append(name) - self.assertCountEqual(urllib.parse.__all__, expected) - -+ def test_urlsplit_normalization(self): -+ # Certain characters should never occur in the netloc, -+ # including under normalization. -+ # Ensure that ALL of them are detected and cause an error -+ illegal_chars = '/:#?@' -+ hex_chars = {'{:04X}'.format(ord(c)) for c in illegal_chars} -+ denorm_chars = [ -+ c for c in map(chr, range(128, sys.maxunicode)) -+ if (hex_chars & set(unicodedata.decomposition(c).split())) -+ and c not in illegal_chars -+ ] -+ # Sanity check that we found at least one such character -+ self.assertIn('\u2100', denorm_chars) -+ self.assertIn('\uFF03', denorm_chars) -+ -+ for scheme in ["http", "https", "ftp"]: -+ for c in denorm_chars: -+ url = "{}://netloc{}false.netloc/path".format(scheme, c) -+ with self.subTest(url=url, char='{:04X}'.format(ord(c))): -+ with self.assertRaises(ValueError): -+ urllib.parse.urlsplit(url) - - class Utility_Tests(unittest.TestCase): - """Testcase to test the various utility functions in the urllib.""" -Index: python3.6-3.6.8/Lib/urllib/parse.py -=================================================================== ---- python3.6-3.6.8.orig/Lib/urllib/parse.py 2019-07-10 07:49:06.243712682 -0400 -+++ python3.6-3.6.8/Lib/urllib/parse.py 2019-07-10 07:49:06.239712671 -0400 -@@ -391,6 +391,21 @@ def _splitnetloc(url, start=0): - delim = min(delim, wdelim) # use earliest delim position - return url[start:delim], url[delim:] # return (domain, rest) - -+def _checknetloc(netloc): -+ if not netloc or not any(ord(c) > 127 for c in netloc): -+ return -+ # looking for characters like \u2100 that expand to 'a/c' -+ # IDNA uses NFKC equivalence, so normalize for this check -+ import unicodedata -+ netloc2 = unicodedata.normalize('NFKC', netloc) -+ if netloc == netloc2: -+ return -+ _, _, netloc = netloc.rpartition('@') # anything to the left of '@' is okay -+ for c in '/?#@:': -+ if c in netloc2: -+ raise ValueError("netloc '" + netloc2 + "' contains invalid " + -+ "characters under NFKC normalization") -+ - def urlsplit(url, scheme='', allow_fragments=True): - """Parse a URL into 5 components: - :///?# -@@ -420,6 +435,7 @@ def urlsplit(url, scheme='', allow_fragm - url, fragment = url.split('#', 1) - if '?' in url: - url, query = url.split('?', 1) -+ _checknetloc(netloc) - v = SplitResult(scheme, netloc, url, query, fragment) - _parse_cache[key] = v - return _coerce_result(v) -@@ -443,6 +459,7 @@ def urlsplit(url, scheme='', allow_fragm - url, fragment = url.split('#', 1) - if '?' in url: - url, query = url.split('?', 1) -+ _checknetloc(netloc) - v = SplitResult(scheme, netloc, url, query, fragment) - _parse_cache[key] = v - return _coerce_result(v) diff -Nru python3.6-3.6.8/debian/patches/CVE-2020-8492.patch python3.6-3.6.9/debian/patches/CVE-2020-8492.patch --- python3.6-3.6.8/debian/patches/CVE-2020-8492.patch 1970-01-01 00:00:00.000000000 +0000 +++ python3.6-3.6.9/debian/patches/CVE-2020-8492.patch 2020-04-18 01:56:04.000000000 +0000 @@ -0,0 +1,40 @@ +Backported of: + +From: Victor Stinner +Date: Fri, 3 Apr 2020 03:15:56 +0200 +Subject: [PATCH] bpo-39503: CVE-2020-8492: Fix AbstractBasicAuthHandler + (GH-18284) (GH-19304) + +The AbstractBasicAuthHandler class of the urllib.request module uses +an inefficient regular expression which can be exploited by an +attacker to cause a denial of service. Fix the regex to prevent the +catastrophic backtracking. Vulnerability reported by Ben Caller +and Matt Schwager. + +AbstractBasicAuthHandler of urllib.request now parses all +WWW-Authenticate HTTP headers and accepts multiple challenges per +header: use the realm of the first Basic challenge. + +Co-Authored-By: Serhiy Storchaka +Index: python3.6-3.6.9/Lib/urllib/request.py +=================================================================== +--- python3.6-3.6.9.orig/Lib/urllib/request.py ++++ python3.6-3.6.9/Lib/urllib/request.py +@@ -945,8 +945,15 @@ class AbstractBasicAuthHandler: + + # allow for double- and single-quoted realm values + # (single quotes are a violation of the RFC, but appear in the wild) +- rx = re.compile('(?:.*,)*[ \t]*([^ \t]+)[ \t]+' +- 'realm=(["\']?)([^"\']*)\\2', re.I) ++ rx = re.compile('(?:^|,)' # start of the string or ',' ++ '[ \t]*' # optional whitespaces ++ '([^ \t]+)' # scheme like "Basic" ++ '[ \t]+' # mandatory whitespaces ++ # realm=xxx ++ # realm='xxx' ++ # realm="xxx" ++ 'realm=(["\']?)([^"\']*)\\2', ++ re.I) + + # XXX could pre-emptively send auth info already accepted (RFC 2617, + # end of section 2, and section 1.2 immediately after "credentials" diff -Nru python3.6-3.6.8/debian/patches/platform-lsbrelease.diff python3.6-3.6.9/debian/patches/platform-lsbrelease.diff --- python3.6-3.6.8/debian/patches/platform-lsbrelease.diff 2018-12-12 06:16:32.000000000 +0000 +++ python3.6-3.6.9/debian/patches/platform-lsbrelease.diff 2019-03-26 14:24:23.000000000 +0000 @@ -15,9 +15,9 @@ id = l[1] return '', version, id -+_distributor_id_file_re = re.compile("(?:DISTRIB_ID\s*=)\s*(.*)", re.I) -+_release_file_re = re.compile("(?:DISTRIB_RELEASE\s*=)\s*(.*)", re.I) -+_codename_file_re = re.compile("(?:DISTRIB_CODENAME\s*=)\s*(.*)", re.I) ++_distributor_id_file_re = re.compile(r"(?:DISTRIB_ID\s*=)\s*(.*)", re.I) ++_release_file_re = re.compile(r"(?:DISTRIB_RELEASE\s*=)\s*(.*)", re.I) ++_codename_file_re = re.compile(r"(?:DISTRIB_CODENAME\s*=)\s*(.*)", re.I) + def linux_distribution(distname='', version='', id='', diff -Nru python3.6-3.6.8/debian/patches/series python3.6-3.6.9/debian/patches/series --- python3.6-3.6.8/debian/patches/series 2019-10-07 12:59:46.000000000 +0000 +++ python3.6-3.6.9/debian/patches/series 2020-04-18 01:56:04.000000000 +0000 @@ -37,12 +37,8 @@ doc-build-texinfo.diff riscv64.diff build-math-object.diff -CVE-2018-20852.patch -CVE-2019-5010.patch -CVE-2019-9636.patch -CVE-2019-9740.patch -CVE-2019-9948.patch -CVE-2019-10160-1.patch -CVE-2019-10160-2.patch +arm-alignment.diff CVE-2019-16056.patch CVE-2019-16935.patch +CVE-2019-18348.patch +CVE-2020-8492.patch diff -Nru python3.6-3.6.8/debian/rules python3.6-3.6.9/debian/rules --- python3.6-3.6.8/debian/rules 2018-08-20 16:17:05.000000000 +0000 +++ python3.6-3.6.9/debian/rules 2019-11-07 10:44:02.000000000 +0000 @@ -188,7 +188,7 @@ endif endif -ifneq (,$(findstring $(DEB_HOST_ARCH), amd64 armel armhf i386 powerpc ppc64 ppc64el s390x)) +ifneq (,$(findstring $(DEB_HOST_ARCH), amd64 armel armhf arm64 i386 powerpc ppc64 ppc64el s390x)) with_lto := yes endif diff -Nru python3.6-3.6.8/Doc/c-api/exceptions.rst python3.6-3.6.9/Doc/c-api/exceptions.rst --- python3.6-3.6.8/Doc/c-api/exceptions.rst 2018-12-23 21:37:14.000000000 +0000 +++ python3.6-3.6.9/Doc/c-api/exceptions.rst 2019-07-02 20:25:39.000000000 +0000 @@ -53,8 +53,12 @@ .. c:function:: void PyErr_PrintEx(int set_sys_last_vars) Print a standard traceback to ``sys.stderr`` and clear the error indicator. - Call this function only when the error indicator is set. (Otherwise it will - cause a fatal error!) + **Unless** the error is a ``SystemExit``. In that case the no traceback + is printed and Python process will exit with the error code specified by + the ``SystemExit`` instance. + + Call this function **only** when the error indicator is set. Otherwise it + will cause a fatal error! If *set_sys_last_vars* is nonzero, the variables :data:`sys.last_type`, :data:`sys.last_value` and :data:`sys.last_traceback` will be set to the diff -Nru python3.6-3.6.8/Doc/conf.py python3.6-3.6.9/Doc/conf.py --- python3.6-3.6.8/Doc/conf.py 2018-12-23 21:37:14.000000000 +0000 +++ python3.6-3.6.9/Doc/conf.py 2019-07-02 20:25:39.000000000 +0000 @@ -40,6 +40,8 @@ venvdir = os.getenv('VENVDIR', 'venv') exclude_patterns = [venvdir+'/*', 'README.rst'] +# Avoid a warning with Sphinx >= 2.0 +master_doc = 'contents' # Options for HTML output # ----------------------- diff -Nru python3.6-3.6.8/Doc/copyright.rst python3.6-3.6.9/Doc/copyright.rst --- python3.6-3.6.8/Doc/copyright.rst 2018-12-23 21:37:14.000000000 +0000 +++ python3.6-3.6.9/Doc/copyright.rst 2019-07-02 20:25:39.000000000 +0000 @@ -4,7 +4,7 @@ Python and this documentation is: -Copyright © 2001-2018 Python Software Foundation. All rights reserved. +Copyright © 2001-2019 Python Software Foundation. All rights reserved. Copyright © 2000 BeOpen.com. All rights reserved. diff -Nru python3.6-3.6.8/Doc/library/concurrent.futures.rst python3.6-3.6.9/Doc/library/concurrent.futures.rst --- python3.6-3.6.8/Doc/library/concurrent.futures.rst 2018-12-23 21:37:14.000000000 +0000 +++ python3.6-3.6.9/Doc/library/concurrent.futures.rst 2019-07-02 20:25:39.000000000 +0000 @@ -137,12 +137,6 @@ An :class:`Executor` subclass that uses a pool of at most *max_workers* threads to execute calls asynchronously. - *initializer* is an optional callable that is called at the start of - each worker thread; *initargs* is a tuple of arguments passed to the - initializer. Should *initializer* raise an exception, all currently - pending jobs will raise a :exc:`~concurrent.futures.thread.BrokenThreadPool`, - as well any attempt to submit more jobs to the pool. - .. versionchanged:: 3.5 If *max_workers* is ``None`` or not given, it will default to the number of processors on the machine, diff -Nru python3.6-3.6.8/Doc/library/email.compat32-message.rst python3.6-3.6.9/Doc/library/email.compat32-message.rst --- python3.6-3.6.8/Doc/library/email.compat32-message.rst 2018-12-23 21:37:14.000000000 +0000 +++ python3.6-3.6.9/Doc/library/email.compat32-message.rst 2019-07-02 20:25:39.000000000 +0000 @@ -6,6 +6,7 @@ .. module:: email.message :synopsis: The base class representing email messages in a fashion backward compatible with python3.2 + :noindex: The :class:`Message` class is very similar to the diff -Nru python3.6-3.6.8/Doc/library/importlib.rst python3.6-3.6.9/Doc/library/importlib.rst --- python3.6-3.6.8/Doc/library/importlib.rst 2018-12-23 21:37:14.000000000 +0000 +++ python3.6-3.6.9/Doc/library/importlib.rst 2019-07-02 20:25:39.000000000 +0000 @@ -1488,7 +1488,8 @@ if spec is not None: break else: - raise ImportError(f'No module named {absolute_name!r}') + msg = f'No module named {absolute_name!r}' + raise ModuleNotFoundError(msg, name=absolute_name) module = importlib.util.module_from_spec(spec) spec.loader.exec_module(module) sys.modules[absolute_name] = module diff -Nru python3.6-3.6.8/Doc/library/nntplib.rst python3.6-3.6.9/Doc/library/nntplib.rst --- python3.6-3.6.8/Doc/library/nntplib.rst 2018-12-23 21:37:14.000000000 +0000 +++ python3.6-3.6.9/Doc/library/nntplib.rst 2019-07-02 20:25:39.000000000 +0000 @@ -232,10 +232,10 @@ .. versionadded:: 3.2 -.. method:: NNTP.starttls(ssl_context=None) +.. method:: NNTP.starttls(context=None) Send a ``STARTTLS`` command. This will enable encryption on the NNTP - connection. The *ssl_context* argument is optional and should be a + connection. The *context* argument is optional and should be a :class:`ssl.SSLContext` object. Please read :ref:`ssl-security` for best practices. diff -Nru python3.6-3.6.8/Doc/library/urllib.parse.rst python3.6-3.6.9/Doc/library/urllib.parse.rst --- python3.6-3.6.8/Doc/library/urllib.parse.rst 2018-12-23 21:37:14.000000000 +0000 +++ python3.6-3.6.9/Doc/library/urllib.parse.rst 2019-07-02 20:25:39.000000000 +0000 @@ -121,6 +121,11 @@ Unmatched square brackets in the :attr:`netloc` attribute will raise a :exc:`ValueError`. + Characters in the :attr:`netloc` attribute that decompose under NFKC + normalization (as used by the IDNA encoding) into any of ``/``, ``?``, + ``#``, ``@``, or ``:`` will raise a :exc:`ValueError`. If the URL is + decomposed before parsing, no error will be raised. + .. versionchanged:: 3.2 Added IPv6 URL parsing capabilities. @@ -133,6 +138,10 @@ Out-of-range port numbers now raise :exc:`ValueError`, instead of returning :const:`None`. + .. versionchanged:: 3.6.9 + Characters that affect netloc parsing under NFKC normalization will + now raise :exc:`ValueError`. + .. function:: parse_qs(qs, keep_blank_values=False, strict_parsing=False, encoding='utf-8', errors='replace', max_num_fields=None) @@ -256,10 +265,19 @@ Unmatched square brackets in the :attr:`netloc` attribute will raise a :exc:`ValueError`. + Characters in the :attr:`netloc` attribute that decompose under NFKC + normalization (as used by the IDNA encoding) into any of ``/``, ``?``, + ``#``, ``@``, or ``:`` will raise a :exc:`ValueError`. If the URL is + decomposed before parsing, no error will be raised. + .. versionchanged:: 3.6 Out-of-range port numbers now raise :exc:`ValueError`, instead of returning :const:`None`. + .. versionchanged:: 3.6.9 + Characters that affect netloc parsing under NFKC normalization will + now raise :exc:`ValueError`. + .. function:: urlunsplit(parts) diff -Nru python3.6-3.6.8/Doc/license.rst python3.6-3.6.9/Doc/license.rst --- python3.6-3.6.8/Doc/license.rst 2018-12-23 21:37:14.000000000 +0000 +++ python3.6-3.6.9/Doc/license.rst 2019-07-02 20:25:39.000000000 +0000 @@ -87,7 +87,7 @@ analyze, test, perform and/or display publicly, prepare derivative works, distribute, and otherwise use Python |release| alone or in any derivative version, provided, however, that PSF's License Agreement and PSF's notice of - copyright, i.e., "Copyright © 2001-2018 Python Software Foundation; All Rights + copyright, i.e., "Copyright © 2001-2019 Python Software Foundation; All Rights Reserved" are retained in Python |release| alone or in any derivative version prepared by Licensee. diff -Nru python3.6-3.6.8/Doc/README.rst python3.6-3.6.9/Doc/README.rst --- python3.6-3.6.8/Doc/README.rst 2018-12-23 21:37:14.000000000 +0000 +++ python3.6-3.6.9/Doc/README.rst 2019-07-02 20:25:39.000000000 +0000 @@ -113,6 +113,15 @@ where ```` is one of html, text, latex, or htmlhelp (for explanations see the make targets above). +Deprecation header +================== + +You can define the ``outdated`` variable in ``html_context`` to show a +red banner on each page redirecting to the "latest" version. + +The link points to the same page on ``/3/``, sadly for the moment the +language is lost during the process. + Contributing ============ diff -Nru python3.6-3.6.8/Doc/tools/extensions/escape4chm.py python3.6-3.6.9/Doc/tools/extensions/escape4chm.py --- python3.6-3.6.8/Doc/tools/extensions/escape4chm.py 2018-12-23 21:37:14.000000000 +0000 +++ python3.6-3.6.9/Doc/tools/extensions/escape4chm.py 2019-07-02 20:25:39.000000000 +0000 @@ -8,7 +8,10 @@ import re from html.entities import codepoint2name -from sphinx.util.logging import getLogger +try: # sphinx>=1.6 + from sphinx.util.logging import getLogger +except ImportError: # sphinx<1.6 + from logging import getLogger # escape the characters which codepoint > 0x7F def _process(string): diff -Nru python3.6-3.6.8/Doc/tools/extensions/pyspecific.py python3.6-3.6.9/Doc/tools/extensions/pyspecific.py --- python3.6-3.6.8/Doc/tools/extensions/pyspecific.py 2018-12-23 21:37:14.000000000 +0000 +++ python3.6-3.6.9/Doc/tools/extensions/pyspecific.py 2019-07-02 20:25:39.000000000 +0000 @@ -23,7 +23,6 @@ from sphinx import addnodes from sphinx.builders import Builder from sphinx.locale import translators -from sphinx.util import status_iterator from sphinx.util.nodes import split_explicit_title from sphinx.writers.html import HTMLTranslator from sphinx.writers.text import TextWriter, TextTranslator @@ -314,6 +313,11 @@ return '' # no URIs def write(self, *ignored): + try: # sphinx>=1.6 + from sphinx.util import status_iterator + except ImportError: # sphinx<1.6 + status_iterator = self.status_iterator + writer = TextWriter(self) for label in status_iterator(pydoc_topic_labels, 'building topics... ', diff -Nru python3.6-3.6.8/Doc/tools/extensions/suspicious.py python3.6-3.6.9/Doc/tools/extensions/suspicious.py --- python3.6-3.6.8/Doc/tools/extensions/suspicious.py 2018-12-23 21:37:14.000000000 +0000 +++ python3.6-3.6.9/Doc/tools/extensions/suspicious.py 2019-07-02 20:25:39.000000000 +0000 @@ -48,6 +48,7 @@ from docutils import nodes from sphinx.builders import Builder +import sphinx.util detect_all = re.compile(r''' ::(?=[^=])| # two :: (but NOT ::=) @@ -85,6 +86,7 @@ Checks for possibly invalid markup that may leak into the output. """ name = 'suspicious' + logger = sphinx.util.logging.getLogger("CheckSuspiciousMarkupBuilder") def init(self): # create output file @@ -116,7 +118,7 @@ self.warn('Found %s/%s unused rules:' % (len(unused_rules), len(self.rules))) for rule in unused_rules: - self.info(repr(rule)) + self.logger.info(repr(rule)) return def check_issue(self, line, lineno, issue): @@ -146,7 +148,7 @@ return False def report_issue(self, text, lineno, issue): - if not self.any_issue: self.info() + if not self.any_issue: self.logger.info() self.any_issue = True self.write_log_entry(lineno, issue, text) if py3: @@ -181,7 +183,7 @@ A csv file, with exactly the same format as suspicious.csv Fields: document name (normalized), line number, issue, surrounding text """ - self.info("loading ignore rules... ", nonl=1) + self.logger.info("loading ignore rules... ", nonl=1) self.rules = rules = [] try: if py3: @@ -206,7 +208,7 @@ rule = Rule(docname, lineno, issue, text) rules.append(rule) f.close() - self.info('done, %d rules loaded' % len(self.rules)) + self.logger.info('done, %d rules loaded' % len(self.rules)) def get_lineno(node): diff -Nru python3.6-3.6.8/Doc/tools/static/switchers.js python3.6-3.6.9/Doc/tools/static/switchers.js --- python3.6-3.6.8/Doc/tools/static/switchers.js 2018-12-23 21:37:14.000000000 +0000 +++ python3.6-3.6.9/Doc/tools/static/switchers.js 2019-07-02 20:25:39.000000000 +0000 @@ -10,7 +10,8 @@ '(?:release/\\d.\\d[\\x\\d\\.]*)']; var all_versions = { - '3.8': 'dev (3.8)', + '3.9': 'dev (3.9)', + '3.8': 'pre (3.8)', '3.7': '3.7', '3.6': '3.6', '3.5': '3.5', diff -Nru python3.6-3.6.8/Doc/tools/templates/indexsidebar.html python3.6-3.6.9/Doc/tools/templates/indexsidebar.html --- python3.6-3.6.8/Doc/tools/templates/indexsidebar.html 2018-12-23 21:37:14.000000000 +0000 +++ python3.6-3.6.9/Doc/tools/templates/indexsidebar.html 2019-07-02 20:25:39.000000000 +0000 @@ -2,9 +2,10 @@

{% trans %}Download these documents{% endtrans %}

{% trans %}Docs by version{% endtrans %}

    -
  • {% trans %}Python 3.8 (in development){% endtrans %}
  • +
  • {% trans %}Python 3.9 (in development){% endtrans %}
  • +
  • {% trans %}Python 3.8 (pre-release){% endtrans %}
  • {% trans %}Python 3.7 (stable){% endtrans %}
  • -
  • {% trans %}Python 3.6 (stable){% endtrans %}
  • +
  • {% trans %}Python 3.6 (security-fixes){% endtrans %}
  • {% trans %}Python 3.5 (security-fixes){% endtrans %}
  • {% trans %}Python 2.7 (stable){% endtrans %}
  • {% trans %}All versions{% endtrans %}
  • diff -Nru python3.6-3.6.8/Doc/tools/templates/layout.html python3.6-3.6.9/Doc/tools/templates/layout.html --- python3.6-3.6.8/Doc/tools/templates/layout.html 2018-12-23 21:37:14.000000000 +0000 +++ python3.6-3.6.9/Doc/tools/templates/layout.html 2019-07-02 20:25:39.000000000 +0000 @@ -1,4 +1,15 @@ {% extends "!layout.html" %} + +{% block header %} +{%- if outdated %} +
    + {% trans %}This document is for an old version of Python that is no longer supported. + You should upgrade, and read the {% endtrans %} + {% trans %} Python documentation for the current stable release{% endtrans %}. +
    +{%- endif %} +{% endblock %} + {% block rootrellink %}
  • diff -Nru python3.6-3.6.8/Doc/whatsnew/3.6.rst python3.6-3.6.9/Doc/whatsnew/3.6.rst --- python3.6-3.6.8/Doc/whatsnew/3.6.rst 2018-12-23 21:37:14.000000000 +0000 +++ python3.6-3.6.9/Doc/whatsnew/3.6.rst 2019-07-02 20:25:39.000000000 +0000 @@ -2328,6 +2328,17 @@ a :exc:`DeprecationWarning` in Python 3.6 and a :exc:`RuntimeError` in Python 3.8. +* With the introduction of :exc:`ModuleNotFoundError`, import system consumers + may start expecting import system replacements to raise that more specific + exception when appropriate, rather than the less-specific :exc:`ImportError`. + To provide future compatibility with such consumers, implementors of + alternative import systems that completely replace :func:`__import__` will + need to update their implementations to raise the new subclass when a module + can't be found at all. Implementors of compliant plugins to the default + import system shouldn't need to make any changes, as the default import + system will raise the new subclass when appropriate. + + Changes in the C API -------------------- diff -Nru python3.6-3.6.8/Include/patchlevel.h python3.6-3.6.9/Include/patchlevel.h --- python3.6-3.6.8/Include/patchlevel.h 2018-12-23 21:37:14.000000000 +0000 +++ python3.6-3.6.9/Include/patchlevel.h 2019-07-02 20:25:39.000000000 +0000 @@ -18,12 +18,12 @@ /*--start constants--*/ #define PY_MAJOR_VERSION 3 #define PY_MINOR_VERSION 6 -#define PY_MICRO_VERSION 8 +#define PY_MICRO_VERSION 9 #define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_FINAL #define PY_RELEASE_SERIAL 0 /* Version as a string */ -#define PY_VERSION "3.6.8" +#define PY_VERSION "3.6.9" /*--end constants--*/ /* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2. diff -Nru python3.6-3.6.8/Lib/email/_header_value_parser.py python3.6-3.6.9/Lib/email/_header_value_parser.py --- python3.6-3.6.8/Lib/email/_header_value_parser.py 2018-12-23 21:37:14.000000000 +0000 +++ python3.6-3.6.9/Lib/email/_header_value_parser.py 2019-07-02 20:25:39.000000000 +0000 @@ -2725,16 +2725,19 @@ lines.append(' ') # XXX We'll get an infinite loop here if maxlen is <= 7 continue - first_part = to_encode[:text_space] - ew = _ew.encode(first_part, charset=encode_as) - excess = len(ew) - remaining_space - if excess > 0: - # encode always chooses the shortest encoding, so this - # is guaranteed to fit at this point. - first_part = first_part[:-excess] - ew = _ew.encode(first_part) - lines[-1] += ew - to_encode = to_encode[len(first_part):] + + to_encode_word = to_encode[:text_space] + encoded_word = _ew.encode(to_encode_word, charset=encode_as) + excess = len(encoded_word) - remaining_space + while excess > 0: + # Since the chunk to encode is guaranteed to fit into less than 100 characters, + # shrinking it by one at a time shouldn't take long. + to_encode_word = to_encode_word[:-1] + encoded_word = _ew.encode(to_encode_word, charset=encode_as) + excess = len(encoded_word) - remaining_space + lines[-1] += encoded_word + to_encode = to_encode[len(to_encode_word):] + if to_encode: lines.append(' ') new_last_ew = len(lines[-1]) diff -Nru python3.6-3.6.8/Lib/http/client.py python3.6-3.6.9/Lib/http/client.py --- python3.6-3.6.8/Lib/http/client.py 2018-12-23 21:37:14.000000000 +0000 +++ python3.6-3.6.9/Lib/http/client.py 2019-07-02 20:25:39.000000000 +0000 @@ -141,6 +141,16 @@ _is_legal_header_name = re.compile(rb'[^:\s][^:\r\n]*').fullmatch _is_illegal_header_value = re.compile(rb'\n(?![ \t])|\r(?![ \t\n])').search +# These characters are not allowed within HTTP URL paths. +# See https://tools.ietf.org/html/rfc3986#section-3.3 and the +# https://tools.ietf.org/html/rfc3986#appendix-A pchar definition. +# Prevents CVE-2019-9740. Includes control characters such as \r\n. +# We don't restrict chars above \x7f as putrequest() limits us to ASCII. +_contains_disallowed_url_pchar_re = re.compile('[\x00-\x20\x7f]') +# Arguably only these _should_ allowed: +# _is_allowed_url_pchars_re = re.compile(r"^[/!$&'()*+,;=:@%a-zA-Z0-9._~-]+$") +# We are more lenient for assumed real world compatibility purposes. + # We always set the Content-Length header for these methods because some # servers will otherwise respond with a 411 _METHODS_EXPECTING_BODY = {'PATCH', 'POST', 'PUT'} @@ -1111,6 +1121,11 @@ self._method = method if not url: url = '/' + # Prevent CVE-2019-9740. + match = _contains_disallowed_url_pchar_re.search(url) + if match: + raise InvalidURL(f"URL can't contain control characters. {url!r} " + f"(found at least {match.group()!r})") request = '%s %s %s' % (method, url, self._http_vsn_str) # Non-ASCII characters should have been eliminated earlier diff -Nru python3.6-3.6.8/Lib/http/cookiejar.py python3.6-3.6.9/Lib/http/cookiejar.py --- python3.6-3.6.8/Lib/http/cookiejar.py 2018-12-23 21:37:14.000000000 +0000 +++ python3.6-3.6.9/Lib/http/cookiejar.py 2019-07-02 20:25:39.000000000 +0000 @@ -993,7 +993,7 @@ req_path = request_path(request) if ((cookie.version > 0 or (cookie.version == 0 and self.strict_ns_set_path)) and - not req_path.startswith(cookie.path)): + not self.path_return_ok(cookie.path, request)): _debug(" path attribute %s is not a prefix of request " "path %s", cookie.path, req_path) return False @@ -1148,6 +1148,11 @@ req_host, erhn = eff_request_host(request) domain = cookie.domain + if domain and not domain.startswith("."): + dotdomain = "." + domain + else: + dotdomain = domain + # strict check of non-domain cookies: Mozilla does this, MSIE5 doesn't if (cookie.version == 0 and (self.strict_ns_domain & self.DomainStrictNonDomain) and @@ -1160,7 +1165,7 @@ _debug(" effective request-host name %s does not domain-match " "RFC 2965 cookie domain %s", erhn, domain) return False - if cookie.version == 0 and not ("."+erhn).endswith(domain): + if cookie.version == 0 and not ("."+erhn).endswith(dotdomain): _debug(" request-host %s does not match Netscape cookie domain " "%s", req_host, domain) return False @@ -1174,7 +1179,11 @@ req_host = "."+req_host if not erhn.startswith("."): erhn = "."+erhn - if not (req_host.endswith(domain) or erhn.endswith(domain)): + if domain and not domain.startswith("."): + dotdomain = "." + domain + else: + dotdomain = domain + if not (req_host.endswith(dotdomain) or erhn.endswith(dotdomain)): #_debug(" request domain %s does not match cookie domain %s", # req_host, domain) return False @@ -1191,11 +1200,15 @@ def path_return_ok(self, path, request): _debug("- checking cookie path=%s", path) req_path = request_path(request) - if not req_path.startswith(path): - _debug(" %s does not path-match %s", req_path, path) - return False - return True + pathlen = len(path) + if req_path == path: + return True + elif (req_path.startswith(path) and + (path.endswith("/") or req_path[pathlen:pathlen+1] == "/")): + return True + _debug(" %s does not path-match %s", req_path, path) + return False def vals_sorted_by_key(adict): keys = sorted(adict.keys()) diff -Nru python3.6-3.6.8/Lib/pydoc_data/topics.py python3.6-3.6.9/Lib/pydoc_data/topics.py --- python3.6-3.6.8/Lib/pydoc_data/topics.py 2018-12-23 21:37:14.000000000 +0000 +++ python3.6-3.6.9/Lib/pydoc_data/topics.py 2019-07-02 20:25:39.000000000 +0000 @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Autogenerated by Sphinx on Sun Dec 23 16:24:21 2018 +# Autogenerated by Sphinx on Tue Jun 18 20:31:29 2019 topics = {'assert': 'The "assert" statement\n' '**********************\n' '\n' @@ -4862,7 +4862,7 @@ 'Meaning ' '|\n' ' ' - '+===========+============================================================+\n' + '|===========|============================================================|\n' ' | "\'<\'" | Forces the field to be left-aligned ' 'within the available |\n' ' | | space (this is the default for most ' @@ -4911,7 +4911,7 @@ 'Meaning ' '|\n' ' ' - '+===========+============================================================+\n' + '|===========|============================================================|\n' ' | "\'+\'" | indicates that a sign should be used for ' 'both positive as |\n' ' | | well as negative ' @@ -5015,7 +5015,7 @@ 'Meaning ' '|\n' ' ' - '+===========+============================================================+\n' + '|===========|============================================================|\n' ' | "\'s\'" | String format. This is the default type ' 'for strings and |\n' ' | | may be ' @@ -5035,7 +5035,7 @@ 'Meaning ' '|\n' ' ' - '+===========+============================================================+\n' + '|===========|============================================================|\n' ' | "\'b\'" | Binary format. Outputs the number in ' 'base 2. |\n' ' ' @@ -5097,7 +5097,7 @@ 'Meaning ' '|\n' ' ' - '+===========+============================================================+\n' + '|===========|============================================================|\n' ' | "\'e\'" | Exponent notation. Prints the number in ' 'scientific |\n' ' | | notation using the letter ‘e’ to indicate ' @@ -6777,7 +6777,7 @@ '+-------------------------------------------------+---------------------------------------+\n' '| Operator | ' 'Description |\n' - '+=================================================+=======================================+\n' + '|=================================================|=======================================|\n' '| "lambda" | ' 'Lambda expression |\n' '+-------------------------------------------------+---------------------------------------+\n' @@ -9911,7 +9911,7 @@ ' | Representation | ' 'Description |\n' ' ' - '+=========================+===============================+\n' + '|=========================|===============================|\n' ' | "\\n" | Line ' 'Feed |\n' ' ' @@ -10252,7 +10252,7 @@ '+-------------------+-----------------------------------+---------+\n' '| Escape Sequence | Meaning | Notes ' '|\n' - '+===================+===================================+=========+\n' + '|===================|===================================|=========|\n' '| "\\newline" | Backslash and newline ignored ' '| |\n' '+-------------------+-----------------------------------+---------+\n' @@ -10298,7 +10298,7 @@ '+-------------------+-----------------------------------+---------+\n' '| Escape Sequence | Meaning | Notes ' '|\n' - '+===================+===================================+=========+\n' + '|===================|===================================|=========|\n' '| "\\N{name}" | Character named *name* in the | ' '(4) |\n' '| | Unicode database | ' @@ -10929,7 +10929,7 @@ ' | Attribute | Meaning ' '| |\n' ' ' - '+===========================+=================================+=============+\n' + '|===========================|=================================|=============|\n' ' | "__doc__" | The function’s documentation ' '| Writable |\n' ' | | string, or "None" if ' @@ -12110,7 +12110,7 @@ '+----------------------------+----------------------------------+------------+\n' '| Operation | Result ' '| Notes |\n' - '+============================+==================================+============+\n' + '|============================|==================================|============|\n' '| "x in s" | "True" if an item of *s* is ' '| (1) |\n' '| | equal to *x*, else "False" ' @@ -12339,7 +12339,7 @@ '+--------------------------------+----------------------------------+-----------------------+\n' '| Operation | ' 'Result | Notes |\n' - '+================================+==================================+=======================+\n' + '|================================|==================================|=======================|\n' '| "s[i] = x" | item *i* of *s* is replaced ' 'by | |\n' '| | ' @@ -12793,7 +12793,7 @@ '| Operation | ' 'Result | Notes ' '|\n' - '+================================+==================================+=======================+\n' + '|================================|==================================|=======================|\n' '| "s[i] = x" | item *i* of *s* is ' 'replaced by | |\n' '| | ' diff -Nru python3.6-3.6.8/Lib/test/libregrtest/setup.py python3.6-3.6.9/Lib/test/libregrtest/setup.py --- python3.6-3.6.8/Lib/test/libregrtest/setup.py 2018-12-23 21:37:14.000000000 +0000 +++ python3.6-3.6.9/Lib/test/libregrtest/setup.py 2019-07-02 20:25:39.000000000 +0000 @@ -60,22 +60,6 @@ if getattr(module, '__file__', None): module.__file__ = os.path.abspath(module.__file__) - # MacOSX (a.k.a. Darwin) has a default stack size that is too small - # for deeply recursive regular expressions. We see this as crashes in - # the Python test suite when running test_re.py and test_sre.py. The - # fix is to set the stack limit to 2048. - # This approach may also be useful for other Unixy platforms that - # suffer from small default stack limits. - if sys.platform == 'darwin': - try: - import resource - except ImportError: - pass - else: - soft, hard = resource.getrlimit(resource.RLIMIT_STACK) - newsoft = min(hard, max(soft, 1024*2048)) - resource.setrlimit(resource.RLIMIT_STACK, (newsoft, hard)) - if ns.huntrleaks: unittest.BaseTestSuite._cleanup = False diff -Nru python3.6-3.6.8/Lib/test/selfsigned_pythontestdotnet.pem python3.6-3.6.9/Lib/test/selfsigned_pythontestdotnet.pem --- python3.6-3.6.8/Lib/test/selfsigned_pythontestdotnet.pem 2018-12-23 21:37:14.000000000 +0000 +++ python3.6-3.6.9/Lib/test/selfsigned_pythontestdotnet.pem 2019-07-02 20:25:39.000000000 +0000 @@ -1,16 +1,34 @@ -----BEGIN CERTIFICATE----- -MIIClTCCAf6gAwIBAgIJAKGU95wKR8pTMA0GCSqGSIb3DQEBBQUAMHAxCzAJBgNV -BAYTAlhZMRcwFQYDVQQHDA5DYXN0bGUgQW50aHJheDEjMCEGA1UECgwaUHl0aG9u -IFNvZnR3YXJlIEZvdW5kYXRpb24xIzAhBgNVBAMMGnNlbGYtc2lnbmVkLnB5dGhv -bnRlc3QubmV0MB4XDTE0MTEwMjE4MDkyOVoXDTI0MTAzMDE4MDkyOVowcDELMAkG -A1UEBhMCWFkxFzAVBgNVBAcMDkNhc3RsZSBBbnRocmF4MSMwIQYDVQQKDBpQeXRo -b24gU29mdHdhcmUgRm91bmRhdGlvbjEjMCEGA1UEAwwac2VsZi1zaWduZWQucHl0 -aG9udGVzdC5uZXQwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANDXQXW9tjyZ -Xt0Iv2tLL1+jinr4wGg36ioLDLFkMf+2Y1GL0v0BnKYG4N1OKlAU15LXGeGer8vm -Sv/yIvmdrELvhAbbo3w4a9TMYQA4XkIVLdvu3mvNOAet+8PMJxn26dbDhG809ALv -EHY57lQsBS3G59RZyBPVqAqmImWNJnVzAgMBAAGjNzA1MCUGA1UdEQQeMByCGnNl -bGYtc2lnbmVkLnB5dGhvbnRlc3QubmV0MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcN -AQEFBQADgYEAIuzAhgMouJpNdf3URCHIineyoSt6WK/9+eyUcjlKOrDoXNZaD72h -TXMeKYoWvJyVcSLKL8ckPtDobgP2OTt0UkyAaj0n+ZHaqq1lH2yVfGUA1ILJv515 -C8BqbvVZuqm3i7ygmw3bqE/lYMgOrYtXXnqOrz6nvsE6Yc9V9rFflOM= +MIIF9zCCA9+gAwIBAgIUH98b4Fw/DyugC9cV7VK7ZODzHsIwDQYJKoZIhvcNAQEL +BQAwgYoxCzAJBgNVBAYTAlhZMRcwFQYDVQQIDA5DYXN0bGUgQW50aHJheDEYMBYG +A1UEBwwPQXJndW1lbnQgQ2xpbmljMSMwIQYDVQQKDBpQeXRob24gU29mdHdhcmUg +Rm91bmRhdGlvbjEjMCEGA1UEAwwac2VsZi1zaWduZWQucHl0aG9udGVzdC5uZXQw +HhcNMTkwNTA4MDEwMjQzWhcNMjcwNzI0MDEwMjQzWjCBijELMAkGA1UEBhMCWFkx +FzAVBgNVBAgMDkNhc3RsZSBBbnRocmF4MRgwFgYDVQQHDA9Bcmd1bWVudCBDbGlu +aWMxIzAhBgNVBAoMGlB5dGhvbiBTb2Z0d2FyZSBGb3VuZGF0aW9uMSMwIQYDVQQD +DBpzZWxmLXNpZ25lZC5weXRob250ZXN0Lm5ldDCCAiIwDQYJKoZIhvcNAQEBBQAD +ggIPADCCAgoCggIBAMKdJlyCThkahwoBb7pl5q64Pe9Fn5jrIvzsveHTc97TpjV2 +RLfICnXKrltPk/ohkVl6K5SUZQZwMVzFubkyxE0nZPHYHlpiKWQxbsYVkYv01rix +IFdLvaxxbGYke2jwQao31s4o61AdlsfK1SdpHQUynBBMssqI3SB4XPmcA7e+wEEx +jxjVish4ixA1vuIZOx8yibu+CFCf/geEjoBMF3QPdzULzlrCSw8k/45iZCSoNbvK +DoL4TVV07PHOxpheDh8ZQmepGvU6pVqhb9m4lgmV0OGWHgozd5Ur9CbTVDmxIEz3 +TSoRtNJK7qtyZdGNqwjksQxgZTjM/d/Lm/BJG99AiOmYOjsl9gbQMZgvQmMAtUsI +aMJnQuZ6R+KEpW/TR5qSKLWZSG45z/op+tzI2m+cE6HwTRVAWbcuJxcAA55MZjqU +OOOu3BBYMjS5nf2sQ9uoXsVBFH7i0mQqoW1SLzr9opI8KsWwFxQmO2vBxWYaN+lH +OmwBZBwyODIsmI1YGXmTp09NxRYz3Qe5GCgFzYowpMrcxUC24iduIdMwwhRM7rKg +7GtIWMSrFfuI1XCLRmSlhDbhNN6fVg2f8Bo9PdH9ihiIyxSrc+FOUasUYCCJvlSZ +8hFUlLvcmrZlWuazohm0lsXuMK1JflmQr/DA/uXxP9xzFfRy+RU3jDyxJbRHAgMB +AAGjUzBRMB0GA1UdDgQWBBSQJyxiPMRK01i+0BsV9zUwDiBaHzAfBgNVHSMEGDAW +gBSQJyxiPMRK01i+0BsV9zUwDiBaHzAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3 +DQEBCwUAA4ICAQCR+7a7N/m+WLkxPPIA/CB4MOr2Uf8ixTv435Nyv6rXOun0+lTP +ExSZ0uYQ+L0WylItI3cQHULldDueD+s8TGzxf5woaLKf6tqyr0NYhKs+UeNEzDnN +9PHQIhX0SZw3XyXGUgPNBfRCg2ZDdtMMdOU4XlQN/IN/9hbYTrueyY7eXq9hmtI9 +1srftAMqr9SR1JP7aHI6DVgrEsZVMTDnfT8WmLSGLlY1HmGfdEn1Ip5sbo9uSkiH +AEPgPfjYIvR5LqTOMn4KsrlZyBbFIDh9Sl99M1kZzgH6zUGVLCDg1y6Cms69fx/e +W1HoIeVkY4b4TY7Bk7JsqyNhIuqu7ARaxkdaZWhYaA2YyknwANdFfNpfH+elCLIk +BUt5S3f4i7DaUePTvKukCZiCq4Oyln7RcOn5If73wCeLB/ZM9Ei1HforyLWP1CN8 +XLfpHaoeoPSWIveI0XHUl65LsPN2UbMbul/F23hwl+h8+BLmyAS680Yhn4zEN6Ku +B7Po90HoFa1Du3bmx4jsN73UkT/dwMTi6K072FbipnC1904oGlWmLwvAHvrtxxmL +Pl3pvEaZIu8wa/PNF6Y7J7VIewikIJq6Ta6FrWeFfzMWOj2qA1ZZi6fUaDSNYvuV +J5quYKCc/O+I/yDDf8wyBbZ/gvUXzUHTMYGG+bFrn1p7XDbYYeEJ6R/xEg== -----END CERTIFICATE----- diff -Nru python3.6-3.6.8/Lib/test/talos-2019-0758.pem python3.6-3.6.9/Lib/test/talos-2019-0758.pem --- python3.6-3.6.8/Lib/test/talos-2019-0758.pem 1970-01-01 00:00:00.000000000 +0000 +++ python3.6-3.6.9/Lib/test/talos-2019-0758.pem 2019-07-02 20:25:39.000000000 +0000 @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDqDCCApKgAwIBAgIBAjALBgkqhkiG9w0BAQswHzELMAkGA1UEBhMCVUsxEDAO +BgNVBAMTB2NvZHktY2EwHhcNMTgwNjE4MTgwMDU4WhcNMjgwNjE0MTgwMDU4WjA7 +MQswCQYDVQQGEwJVSzEsMCoGA1UEAxMjY29kZW5vbWljb24tdm0tMi50ZXN0Lmxh +bC5jaXNjby5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC63fGB +J80A9Av1GB0bptslKRIUtJm8EeEu34HkDWbL6AJY0P8WfDtlXjlPaLqFa6sqH6ES +V48prSm1ZUbDSVL8R6BYVYpOlK8/48xk4pGTgRzv69gf5SGtQLwHy8UPBKgjSZoD +5a5k5wJXGswhKFFNqyyxqCvWmMnJWxXTt2XDCiWc4g4YAWi4O4+6SeeHVAV9rV7C +1wxqjzKovVe2uZOHjKEzJbbIU6JBPb6TRfMdRdYOw98n1VXDcKVgdX2DuuqjCzHP +WhU4Tw050M9NaK3eXp4Mh69VuiKoBGOLSOcS8reqHIU46Reg0hqeL8LIL6OhFHIF +j7HR6V1X6F+BfRS/AgMBAAGjgdYwgdMwCQYDVR0TBAIwADAdBgNVHQ4EFgQUOktp +HQjxDXXUg8prleY9jeLKeQ4wTwYDVR0jBEgwRoAUx6zgPygZ0ZErF9sPC4+5e2Io +UU+hI6QhMB8xCzAJBgNVBAYTAlVLMRAwDgYDVQQDEwdjb2R5LWNhggkA1QEAuwb7 +2s0wCQYDVR0SBAIwADAuBgNVHREEJzAlgiNjb2Rlbm9taWNvbi12bS0yLnRlc3Qu +bGFsLmNpc2NvLmNvbTAOBgNVHQ8BAf8EBAMCBaAwCwYDVR0fBAQwAjAAMAsGCSqG +SIb3DQEBCwOCAQEAvqantx2yBlM11RoFiCfi+AfSblXPdrIrHvccepV4pYc/yO6p +t1f2dxHQb8rWH3i6cWag/EgIZx+HJQvo0rgPY1BFJsX1WnYf1/znZpkUBGbVmlJr +t/dW1gSkNS6sPsM0Q+7HPgEv8CPDNK5eo7vU2seE0iWOkxSyVUuiCEY9ZVGaLVit +p0C78nZ35Pdv4I+1cosmHl28+es1WI22rrnmdBpH8J1eY6WvUw2xuZHLeNVN0TzV +Q3qq53AaCWuLOD1AjESWuUCxMZTK9DPS4JKXTK8RLyDeqOvJGjsSWp3kL0y3GaQ+ +10T1rfkKJub2+m9A9duin1fn6tHc2wSvB7m3DA== +-----END CERTIFICATE----- diff -Nru python3.6-3.6.8/Lib/test/test_asyncio/test_events.py python3.6-3.6.9/Lib/test/test_asyncio/test_events.py --- python3.6-3.6.8/Lib/test/test_asyncio/test_events.py 2018-12-23 21:37:14.000000000 +0000 +++ python3.6-3.6.9/Lib/test/test_asyncio/test_events.py 2019-07-02 20:25:39.000000000 +0000 @@ -557,6 +557,7 @@ self.loop.add_signal_handler(signal.SIGALRM, my_handler) signal.setitimer(signal.ITIMER_REAL, 0.01, 0) # Send SIGALRM once. + self.loop.call_later(60, self.loop.stop) self.loop.run_forever() self.assertEqual(caught, 1) @@ -569,11 +570,12 @@ nonlocal caught caught += 1 self.assertEqual(args, some_args) + self.loop.stop() self.loop.add_signal_handler(signal.SIGALRM, my_handler, *some_args) signal.setitimer(signal.ITIMER_REAL, 0.1, 0) # Send SIGALRM once. - self.loop.call_later(0.5, self.loop.stop) + self.loop.call_later(60, self.loop.stop) self.loop.run_forever() self.assertEqual(caught, 1) diff -Nru python3.6-3.6.8/Lib/test/test_email/test_headerregistry.py python3.6-3.6.9/Lib/test/test_email/test_headerregistry.py --- python3.6-3.6.8/Lib/test/test_email/test_headerregistry.py 2018-12-23 21:37:14.000000000 +0000 +++ python3.6-3.6.9/Lib/test/test_email/test_headerregistry.py 2019-07-02 20:25:39.000000000 +0000 @@ -1643,10 +1643,10 @@ self.assertEqual( h.fold(policy=policy.default), 'X-Report-Abuse: =?utf-8?q?=3Chttps=3A//www=2Emailitapp=2E' - 'com/report=5F?=\n' - ' =?utf-8?q?abuse=2Ephp=3Fmid=3Dxxx-xxx-xxxx' - 'xxxxxxxxxxxxxxxxxxxx=3D=3D-xxx-?=\n' - ' =?utf-8?q?xx-xx=3E?=\n') + 'com/report=5Fabuse?=\n' + ' =?utf-8?q?=2Ephp=3Fmid=3Dxxx-xxx-xxxx' + 'xxxxxxxxxxxxxxxxxxxx=3D=3D-xxx-xx-xx?=\n' + ' =?utf-8?q?=3E?=\n') if __name__ == '__main__': diff -Nru python3.6-3.6.8/Lib/test/test_email/test_policy.py python3.6-3.6.9/Lib/test/test_email/test_policy.py --- python3.6-3.6.8/Lib/test/test_email/test_policy.py 2018-12-23 21:37:14.000000000 +0000 +++ python3.6-3.6.9/Lib/test/test_email/test_policy.py 2019-07-02 20:25:39.000000000 +0000 @@ -237,6 +237,14 @@ email.policy.EmailPolicy.header_factory) self.assertEqual(newpolicy.__dict__, {'raise_on_defect': True}) + def test_non_ascii_chars_do_not_cause_inf_loop(self): + policy = email.policy.default.clone(max_line_length=20) + actual = policy.fold('Subject', 'ą' * 12) + self.assertEqual( + actual, + 'Subject: \n' + + 12 * ' =?utf-8?q?=C4=85?=\n') + # XXX: Need subclassing tests. # For adding subclassed objects, make sure the usual rules apply (subclass # wins), but that the order still works (right overrides left). diff -Nru python3.6-3.6.8/Lib/test/test_http_cookiejar.py python3.6-3.6.9/Lib/test/test_http_cookiejar.py --- python3.6-3.6.8/Lib/test/test_http_cookiejar.py 2018-12-23 21:37:14.000000000 +0000 +++ python3.6-3.6.9/Lib/test/test_http_cookiejar.py 2019-07-02 20:25:39.000000000 +0000 @@ -415,6 +415,7 @@ ("http://foo.bar.com/", ".foo.bar.com", True), ("http://foo.bar.com/", "foo.bar.com", True), ("http://foo.bar.com/", ".bar.com", True), + ("http://foo.bar.com/", "bar.com", True), ("http://foo.bar.com/", "com", True), ("http://foo.com/", "rhubarb.foo.com", False), ("http://foo.com/", ".foo.com", True), @@ -425,6 +426,8 @@ ("http://foo/", "foo", True), ("http://foo/", "foo.local", True), ("http://foo/", ".local", True), + ("http://barfoo.com", ".foo.com", False), + ("http://barfoo.com", "foo.com", False), ]: request = urllib.request.Request(url) r = pol.domain_return_ok(domain, request) @@ -692,6 +695,30 @@ req = urllib.request.Request("http://www.example.com") self.assertEqual(request_path(req), "/") + def test_path_prefix_match(self): + pol = DefaultCookiePolicy() + strict_ns_path_pol = DefaultCookiePolicy(strict_ns_set_path=True) + + c = CookieJar(pol) + base_url = "http://bar.com" + interact_netscape(c, base_url, 'spam=eggs; Path=/foo') + cookie = c._cookies['bar.com']['/foo']['spam'] + + for path, ok in [('/foo', True), + ('/foo/', True), + ('/foo/bar', True), + ('/', False), + ('/foobad/foo', False)]: + url = f'{base_url}{path}' + req = urllib.request.Request(url) + h = interact_netscape(c, url) + if ok: + self.assertIn('spam=eggs', h, f"cookie not set for {path}") + self.assertTrue(strict_ns_path_pol.set_ok_path(cookie, req)) + else: + self.assertNotIn('spam=eggs', h, f"cookie set for {path}") + self.assertFalse(strict_ns_path_pol.set_ok_path(cookie, req)) + def test_request_port(self): req = urllib.request.Request("http://www.acme.com:1234/", headers={"Host": "www.acme.com:4321"}) @@ -959,6 +986,33 @@ c.add_cookie_header(req) self.assertFalse(req.has_header("Cookie")) + c.clear() + + pol.set_blocked_domains([]) + req = urllib.request.Request("http://acme.com/") + res = FakeResponse(headers, "http://acme.com/") + cookies = c.make_cookies(res, req) + c.extract_cookies(res, req) + self.assertEqual(len(c), 1) + + req = urllib.request.Request("http://acme.com/") + c.add_cookie_header(req) + self.assertTrue(req.has_header("Cookie")) + + req = urllib.request.Request("http://badacme.com/") + c.add_cookie_header(req) + self.assertFalse(pol.return_ok(cookies[0], req)) + self.assertFalse(req.has_header("Cookie")) + + p = pol.set_blocked_domains(["acme.com"]) + req = urllib.request.Request("http://acme.com/") + c.add_cookie_header(req) + self.assertFalse(req.has_header("Cookie")) + + req = urllib.request.Request("http://badacme.com/") + c.add_cookie_header(req) + self.assertFalse(req.has_header("Cookie")) + def test_secure(self): for ns in True, False: for whitespace in " ", "": diff -Nru python3.6-3.6.8/Lib/test/test_nntplib.py python3.6-3.6.9/Lib/test/test_nntplib.py --- python3.6-3.6.8/Lib/test/test_nntplib.py 2018-12-23 21:37:14.000000000 +0000 +++ python3.6-3.6.9/Lib/test/test_nntplib.py 2019-07-02 20:25:39.000000000 +0000 @@ -6,6 +6,8 @@ import functools import contextlib import os.path +import re + from test import support from nntplib import NNTP, GroupInfo import nntplib @@ -22,6 +24,13 @@ TIMEOUT = 30 certfile = os.path.join(os.path.dirname(__file__), 'keycert3.pem') +if ssl is not None: + SSLError = ssl.SSLError +else: + class SSLError(Exception): + """Non-existent exception class when we lack SSL support.""" + reason = "This will never be raised." + # TODO: # - test the `file` arg to more commands # - test error conditions @@ -262,14 +271,21 @@ return False return True - with self.NNTP_CLASS(self.NNTP_HOST, timeout=TIMEOUT, usenetrc=False) as server: - self.assertTrue(is_connected()) - self.assertTrue(server.help()) - self.assertFalse(is_connected()) - - with self.NNTP_CLASS(self.NNTP_HOST, timeout=TIMEOUT, usenetrc=False) as server: - server.quit() - self.assertFalse(is_connected()) + try: + with self.NNTP_CLASS(self.NNTP_HOST, timeout=TIMEOUT, usenetrc=False) as server: + self.assertTrue(is_connected()) + self.assertTrue(server.help()) + self.assertFalse(is_connected()) + + with self.NNTP_CLASS(self.NNTP_HOST, timeout=TIMEOUT, usenetrc=False) as server: + server.quit() + self.assertFalse(is_connected()) + except SSLError as ssl_err: + # matches "[SSL: DH_KEY_TOO_SMALL] dh key too small" + if re.search(r'(?i)KEY.TOO.SMALL', ssl_err.reason): + raise unittest.SkipTest(f"Got {ssl_err} connecting " + f"to {self.NNTP_HOST!r}") + raise NetworkedNNTPTestsMixin.wrap_methods() @@ -290,6 +306,12 @@ try: cls.server = cls.NNTP_CLASS(cls.NNTP_HOST, timeout=TIMEOUT, usenetrc=False) + except SSLError as ssl_err: + # matches "[SSL: DH_KEY_TOO_SMALL] dh key too small" + if re.search(r'(?i)KEY.TOO.SMALL', ssl_err.reason): + raise unittest.SkipTest(f"{cls} got {ssl_err} connecting " + f"to {cls.NNTP_HOST!r}") + raise except EOFError: raise unittest.SkipTest(f"{cls} got EOF error on connecting " f"to {cls.NNTP_HOST!r}") diff -Nru python3.6-3.6.8/Lib/test/test_socket.py python3.6-3.6.9/Lib/test/test_socket.py --- python3.6-3.6.8/Lib/test/test_socket.py 2018-12-23 21:37:14.000000000 +0000 +++ python3.6-3.6.9/Lib/test/test_socket.py 2019-07-02 20:25:39.000000000 +0000 @@ -5363,11 +5363,10 @@ def _testWithTimeoutTriggeredSend(self): address = self.serv.getsockname() - file = open(support.TESTFN, 'rb') - with socket.create_connection(address, timeout=0.01) as sock, \ - file as file: - meth = self.meth_from_sock(sock) - self.assertRaises(socket.timeout, meth, file) + with open(support.TESTFN, 'rb') as file: + with socket.create_connection(address, timeout=0.01) as sock: + meth = self.meth_from_sock(sock) + self.assertRaises(socket.timeout, meth, file) def testWithTimeoutTriggeredSend(self): conn = self.accept_conn() diff -Nru python3.6-3.6.8/Lib/test/test_ssl.py python3.6-3.6.9/Lib/test/test_ssl.py --- python3.6-3.6.8/Lib/test/test_ssl.py 2018-12-23 21:37:14.000000000 +0000 +++ python3.6-3.6.9/Lib/test/test_ssl.py 2019-07-02 20:25:39.000000000 +0000 @@ -17,6 +17,7 @@ import asyncore import weakref import platform +import re import functools try: import ctypes @@ -79,6 +80,7 @@ BADKEY = data_file("badkey.pem") NOKIACERT = data_file("nokia.pem") NULLBYTECERT = data_file("nullbytecert.pem") +TALOS_INVALID_CRLDP = data_file("talos-2019-0758.pem") DHFILE = data_file("ffdh3072.pem") BYTES_DHFILE = os.fsencode(DHFILE) @@ -144,6 +146,38 @@ else: return func +def skip_if_openssl_cnf_minprotocol_gt_tls1(func): + """Skip a test if the OpenSSL config MinProtocol is > TLSv1. + + OS distros with an /etc/ssl/openssl.cnf and MinProtocol set often do so to + require TLSv1.2 or higher (Debian Buster). Some of our tests for older + protocol versions will fail under such a config. + + Alternative workaround: Run this test in a process with + OPENSSL_CONF=/dev/null in the environment. + """ + @functools.wraps(func) + def f(*args, **kwargs): + openssl_cnf = os.environ.get("OPENSSL_CONF", "/etc/ssl/openssl.cnf") + try: + with open(openssl_cnf, "r") as config: + for line in config: + match = re.match(r"MinProtocol\s*=\s*(TLSv\d+\S*)", line) + if match: + tls_ver = match.group(1) + if tls_ver > "TLSv1": + raise unittest.SkipTest( + "%s has MinProtocol = %s which is > TLSv1." % + (openssl_cnf, tls_ver)) + except (EnvironmentError, UnicodeDecodeError) as err: + # no config file found, etc. + if support.verbose: + sys.stdout.write("\n Could not scan %s for MinProtocol: %s\n" + % (openssl_cnf, err)) + return func(*args, **kwargs) + return f + + needs_sni = unittest.skipUnless(ssl.HAS_SNI, "SNI support needed for this test") @@ -293,6 +327,27 @@ self.assertEqual(p['crlDistributionPoints'], ('http://SVRIntl-G3-crl.verisign.com/SVRIntlG3.crl',)) + def test_parse_cert_CVE_2019_5010(self): + p = ssl._ssl._test_decode_cert(TALOS_INVALID_CRLDP) + if support.verbose: + sys.stdout.write("\n" + pprint.pformat(p) + "\n") + self.assertEqual( + p, + { + 'issuer': ( + (('countryName', 'UK'),), (('commonName', 'cody-ca'),)), + 'notAfter': 'Jun 14 18:00:58 2028 GMT', + 'notBefore': 'Jun 18 18:00:58 2018 GMT', + 'serialNumber': '02', + 'subject': ((('countryName', 'UK'),), + (('commonName', + 'codenomicon-vm-2.test.lal.cisco.com'),)), + 'subjectAltName': ( + ('DNS', 'codenomicon-vm-2.test.lal.cisco.com'),), + 'version': 3 + } + ) + def test_parse_cert_CVE_2013_4238(self): p = ssl._ssl._test_decode_cert(NULLBYTECERT) if support.verbose: @@ -2007,6 +2062,16 @@ sys.stdout.write(" server: read %r (%s), sending back %r (%s)...\n" % (msg, ctype, msg.lower(), ctype)) self.write(msg.lower()) + except ConnectionResetError: + # XXX: OpenSSL 1.1.1 sometimes raises ConnectionResetError + # when connection is not shut down gracefully. + if self.server.chatty and support.verbose: + sys.stdout.write( + " Connection reset by peer: {}\n".format( + self.addr) + ) + self.close() + self.running = False except OSError: if self.server.chatty: handle_error("Test server failure:\n") @@ -2086,6 +2151,11 @@ pass except KeyboardInterrupt: self.stop() + except BaseException as e: + if support.verbose and self.chatty: + sys.stdout.write( + ' connection handling failed: ' + repr(e) + '\n') + self.sock.close() def stop(self): @@ -2592,6 +2662,7 @@ client_options=ssl.OP_NO_TLSv1) @skip_if_broken_ubuntu_ssl + @skip_if_openssl_cnf_minprotocol_gt_tls1 def test_protocol_sslv23(self): """Connecting to an SSLv23 server with various client options""" if support.verbose: @@ -2669,6 +2740,7 @@ @skip_if_broken_ubuntu_ssl @unittest.skipUnless(hasattr(ssl, "PROTOCOL_TLSv1_1"), "TLS version 1.1 not supported.") + @skip_if_openssl_cnf_minprotocol_gt_tls1 def test_protocol_tlsv1_1(self): """Connecting to a TLSv1.1 server with various client options. Testing against older TLS versions.""" diff -Nru python3.6-3.6.8/Lib/test/test_urllib.py python3.6-3.6.9/Lib/test/test_urllib.py --- python3.6-3.6.8/Lib/test/test_urllib.py 2018-12-23 21:37:14.000000000 +0000 +++ python3.6-3.6.9/Lib/test/test_urllib.py 2019-07-02 20:25:39.000000000 +0000 @@ -16,6 +16,7 @@ ssl = None import sys import tempfile +import warnings from nturl2path import url2pathname, pathname2url from base64 import b64encode @@ -329,6 +330,59 @@ finally: self.unfakehttp() + @unittest.skipUnless(ssl, "ssl module required") + def test_url_with_control_char_rejected(self): + for char_no in list(range(0, 0x21)) + [0x7f]: + char = chr(char_no) + schemeless_url = f"//localhost:7777/test{char}/" + self.fakehttp(b"HTTP/1.1 200 OK\r\n\r\nHello.") + try: + # We explicitly test urllib.request.urlopen() instead of the top + # level 'def urlopen()' function defined in this... (quite ugly) + # test suite. They use different url opening codepaths. Plain + # urlopen uses FancyURLOpener which goes via a codepath that + # calls urllib.parse.quote() on the URL which makes all of the + # above attempts at injection within the url _path_ safe. + escaped_char_repr = repr(char).replace('\\', r'\\') + InvalidURL = http.client.InvalidURL + with self.assertRaisesRegex( + InvalidURL, f"contain control.*{escaped_char_repr}"): + urllib.request.urlopen(f"http:{schemeless_url}") + with self.assertRaisesRegex( + InvalidURL, f"contain control.*{escaped_char_repr}"): + urllib.request.urlopen(f"https:{schemeless_url}") + # This code path quotes the URL so there is no injection. + resp = urlopen(f"http:{schemeless_url}") + self.assertNotIn(char, resp.geturl()) + finally: + self.unfakehttp() + + @unittest.skipUnless(ssl, "ssl module required") + def test_url_with_newline_header_injection_rejected(self): + self.fakehttp(b"HTTP/1.1 200 OK\r\n\r\nHello.") + host = "localhost:7777?a=1 HTTP/1.1\r\nX-injected: header\r\nTEST: 123" + schemeless_url = "//" + host + ":8080/test/?test=a" + try: + # We explicitly test urllib.request.urlopen() instead of the top + # level 'def urlopen()' function defined in this... (quite ugly) + # test suite. They use different url opening codepaths. Plain + # urlopen uses FancyURLOpener which goes via a codepath that + # calls urllib.parse.quote() on the URL which makes all of the + # above attempts at injection within the url _path_ safe. + InvalidURL = http.client.InvalidURL + with self.assertRaisesRegex( + InvalidURL, r"contain control.*\\r.*(found at least . .)"): + urllib.request.urlopen(f"http:{schemeless_url}") + with self.assertRaisesRegex(InvalidURL, r"contain control.*\\n"): + urllib.request.urlopen(f"https:{schemeless_url}") + # This code path quotes the URL so there is no injection. + resp = urlopen(f"http:{schemeless_url}") + self.assertNotIn(' ', resp.geturl()) + self.assertNotIn('\r', resp.geturl()) + self.assertNotIn('\n', resp.geturl()) + finally: + self.unfakehttp() + def test_read_0_9(self): # "0.9" response accepted (but not "simple responses" without # a status line) @@ -1410,6 +1464,23 @@ "spam://c:|windows%/:=&?~#+!$,;'@()*[]|/path/"), "//c:|windows%/:=&?~#+!$,;'@()*[]|/path/") + def test_local_file_open(self): + # bpo-35907, CVE-2019-9948: urllib must reject local_file:// scheme + class DummyURLopener(urllib.request.URLopener): + def open_local_file(self, url): + return url + + with warnings.catch_warnings(record=True): + warnings.simplefilter("ignore", DeprecationWarning) + + for url in ('local_file://example', 'local-file://example'): + self.assertRaises(OSError, urllib.request.urlopen, url) + self.assertRaises(OSError, urllib.request.URLopener().open, url) + self.assertRaises(OSError, urllib.request.URLopener().retrieve, url) + self.assertRaises(OSError, DummyURLopener().open, url) + self.assertRaises(OSError, DummyURLopener().retrieve, url) + + # Just commented them out. # Can't really tell why keep failing in windows and sparc. # Everywhere else they work ok, but on those machines, sometimes diff -Nru python3.6-3.6.8/Lib/test/test_urlparse.py python3.6-3.6.9/Lib/test/test_urlparse.py --- python3.6-3.6.8/Lib/test/test_urlparse.py 2018-12-23 21:37:14.000000000 +0000 +++ python3.6-3.6.9/Lib/test/test_urlparse.py 2019-07-02 20:25:39.000000000 +0000 @@ -1,3 +1,5 @@ +import sys +import unicodedata import unittest import urllib.parse @@ -984,6 +986,34 @@ expected.append(name) self.assertCountEqual(urllib.parse.__all__, expected) + def test_urlsplit_normalization(self): + # Certain characters should never occur in the netloc, + # including under normalization. + # Ensure that ALL of them are detected and cause an error + illegal_chars = '/:#?@' + hex_chars = {'{:04X}'.format(ord(c)) for c in illegal_chars} + denorm_chars = [ + c for c in map(chr, range(128, sys.maxunicode)) + if (hex_chars & set(unicodedata.decomposition(c).split())) + and c not in illegal_chars + ] + # Sanity check that we found at least one such character + self.assertIn('\u2100', denorm_chars) + self.assertIn('\uFF03', denorm_chars) + + # bpo-36742: Verify port separators are ignored when they + # existed prior to decomposition + urllib.parse.urlsplit('http://\u30d5\u309a:80') + with self.assertRaises(ValueError): + urllib.parse.urlsplit('http://\u30d5\u309a\ufe1380') + + for scheme in ["http", "https", "ftp"]: + for netloc in ["netloc{}false.netloc", "n{}user@netloc"]: + for c in denorm_chars: + url = "{}://{}/path".format(scheme, netloc.format(c)) + with self.subTest(url=url, char='{:04X}'.format(ord(c))): + with self.assertRaises(ValueError): + urllib.parse.urlsplit(url) class Utility_Tests(unittest.TestCase): """Testcase to test the various utility functions in the urllib.""" diff -Nru python3.6-3.6.8/Lib/test/test_xmlrpc.py python3.6-3.6.9/Lib/test/test_xmlrpc.py --- python3.6-3.6.8/Lib/test/test_xmlrpc.py 2018-12-23 21:37:14.000000000 +0000 +++ python3.6-3.6.9/Lib/test/test_xmlrpc.py 2019-07-02 20:25:39.000000000 +0000 @@ -950,7 +950,12 @@ def test_partial_post(self): # Check that a partial POST doesn't make the server loop: issue #14001. conn = http.client.HTTPConnection(ADDR, PORT) - conn.request('POST', '/RPC2 HTTP/1.0\r\nContent-Length: 100\r\n\r\nbye') + conn.send('POST /RPC2 HTTP/1.0\r\n' + 'Content-Length: 100\r\n\r\n' + 'bye HTTP/1.1\r\n' + f'Host: {ADDR}:{PORT}\r\n' + 'Accept-Encoding: identity\r\n' + 'Content-Length: 0\r\n\r\n'.encode('ascii')) conn.close() def test_context_manager(self): diff -Nru python3.6-3.6.8/Lib/tkinter/test/test_ttk/test_widgets.py python3.6-3.6.9/Lib/tkinter/test/test_ttk/test_widgets.py --- python3.6-3.6.8/Lib/tkinter/test/test_ttk/test_widgets.py 2018-12-23 21:37:14.000000000 +0000 +++ python3.6-3.6.9/Lib/tkinter/test/test_ttk/test_widgets.py 2019-07-02 20:25:39.000000000 +0000 @@ -329,7 +329,12 @@ self.entry.wait_visibility() self.entry.update_idletasks() - self.assertEqual(self.entry.identify(5, 5), "textarea") + # bpo-27313: macOS Cocoa widget differs from X, allow either + if sys.platform == 'darwin': + self.assertIn(self.entry.identify(5, 5), + ("textarea", "Combobox.button") ) + else: + self.assertEqual(self.entry.identify(5, 5), "textarea") self.assertEqual(self.entry.identify(-1, -1), "") self.assertRaises(tkinter.TclError, self.entry.identify, None, 5) diff -Nru python3.6-3.6.8/Lib/urllib/parse.py python3.6-3.6.9/Lib/urllib/parse.py --- python3.6-3.6.8/Lib/urllib/parse.py 2018-12-23 21:37:14.000000000 +0000 +++ python3.6-3.6.9/Lib/urllib/parse.py 2019-07-02 20:25:39.000000000 +0000 @@ -391,6 +391,24 @@ delim = min(delim, wdelim) # use earliest delim position return url[start:delim], url[delim:] # return (domain, rest) +def _checknetloc(netloc): + if not netloc or not any(ord(c) > 127 for c in netloc): + return + # looking for characters like \u2100 that expand to 'a/c' + # IDNA uses NFKC equivalence, so normalize for this check + import unicodedata + n = netloc.replace('@', '') # ignore characters already included + n = n.replace(':', '') # but not the surrounding text + n = n.replace('#', '') + n = n.replace('?', '') + netloc2 = unicodedata.normalize('NFKC', n) + if n == netloc2: + return + for c in '/?#@:': + if c in netloc2: + raise ValueError("netloc '" + netloc + "' contains invalid " + + "characters under NFKC normalization") + def urlsplit(url, scheme='', allow_fragments=True): """Parse a URL into 5 components: :///?# @@ -420,6 +438,7 @@ url, fragment = url.split('#', 1) if '?' in url: url, query = url.split('?', 1) + _checknetloc(netloc) v = SplitResult(scheme, netloc, url, query, fragment) _parse_cache[key] = v return _coerce_result(v) @@ -443,6 +462,7 @@ url, fragment = url.split('#', 1) if '?' in url: url, query = url.split('?', 1) + _checknetloc(netloc) v = SplitResult(scheme, netloc, url, query, fragment) _parse_cache[key] = v return _coerce_result(v) diff -Nru python3.6-3.6.8/Lib/urllib/request.py python3.6-3.6.9/Lib/urllib/request.py --- python3.6-3.6.8/Lib/urllib/request.py 2018-12-23 21:37:14.000000000 +0000 +++ python3.6-3.6.9/Lib/urllib/request.py 2019-07-02 20:25:39.000000000 +0000 @@ -1747,7 +1747,7 @@ name = 'open_' + urltype self.type = urltype name = name.replace('-', '_') - if not hasattr(self, name): + if not hasattr(self, name) or name == 'open_local_file': if proxy: return self.open_unknown_proxy(proxy, fullurl, data) else: diff -Nru python3.6-3.6.8/LICENSE python3.6-3.6.9/LICENSE --- python3.6-3.6.8/LICENSE 2018-12-23 21:37:14.000000000 +0000 +++ python3.6-3.6.9/LICENSE 2019-07-02 20:25:39.000000000 +0000 @@ -73,8 +73,8 @@ distribute, and otherwise use Python alone or in any derivative version, provided, however, that PSF's License Agreement and PSF's notice of copyright, i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, -2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 Python Software Foundation; All -Rights Reserved" are retained in Python alone or in any derivative version +2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 Python Software Foundation; +All Rights Reserved" are retained in Python alone or in any derivative version prepared by Licensee. 3. In the event Licensee prepares a derivative work that is based on diff -Nru python3.6-3.6.8/Mac/BuildScript/build-installer.py python3.6-3.6.9/Mac/BuildScript/build-installer.py --- python3.6-3.6.8/Mac/BuildScript/build-installer.py 2018-12-23 21:37:14.000000000 +0000 +++ python3.6-3.6.9/Mac/BuildScript/build-installer.py 2019-07-02 20:25:39.000000000 +0000 @@ -225,9 +225,9 @@ if internalTk(): result.extend([ dict( - name="Tcl 8.6.9", - url="ftp://ftp.tcl.tk/pub/tcl//tcl8_6/tcl8.6.9-src.tar.gz", - checksum='aa0a121d95a0e7b73a036f26028538d4', + name="Tcl 8.6.8", + url="ftp://ftp.tcl.tk/pub/tcl//tcl8_6/tcl8.6.8-src.tar.gz", + checksum='81656d3367af032e0ae6157eff134f89', buildDir="unix", configure_pre=[ '--enable-shared', @@ -241,9 +241,12 @@ }, ), dict( - name="Tk 8.6.9.1", - url="ftp://ftp.tcl.tk/pub/tcl//tcl8_6/tk8.6.9.1-src.tar.gz", - checksum='9efe3976468352dc894dae0c4e785a8e', + name="Tk 8.6.8", + url="ftp://ftp.tcl.tk/pub/tcl//tcl8_6/tk8.6.8-src.tar.gz", + checksum='5e0faecba458ee1386078fb228d008ba', + patches=[ + "tk868_on_10_8_10_9.patch", + ], buildDir="unix", configure_pre=[ '--enable-aqua', @@ -705,7 +708,6 @@ work for current Tcl and Tk source releases where the basename of the archive ends with "-src" but the uncompressed directory does not. For now, just special case Tcl and Tk tar.gz downloads. - Another special case: the tk8.6.9.1 tarball extracts to tk8.6.9. """ curdir = os.getcwd() try: @@ -715,8 +717,6 @@ if ((retval.startswith('tcl') or retval.startswith('tk')) and retval.endswith('-src')): retval = retval[:-4] - if retval == 'tk8.6.9.1': - retval = 'tk8.6.9' if os.path.exists(retval): shutil.rmtree(retval) fp = os.popen("tar zxf %s 2>&1"%(shellQuote(archiveName),), 'r') diff -Nru python3.6-3.6.8/Mac/BuildScript/tk868_on_10_8_10_9.patch python3.6-3.6.9/Mac/BuildScript/tk868_on_10_8_10_9.patch --- python3.6-3.6.8/Mac/BuildScript/tk868_on_10_8_10_9.patch 1970-01-01 00:00:00.000000000 +0000 +++ python3.6-3.6.9/Mac/BuildScript/tk868_on_10_8_10_9.patch 2019-07-02 20:25:39.000000000 +0000 @@ -0,0 +1,18 @@ +Fix build failure with +quartz variant on OS X 10.8 and 10.9. +Even though Gestalt was deprecated in OS X 10.8, it should work fine +through OS X 10.9, and its replacement NSOperatingSystemVersion was +not introduced until OS X 10.10. + +Patch from MacPorts project and reported upstream: +https://trac.macports.org/ticket/55649 +--- tk8.6.8/macosx/tkMacOSXXStubs.c.orig 2017-12-06 09:25:08.000000000 -0600 ++++ tk8.6.8-patched/macosx/tkMacOSXXStubs.c 2018-01-06 19:34:17.000000000 -0600 +@@ -175,7 +175,7 @@ + { + int major, minor, patch; + +-#if MAC_OS_X_VERSION_MIN_REQUIRED < 1080 ++#if MAC_OS_X_VERSION_MIN_REQUIRED < 101000 + Gestalt(gestaltSystemVersionMajor, (SInt32*)&major); + Gestalt(gestaltSystemVersionMinor, (SInt32*)&minor); + Gestalt(gestaltSystemVersionBugFix, (SInt32*)&patch); diff -Nru python3.6-3.6.8/Mac/IDLE/IDLE.app/Contents/Info.plist python3.6-3.6.9/Mac/IDLE/IDLE.app/Contents/Info.plist --- python3.6-3.6.8/Mac/IDLE/IDLE.app/Contents/Info.plist 2018-12-23 21:37:14.000000000 +0000 +++ python3.6-3.6.9/Mac/IDLE/IDLE.app/Contents/Info.plist 2019-07-02 20:25:39.000000000 +0000 @@ -36,7 +36,7 @@ CFBundleExecutable IDLE CFBundleGetInfoString - %version%, © 2001-2018 Python Software Foundation + %version%, © 2001-2019 Python Software Foundation CFBundleIconFile IDLE.icns CFBundleIdentifier diff -Nru python3.6-3.6.8/Mac/PythonLauncher/Info.plist.in python3.6-3.6.9/Mac/PythonLauncher/Info.plist.in --- python3.6-3.6.8/Mac/PythonLauncher/Info.plist.in 2018-12-23 21:37:14.000000000 +0000 +++ python3.6-3.6.9/Mac/PythonLauncher/Info.plist.in 2019-07-02 20:25:39.000000000 +0000 @@ -40,7 +40,7 @@ CFBundleExecutable Python Launcher CFBundleGetInfoString - %VERSION%, © 2001-2018 Python Software Foundation + %VERSION%, © 2001-2019 Python Software Foundation CFBundleIconFile PythonLauncher.icns CFBundleIdentifier diff -Nru python3.6-3.6.8/Mac/Resources/app/Info.plist.in python3.6-3.6.9/Mac/Resources/app/Info.plist.in --- python3.6-3.6.8/Mac/Resources/app/Info.plist.in 2018-12-23 21:37:14.000000000 +0000 +++ python3.6-3.6.9/Mac/Resources/app/Info.plist.in 2019-07-02 20:25:39.000000000 +0000 @@ -37,7 +37,7 @@ CFBundleInfoDictionaryVersion 6.0 CFBundleLongVersionString - %version%, (c) 2001-2018 Python Software Foundation. + %version%, (c) 2001-2019 Python Software Foundation. CFBundleName Python CFBundlePackageType diff -Nru python3.6-3.6.8/Mac/Resources/framework/Info.plist.in python3.6-3.6.9/Mac/Resources/framework/Info.plist.in --- python3.6-3.6.8/Mac/Resources/framework/Info.plist.in 2018-12-23 21:37:14.000000000 +0000 +++ python3.6-3.6.9/Mac/Resources/framework/Info.plist.in 2019-07-02 20:25:39.000000000 +0000 @@ -17,9 +17,9 @@ CFBundlePackageType FMWK CFBundleShortVersionString - %VERSION%, (c) 2001-2018 Python Software Foundation. + %VERSION%, (c) 2001-2019 Python Software Foundation. CFBundleLongVersionString - %VERSION%, (c) 2001-2018 Python Software Foundation. + %VERSION%, (c) 2001-2019 Python Software Foundation. CFBundleSignature ???? CFBundleVersion diff -Nru python3.6-3.6.8/Misc/NEWS python3.6-3.6.9/Misc/NEWS --- python3.6-3.6.8/Misc/NEWS 2018-12-24 03:01:30.000000000 +0000 +++ python3.6-3.6.9/Misc/NEWS 2019-07-02 20:43:20.000000000 +0000 @@ -2,6 +2,109 @@ Python News +++++++++++ +What's New in Python 3.6.9 final? +================================= + +*Release date: 2019-07-02* + +Library +------- + +- bpo-37437: Update vendorized expat version to 2.2.7. + +macOS +----- + +- bpo-34602: Avoid test suite failures on macOS by no longer calling + resource.setrlimit to increase the process stack size limit at runtime. + The runtime change is no longer needed since the interpreter is being + built with a larger default stack size. + + +What's New in Python 3.6.9 release candidate 1? +=============================================== + +*Release date: 2019-06-18* + +Security +-------- + +- bpo-35907: CVE-2019-9948: Avoid file reading by disallowing + ``local-file://`` and ``local_file://`` URL schemes in + ``URLopener().open()`` and ``URLopener().retrieve()`` of + :mod:`urllib.request`. + +- bpo-36742: Fixes mishandling of pre-normalization characters in + urlsplit(). + +- bpo-30458: Address CVE-2019-9740 by disallowing URL paths with embedded + whitespace or control characters through into the underlying http client + request. Such potentially malicious header injection URLs now cause an + http.client.InvalidURL exception to be raised. + +- bpo-36216: Changes urlsplit() to raise ValueError when the URL contains + characters that decompose under IDNA encoding (NFKC-normalization) into + characters that affect how the URL is parsed. + +- bpo-33529: Prevent fold function used in email header encoding from + entering infinite loop when there are too many non-ASCII characters in a + header. + +- bpo-35746: [CVE-2019-5010] Fix a NULL pointer deref in ssl module. The + cert parser did not handle CRL distribution points with empty DP or URI + correctly. A malicious or buggy certificate can result into segfault. + Vulnerability (TALOS-2018-0758) reported by Colin Read and Nicolas Edet of + Cisco. + +- bpo-35121: Don't send cookies of domain A without Domain attribute to + domain B when domain A is a suffix match of domain B while using a + cookiejar with :class:`http.cookiejar.DefaultCookiePolicy` policy. Patch + by Karthikeyan Singaravelan. + +Library +------- + +- bpo-35643: Fixed a SyntaxWarning: invalid escape sequence in + Modules/_sha3/cleanup.py. Patch by Mickaël Schoentgen. + +- bpo-35121: Don't set cookie for a request when the request path is a + prefix match of the cookie's path attribute but doesn't end with "/". + Patch by Karthikeyan Singaravelan. + +Documentation +------------- + +- bpo-35605: Fix documentation build for sphinx<1.6. Patch by Anthony + Sottile. + +- bpo-35564: Explicitly set master_doc variable in conf.py for compliance + with Sphinx 2.0 + +Tests +----- + +- bpo-36816: Update Lib/test/selfsigned_pythontestdotnet.pem to match + self-signed.pythontest.net's new TLS certificate. + +- bpo-35925: Skip specific nntplib and ssl networking tests when they would + otherwise fail due to a modern OS or distro with a default OpenSSL policy + of rejecting connections to servers with weak certificates or disabling + TLS below TLSv1.2. + +- bpo-27313: Avoid test_ttk_guionly ComboboxTest failure with macOS Cocoa + Tk. + +- bpo-32947: test_ssl fixes for TLS 1.3 and OpenSSL 1.1.1. + +macOS +----- + +- bpo-34602: Avoid failures setting macOS stack resource limit with + resource.setrlimit. This reverts an earlier fix for bpo-18075 which forced + a non-default stack size when building the interpreter executable on + macOS. + + What's New in Python 3.6.8 final? ================================= @@ -312,7 +415,10 @@ - bpo-15663: The macOS 10.6+ installer now provides a private copy of Tcl/Tk 8.6, like the 10.9+ installer does. -- bpo-35402: Update macOS installer to use Tcl/Tk 8.6.9.1. +- bpo-35402: Update macOS installer to use Tcl/Tk 8.6.9.1. [NOTE: This + change was reverted for the released python.org 3.6.8 macOS installers due + to regressions found in Tk 8.6.9.1. For now, the installers provide + Tcl/Tk 8.6.8.] - bpo-35401: Update macOS installer to use OpenSSL 1.0.2q. @@ -818,11 +924,11 @@ Tools/Demos ----------- -- bpo-32962: python-gdb now catchs ``UnicodeDecodeError`` exceptions when +- bpo-32962: python-gdb now catches ``UnicodeDecodeError`` exceptions when calling ``string()``. -- bpo-32962: python-gdb now catchs ValueError on read_var(): when Python has - no debug symbols for example. +- bpo-32962: python-gdb now catches ValueError on read_var(): when Python + has no debug symbols for example. C API ----- diff -Nru python3.6-3.6.8/Modules/expat/expat_external.h python3.6-3.6.9/Modules/expat/expat_external.h --- python3.6-3.6.8/Modules/expat/expat_external.h 2018-12-23 21:37:14.000000000 +0000 +++ python3.6-3.6.9/Modules/expat/expat_external.h 2019-07-02 20:25:39.000000000 +0000 @@ -35,10 +35,6 @@ /* External API definitions */ -/* Namespace external symbols to allow multiple libexpat version to - co-exist. */ -#include "pyexpatns.h" - #if defined(_MSC_EXTENSIONS) && !defined(__BEOS__) && !defined(__CYGWIN__) # define XML_USE_MSC_EXTENSIONS 1 #endif @@ -85,6 +81,10 @@ # endif #endif /* not defined XMLCALL */ +/* Namespace external symbols to allow multiple libexpat version to + co-exist. */ +#include "pyexpatns.h" + #if !defined(XML_STATIC) && !defined(XMLIMPORT) # ifndef XML_BUILDING_EXPAT @@ -97,7 +97,11 @@ # endif #endif /* not defined XML_STATIC */ -#if !defined(XMLIMPORT) && defined(__GNUC__) && (__GNUC__ >= 4) +#ifndef XML_ENABLE_VISIBILITY +# define XML_ENABLE_VISIBILITY 0 +#endif + +#if !defined(XMLIMPORT) && XML_ENABLE_VISIBILITY # define XMLIMPORT __attribute__ ((visibility ("default"))) #endif diff -Nru python3.6-3.6.8/Modules/expat/expat.h python3.6-3.6.9/Modules/expat/expat.h --- python3.6-3.6.8/Modules/expat/expat.h 2018-12-23 21:37:14.000000000 +0000 +++ python3.6-3.6.9/Modules/expat/expat.h 2019-07-02 20:25:39.000000000 +0000 @@ -1076,7 +1076,7 @@ */ #define XML_MAJOR_VERSION 2 #define XML_MINOR_VERSION 2 -#define XML_MICRO_VERSION 6 +#define XML_MICRO_VERSION 7 #ifdef __cplusplus } diff -Nru python3.6-3.6.8/Modules/expat/internal.h python3.6-3.6.9/Modules/expat/internal.h --- python3.6-3.6.8/Modules/expat/internal.h 2018-12-23 21:37:14.000000000 +0000 +++ python3.6-3.6.9/Modules/expat/internal.h 2019-07-02 20:25:39.000000000 +0000 @@ -115,6 +115,11 @@ #endif +#ifdef XML_ENABLE_VISIBILITY +#if XML_ENABLE_VISIBILITY +__attribute__ ((visibility ("default"))) +#endif +#endif void _INTERNAL_trim_to_complete_utf8_characters(const char * from, const char ** fromLimRef); diff -Nru python3.6-3.6.8/Modules/expat/winconfig.h python3.6-3.6.9/Modules/expat/winconfig.h --- python3.6-3.6.8/Modules/expat/winconfig.h 2018-12-23 21:37:14.000000000 +0000 +++ python3.6-3.6.9/Modules/expat/winconfig.h 2019-07-02 20:25:39.000000000 +0000 @@ -53,10 +53,6 @@ /* we will assume all Windows platforms are little endian */ #define BYTEORDER 1234 -/* Windows has memmove() available. */ -#define HAVE_MEMMOVE - - #endif /* !defined(HAVE_EXPAT_CONFIG_H) */ diff -Nru python3.6-3.6.8/Modules/expat/xmlparse.c python3.6-3.6.9/Modules/expat/xmlparse.c --- python3.6-3.6.8/Modules/expat/xmlparse.c 2018-12-23 21:37:14.000000000 +0000 +++ python3.6-3.6.9/Modules/expat/xmlparse.c 2019-07-02 20:25:39.000000000 +0000 @@ -1,4 +1,4 @@ -/* 19ac4776051591216f1874e34ee99b6a43a3784c8bd7d70efeb9258dd22b906a (2.2.6+) +/* 69df5be70289a11fb834869ce4a91c23c1d9dd04baffcbd10e86742d149a080c (2.2.7+) __ __ _ ___\ \/ /_ __ __ _| |_ / _ \\ /| '_ \ / _` | __| @@ -164,15 +164,6 @@ /* Do safe (NULL-aware) pointer arithmetic */ #define EXPAT_SAFE_PTR_DIFF(p, q) (((p) && (q)) ? ((p) - (q)) : 0) -/* Handle the case where memmove() doesn't exist. */ -#ifndef HAVE_MEMMOVE -#ifdef HAVE_BCOPY -#define memmove(d,s,l) bcopy((s),(d),(l)) -#else -#error memmove does not exist on this platform, nor is a substitute available -#endif /* HAVE_BCOPY */ -#endif /* HAVE_MEMMOVE */ - #include "internal.h" #include "xmltok.h" #include "xmlrole.h" @@ -747,7 +738,7 @@ #endif /* ! defined(HAVE_ARC4RANDOM_BUF) && ! defined(HAVE_ARC4RANDOM) */ -#if defined(HAVE_ARC4RANDOM) +#if defined(HAVE_ARC4RANDOM) && ! defined(HAVE_ARC4RANDOM_BUF) static void writeRandomBytes_arc4random(void * target, size_t count) { @@ -765,7 +756,7 @@ } } -#endif /* defined(HAVE_ARC4RANDOM) */ +#endif /* defined(HAVE_ARC4RANDOM) && ! defined(HAVE_ARC4RANDOM_BUF) */ #ifdef _WIN32 @@ -3019,7 +3010,7 @@ enum XML_Error result; if (parser->m_startCdataSectionHandler) parser->m_startCdataSectionHandler(parser->m_handlerArg); -#if 0 +/* BEGIN disabled code */ /* Suppose you doing a transformation on a document that involves changing only the character data. You set up a defaultHandler and a characterDataHandler. The defaultHandler simply copies @@ -3032,9 +3023,9 @@ However, now we have a start/endCdataSectionHandler, so it seems easier to let the user deal with this. */ - else if (parser->m_characterDataHandler) + else if (0 && parser->m_characterDataHandler) parser->m_characterDataHandler(parser->m_handlerArg, parser->m_dataBuf, 0); -#endif +/* END disabled code */ else if (parser->m_defaultHandler) reportDefault(parser, enc, s, next); result = doCdataSection(parser, enc, &next, end, nextPtr, haveMore); @@ -3731,11 +3722,11 @@ case XML_TOK_CDATA_SECT_CLOSE: if (parser->m_endCdataSectionHandler) parser->m_endCdataSectionHandler(parser->m_handlerArg); -#if 0 +/* BEGIN disabled code */ /* see comment under XML_TOK_CDATA_SECT_OPEN */ - else if (parser->m_characterDataHandler) + else if (0 && parser->m_characterDataHandler) parser->m_characterDataHandler(parser->m_handlerArg, parser->m_dataBuf, 0); -#endif +/* END disabled code */ else if (parser->m_defaultHandler) reportDefault(parser, enc, s, next); *startPtr = next; @@ -6080,7 +6071,7 @@ else poolDiscard(&dtd->pool); elementType->prefix = prefix; - + break; } } return 1; diff -Nru python3.6-3.6.8/Modules/expat/xmltok.c python3.6-3.6.9/Modules/expat/xmltok.c --- python3.6-3.6.8/Modules/expat/xmltok.c 2018-12-23 21:37:14.000000000 +0000 +++ python3.6-3.6.9/Modules/expat/xmltok.c 2019-07-02 20:25:39.000000000 +0000 @@ -30,9 +30,6 @@ USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#if !defined(_WIN32) && defined(HAVE_EXPAT_CONFIG_H) -# include -#endif #include #include /* memcpy */ diff -Nru python3.6-3.6.8/Modules/_sha3/cleanup.py python3.6-3.6.9/Modules/_sha3/cleanup.py --- python3.6-3.6.8/Modules/_sha3/cleanup.py 2018-12-23 21:37:14.000000000 +0000 +++ python3.6-3.6.9/Modules/_sha3/cleanup.py 2019-07-02 20:25:39.000000000 +0000 @@ -8,7 +8,7 @@ import re CPP1 = re.compile("^//(.*)") -CPP2 = re.compile("\ //(.*)") +CPP2 = re.compile(r"\ //(.*)") STATICS = ("void ", "int ", "HashReturn ", "const UINT64 ", "UINT16 ", " int prefix##") diff -Nru python3.6-3.6.8/Modules/_ssl.c python3.6-3.6.9/Modules/_ssl.c --- python3.6-3.6.8/Modules/_ssl.c 2018-12-23 21:37:14.000000000 +0000 +++ python3.6-3.6.9/Modules/_ssl.c 2019-07-02 20:25:39.000000000 +0000 @@ -1338,6 +1338,10 @@ STACK_OF(GENERAL_NAME) *gns; dp = sk_DIST_POINT_value(dps, i); + if (dp->distpoint == NULL) { + /* Ignore empty DP value, CVE-2019-5010 */ + continue; + } gns = dp->distpoint->name.fullname; for (j=0; j < sk_GENERAL_NAME_num(gns); j++) { diff -Nru python3.6-3.6.8/PC/winreg.c python3.6-3.6.9/PC/winreg.c --- python3.6-3.6.8/PC/winreg.c 2018-12-23 21:37:14.000000000 +0000 +++ python3.6-3.6.9/PC/winreg.c 2019-07-02 20:25:39.000000000 +0000 @@ -520,7 +520,7 @@ Q = data + len; for (P = data, i = 0; P < Q && *P != '\0'; P++, i++) { str[i] = P; - for(; *P != '\0'; P++) + for (; P < Q && *P != '\0'; P++) ; } } diff -Nru python3.6-3.6.8/Python/getcopyright.c python3.6-3.6.9/Python/getcopyright.c --- python3.6-3.6.8/Python/getcopyright.c 2018-12-23 21:37:14.000000000 +0000 +++ python3.6-3.6.9/Python/getcopyright.c 2019-07-02 20:25:39.000000000 +0000 @@ -4,7 +4,7 @@ static const char cprt[] = "\ -Copyright (c) 2001-2018 Python Software Foundation.\n\ +Copyright (c) 2001-2019 Python Software Foundation.\n\ All Rights Reserved.\n\ \n\ Copyright (c) 2000 BeOpen.com.\n\ diff -Nru python3.6-3.6.8/README.rst python3.6-3.6.9/README.rst --- python3.6-3.6.8/README.rst 2018-12-23 21:37:14.000000000 +0000 +++ python3.6-3.6.9/README.rst 2019-07-02 20:25:39.000000000 +0000 @@ -1,4 +1,4 @@ -This is Python version 3.6.8 +This is Python version 3.6.9 ============================ .. image:: https://travis-ci.org/python/cpython.svg?branch=3.6 @@ -18,8 +18,8 @@ :target: https://codecov.io/gh/python/cpython Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, -2012, 2013, 2014, 2015, 2016, 2017, 2018 Python Software Foundation. All rights -reserved. +2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 Python Software Foundation. All +rights reserved. See the end of this file for further copyright and license information. @@ -59,7 +59,7 @@ make test sudo make install -This will install Python as python3. +This will install Python as ``python3``. You can pass many options to the configure script; run ``./configure --help`` to find out more. On macOS and Cygwin, the executable is called ``python.exe``; @@ -245,8 +245,8 @@ --------------------------------- Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, -2012, 2013, 2014, 2015, 2016, 2017, 2018 Python Software Foundation. All rights -reserved. +2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 Python Software Foundation. All +rights reserved. Copyright (c) 2000 BeOpen.com. All rights reserved. diff -Nru python3.6-3.6.8/setup.py python3.6-3.6.9/setup.py --- python3.6-3.6.8/setup.py 2018-12-23 21:37:14.000000000 +0000 +++ python3.6-3.6.9/setup.py 2019-07-02 20:25:39.000000000 +0000 @@ -1557,9 +1557,9 @@ cc = sysconfig.get_config_var('CC').split()[0] ret = os.system( - '"%s" -Werror -Wimplicit-fallthrough -E -xc /dev/null >/dev/null 2>&1' % cc) + '"%s" -Werror -Wno-unreachable-code -E -xc /dev/null >/dev/null 2>&1' % cc) if ret >> 8 == 0: - extra_compile_args.append('-Wno-implicit-fallthrough') + extra_compile_args.append('-Wno-unreachable-code') exts.append(Extension('pyexpat', define_macros = define_macros,