diff options
-rw-r--r-- | system/python3/APKBUILD | 15 | ||||
-rw-r--r-- | system/python3/CVE-2019-16056.patch | 131 | ||||
-rw-r--r-- | system/python3/CVE-2019-16935.patch | 80 | ||||
-rw-r--r-- | system/python3/CVE-2019-18348.patch | 147 |
4 files changed, 156 insertions, 217 deletions
diff --git a/system/python3/APKBUILD b/system/python3/APKBUILD index b8c72f3a7..e875d3941 100644 --- a/system/python3/APKBUILD +++ b/system/python3/APKBUILD @@ -1,7 +1,7 @@ # Contributor: Kiyoshi Aman <adelie@aerdan.vulpine.house> # Maintainer: A. Wilcox <awilfox@adelielinux.org> pkgname=python3 -pkgver=3.6.9 +pkgver=3.6.10 _basever="${pkgver%.*}" pkgrel=2 pkgdesc="A high-level scripting language" @@ -40,8 +40,7 @@ makedepends="expat-dev openssl-dev zlib-dev ncurses-dev bzip2-dev xz-dev source="https://www.python.org/ftp/python/$pkgver/Python-$pkgver.tar.xz musl-find_library.patch fix-xattrs-glibc.patch - CVE-2019-16056.patch - CVE-2019-16935.patch + CVE-2019-18348.patch " builddir="$srcdir/Python-$pkgver" @@ -63,6 +62,8 @@ builddir="$srcdir/Python-$pkgver" # - CVE-2019-16056 # 3.6.9-r2: # - CVE-2019-16935 +# 3.6.10-r0: +# - CVE-2019-18348 prepare() { default_prepare @@ -153,11 +154,14 @@ EOF } package() { + export XDG_CACHE_HOME="$(mktemp -d)" make -j1 DESTDIR="$pkgdir" EXTRA_CFLAGS="$CFLAGS" install maninstall install -Dm644 LICENSE "$pkgdir"/usr/share/licenses/$pkgname/LICENSE # those are provided by python3-tkinter rm -r "$pkgdir"/usr/bin/idle* "$pkgdir"/usr/lib/python*/idlelib \ "$pkgdir"/usr/lib/python*/tkinter + + rm -rf "$XDG_CACHE_HOME" } dev() { @@ -189,8 +193,7 @@ wininst() { "$subpkgdir"/usr/lib/python$_basever/distutils/command } -sha512sums="05de9c6f44d96a52bfce10ede4312de892573edaf8bece65926d19973a3a800d65eed7a857af945f69efcfb25efa3788e7a54016b03d80b611eb51c3ea074819 Python-3.6.9.tar.xz +sha512sums="26147099e1f1a0ffc85febad26e18e991f019599a150887ea0b925e34663fad8e03b3c2a941e2770c1a63960695e173ef32709572c9361e7f2cb862ccf75b28a Python-3.6.10.tar.xz ab8eaa2858d5109049b1f9f553198d40e0ef8d78211ad6455f7b491af525bffb16738fed60fc84e960c4889568d25753b9e4a1494834fea48291b33f07000ec2 musl-find_library.patch 37b6ee5d0d5de43799316aa111423ba5a666c17dc7f81b04c330f59c1d1565540eac4c585abe2199bbed52ebe7426001edb1c53bd0a17486a2a8e052d0f494ad fix-xattrs-glibc.patch -1f1eb61355eb7832bef8e9c3915895cc3b2966a30c809371430b4416260452cd39c48ba593b2259574867bd1e8fea98efbc45c4b0bd95aeb0690c8514b380ea0 CVE-2019-16056.patch -7f94d887c81f79d90afd4a9621547c13cbdd0232250f62a686b26a63160a4d286a6db9b342d06b9b63af64f994835b489c37bab499a2093c3c2585dc7a04d8a1 CVE-2019-16935.patch" +7a15409165feb60358455b711f978b7b1c4dea9ad53aa7b5be07c1f70262988e592e7a630f83125f37051bbed14d14b66d2acd775234a163ff5b048621b9a59c CVE-2019-18348.patch" diff --git a/system/python3/CVE-2019-16056.patch b/system/python3/CVE-2019-16056.patch deleted file mode 100644 index b2f5ce826..000000000 --- a/system/python3/CVE-2019-16056.patch +++ /dev/null @@ -1,131 +0,0 @@ -From 13a19139b5e76175bc95294d54afc9425e4f36c9 Mon Sep 17 00:00:00 2001 -From: "Miss Islington (bot)" - <31488909+miss-islington@users.noreply.github.com> -Date: Fri, 9 Aug 2019 08:22:19 -0700 -Subject: [PATCH] bpo-34155: Dont parse domains containing @ (GH-13079) - (GH-14826) - -Before: - - >>> email.message_from_string('From: a@malicious.org@important.com', policy=email.policy.default)['from'].addresses - (Address(display_name='', username='a', domain='malicious.org'),) - - >>> parseaddr('a@malicious.org@important.com') - ('', 'a@malicious.org') - - After: - - >>> email.message_from_string('From: a@malicious.org@important.com', policy=email.policy.default)['from'].addresses - (Address(display_name='', username='', domain=''),) - - >>> parseaddr('a@malicious.org@important.com') - ('', 'a@') - -https://bugs.python.org/issue34155 -(cherry picked from commit 8cb65d1381b027f0b09ee36bfed7f35bb4dec9a9) - -Co-authored-by: jpic <jpic@users.noreply.github.com> ---- - Lib/email/_header_value_parser.py | 2 ++ - Lib/email/_parseaddr.py | 11 ++++++++++- - Lib/test/test_email/test__header_value_parser.py | 10 ++++++++++ - Lib/test/test_email/test_email.py | 14 ++++++++++++++ - .../2019-05-04-13-33-37.bpo-34155.MJll68.rst | 1 + - 5 files changed, 37 insertions(+), 1 deletion(-) - create mode 100644 Misc/NEWS.d/next/Security/2019-05-04-13-33-37.bpo-34155.MJll68.rst - -diff --git a/Lib/email/_header_value_parser.py b/Lib/email/_header_value_parser.py -index 737951e4b1b1..bc9c9b6241d4 100644 ---- a/Lib/email/_header_value_parser.py -+++ b/Lib/email/_header_value_parser.py -@@ -1561,6 +1561,8 @@ def get_domain(value): - token, value = get_dot_atom(value) - except errors.HeaderParseError: - token, value = get_atom(value) -+ if value and value[0] == '@': -+ raise errors.HeaderParseError('Invalid Domain') - if leader is not None: - token[:0] = [leader] - domain.append(token) -diff --git a/Lib/email/_parseaddr.py b/Lib/email/_parseaddr.py -index cdfa3729adc7..41ff6f8c000d 100644 ---- a/Lib/email/_parseaddr.py -+++ b/Lib/email/_parseaddr.py -@@ -379,7 +379,12 @@ def getaddrspec(self): - aslist.append('@') - self.pos += 1 - self.gotonext() -- return EMPTYSTRING.join(aslist) + self.getdomain() -+ domain = self.getdomain() -+ if not domain: -+ # Invalid domain, return an empty address instead of returning a -+ # local part to denote failed parsing. -+ return EMPTYSTRING -+ return EMPTYSTRING.join(aslist) + domain - - def getdomain(self): - """Get the complete domain name from an address.""" -@@ -394,6 +399,10 @@ def getdomain(self): - elif self.field[self.pos] == '.': - self.pos += 1 - sdlist.append('.') -+ elif self.field[self.pos] == '@': -+ # bpo-34155: Don't parse domains with two `@` like -+ # `a@malicious.org@important.com`. -+ return EMPTYSTRING - elif self.field[self.pos] in self.atomends: - break - else: -diff --git a/Lib/test/test_email/test__header_value_parser.py b/Lib/test/test_email/test__header_value_parser.py -index a2c900fa7fd2..02ef3e1006c6 100644 ---- a/Lib/test/test_email/test__header_value_parser.py -+++ b/Lib/test/test_email/test__header_value_parser.py -@@ -1418,6 +1418,16 @@ def test_get_addr_spec_dot_atom(self): - self.assertEqual(addr_spec.domain, 'example.com') - self.assertEqual(addr_spec.addr_spec, 'star.a.star@example.com') - -+ def test_get_addr_spec_multiple_domains(self): -+ with self.assertRaises(errors.HeaderParseError): -+ parser.get_addr_spec('star@a.star@example.com') -+ -+ with self.assertRaises(errors.HeaderParseError): -+ parser.get_addr_spec('star@a@example.com') -+ -+ with self.assertRaises(errors.HeaderParseError): -+ parser.get_addr_spec('star@172.17.0.1@example.com') -+ - # get_obs_route - - def test_get_obs_route_simple(self): -diff --git a/Lib/test/test_email/test_email.py b/Lib/test/test_email/test_email.py -index f97ccc6711cc..68d052279987 100644 ---- a/Lib/test/test_email/test_email.py -+++ b/Lib/test/test_email/test_email.py -@@ -3035,6 +3035,20 @@ def test_parseaddr_empty(self): - self.assertEqual(utils.parseaddr('<>'), ('', '')) - self.assertEqual(utils.formataddr(utils.parseaddr('<>')), '') - -+ def test_parseaddr_multiple_domains(self): -+ self.assertEqual( -+ utils.parseaddr('a@b@c'), -+ ('', '') -+ ) -+ self.assertEqual( -+ utils.parseaddr('a@b.c@c'), -+ ('', '') -+ ) -+ self.assertEqual( -+ utils.parseaddr('a@172.17.0.1@c'), -+ ('', '') -+ ) -+ - def test_noquote_dump(self): - self.assertEqual( - utils.formataddr(('A Silly Person', 'person@dom.ain')), -diff --git a/Misc/NEWS.d/next/Security/2019-05-04-13-33-37.bpo-34155.MJll68.rst b/Misc/NEWS.d/next/Security/2019-05-04-13-33-37.bpo-34155.MJll68.rst -new file mode 100644 -index 000000000000..50292e29ed1d ---- /dev/null -+++ b/Misc/NEWS.d/next/Security/2019-05-04-13-33-37.bpo-34155.MJll68.rst -@@ -0,0 +1 @@ -+Fix parsing of invalid email addresses with more than one ``@`` (e.g. a@b@c.com.) to not return the part before 2nd ``@`` as valid email address. Patch by maxking & jpic. diff --git a/system/python3/CVE-2019-16935.patch b/system/python3/CVE-2019-16935.patch deleted file mode 100644 index 567eb90fc..000000000 --- a/system/python3/CVE-2019-16935.patch +++ /dev/null @@ -1,80 +0,0 @@ -From 1698cacfb924d1df452e78d11a4bf81ae7777389 Mon Sep 17 00:00:00 2001 -From: Victor Stinner <vstinner@redhat.com> -Date: Sat, 28 Sep 2019 09:33:00 +0200 -Subject: [PATCH] bpo-38243, xmlrpc.server: Escape the server_title (GH-16373) - (GH-16441) - -Escape the server title of xmlrpc.server.DocXMLRPCServer -when rendering the document page as HTML. - -(cherry picked from commit e8650a4f8c7fb76f570d4ca9c1fbe44e91c8dfaa) ---- - Lib/test/test_docxmlrpc.py | 16 ++++++++++++++++ - Lib/xmlrpc/server.py | 3 ++- - .../2019-09-25-13-21-09.bpo-38243.1pfz24.rst | 3 +++ - 3 files changed, 21 insertions(+), 1 deletion(-) - create mode 100644 Misc/NEWS.d/next/Security/2019-09-25-13-21-09.bpo-38243.1pfz24.rst - -diff --git a/Lib/test/test_docxmlrpc.py b/Lib/test/test_docxmlrpc.py -index 00903337c07c2..d2adb21af0fb3 100644 ---- a/Lib/test/test_docxmlrpc.py -+++ b/Lib/test/test_docxmlrpc.py -@@ -1,5 +1,6 @@ - from xmlrpc.server import DocXMLRPCServer - import http.client -+import re - import sys - from test import support - threading = support.import_module('threading') -@@ -193,6 +194,21 @@ def test_annotations(self): - b'method_annotation</strong></a>(x: bytes)</dt></dl>'), - response.read()) - -+ def test_server_title_escape(self): -+ # bpo-38243: Ensure that the server title and documentation -+ # are escaped for HTML. -+ self.serv.set_server_title('test_title<script>') -+ self.serv.set_server_documentation('test_documentation<script>') -+ self.assertEqual('test_title<script>', self.serv.server_title) -+ self.assertEqual('test_documentation<script>', -+ self.serv.server_documentation) -+ -+ generated = self.serv.generate_html_documentation() -+ title = re.search(r'<title>(.+?)</title>', generated).group() -+ documentation = re.search(r'<p><tt>(.+?)</tt></p>', generated).group() -+ self.assertEqual('<title>Python: test_title<script></title>', title) -+ self.assertEqual('<p><tt>test_documentation<script></tt></p>', documentation) -+ - - if __name__ == '__main__': - unittest.main() -diff --git a/Lib/xmlrpc/server.py b/Lib/xmlrpc/server.py -index 3e0dca027f068..efe593748968c 100644 ---- a/Lib/xmlrpc/server.py -+++ b/Lib/xmlrpc/server.py -@@ -106,6 +106,7 @@ def export_add(self, x, y): - - from xmlrpc.client import Fault, dumps, loads, gzip_encode, gzip_decode - from http.server import BaseHTTPRequestHandler -+import html - import http.server - import socketserver - import sys -@@ -904,7 +905,7 @@ def generate_html_documentation(self): - methods - ) - -- return documenter.page(self.server_title, documentation) -+ return documenter.page(html.escape(self.server_title), documentation) - - class DocXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): - """XML-RPC and documentation request handler class. -diff --git a/Misc/NEWS.d/next/Security/2019-09-25-13-21-09.bpo-38243.1pfz24.rst b/Misc/NEWS.d/next/Security/2019-09-25-13-21-09.bpo-38243.1pfz24.rst -new file mode 100644 -index 0000000000000..98d7be129573a ---- /dev/null -+++ b/Misc/NEWS.d/next/Security/2019-09-25-13-21-09.bpo-38243.1pfz24.rst -@@ -0,0 +1,3 @@ -+Escape the server title of :class:`xmlrpc.server.DocXMLRPCServer` -+when rendering the document page as HTML. -+(Contributed by Dong-hee Na in :issue:`38243`.) diff --git a/system/python3/CVE-2019-18348.patch b/system/python3/CVE-2019-18348.patch new file mode 100644 index 000000000..9ebb963a8 --- /dev/null +++ b/system/python3/CVE-2019-18348.patch @@ -0,0 +1,147 @@ +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 <aramaswamis@gmail.com> +--- + Lib/http/client.py | 10 ++++++ + Lib/test/test_httplib.py | 13 ++++++- + Lib/test/test_urllib.py | 36 +++++++++++++++++-- + .../2020-03-14-14-57-44.bpo-38576.OowwQn.rst | 1 + + 4 files changed, 57 insertions(+), 3 deletions(-) + create mode 100644 Misc/NEWS.d/next/Security/2020-03-14-14-57-44.bpo-38576.OowwQn.rst + +diff --git a/Lib/http/client.py b/Lib/http/client.py +index d4821f1a96e07..c0ac7db6f40a0 100644 +--- a/Lib/http/client.py ++++ b/Lib/http/client.py +@@ -858,6 +858,8 @@ def __init__(self, host, port=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT, + + (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 +@@ -1215,6 +1217,14 @@ def _validate_path(self, url): + raise InvalidURL(f"URL can't contain control characters. {url!r} " + f"(found at least {match.group()!r})") + ++ 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_httplib.py b/Lib/test/test_httplib.py +index 14d42d483773c..fcd9231666ede 100644 +--- a/Lib/test/test_httplib.py ++++ b/Lib/test/test_httplib.py +@@ -1132,7 +1132,7 @@ def run_server(): + thread.join() + self.assertEqual(result, b"proxied data\n") + +- def test_putrequest_override_validation(self): ++ def test_putrequest_override_domain_validation(self): + """ + It should be possible to override the default validation + behavior in putrequest (bpo-38216). +@@ -1145,6 +1145,17 @@ def _validate_path(self, url): + conn.sock = FakeSocket('') + conn.putrequest('GET', '/\x00') + ++ def test_putrequest_override_host_validation(self): ++ class UnsafeHTTPConnection(client.HTTPConnection): ++ def _validate_host(self, url): ++ pass ++ ++ conn = UnsafeHTTPConnection('example.com\r\n') ++ conn.sock = FakeSocket('') ++ # set skip_host so a ValueError is not raised upon adding the ++ # invalid URL as the value of the "Host:" header ++ conn.putrequest('GET', '/', skip_host=1) ++ + def test_putrequest_override_encoding(self): + """ + It should be possible to override the default encoding +diff --git a/Lib/test/test_urllib.py b/Lib/test/test_urllib.py +index 0061a5297cb35..ddf425fd8d4b5 100644 +--- a/Lib/test/test_urllib.py ++++ b/Lib/test/test_urllib.py +@@ -331,7 +331,7 @@ def test_willclose(self): + 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 @@ def test_url_with_control_char_rejected(self): + 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 @@ def test_url_with_newline_header_injection_rejected(self): + 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 --git a/Misc/NEWS.d/next/Security/2020-03-14-14-57-44.bpo-38576.OowwQn.rst b/Misc/NEWS.d/next/Security/2020-03-14-14-57-44.bpo-38576.OowwQn.rst +new file mode 100644 +index 0000000000000..34b8af28988fa +--- /dev/null ++++ b/Misc/NEWS.d/next/Security/2020-03-14-14-57-44.bpo-38576.OowwQn.rst +@@ -0,0 +1 @@ ++Disallow control characters in hostnames in http.client, addressing CVE-2019-18348. Such potentially malicious header injection URLs now cause a InvalidURL to be raised. +\ No newline at end of file |