diff --git a/009-raise-an-error-when-STARTTLS-fails.patch b/009-raise-an-error-when-STARTTLS-fails.patch new file mode 100644 index 0000000..ba1cc53 --- /dev/null +++ b/009-raise-an-error-when-STARTTLS-fails.patch @@ -0,0 +1,35 @@ +From 9092f6266c3054befff053aa943632856cedbdba Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= +Date: Fri, 1 Jul 2016 11:42:53 +0200 +Subject: [PATCH] Raise an error when STARTTLS fails + +CVE-2016-0772 python: smtplib StartTLS stripping attack +rhbz#1303647: https://bugzilla.redhat.com/show_bug.cgi?id=1303647 +rhbz#1351680: https://bugzilla.redhat.com/show_bug.cgi?id=1351680 + +Based on an upstream change by Benjamin Peterson +- in changeset 101887:d590114c2394 3.4 +- https://hg.python.org/cpython/rev/d590114c2394 +--- + lib-python/3/smtplib.py | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/lib-python/3/smtplib.py b/lib-python/3/smtplib.py +index 679e478..1aacfaf 100644 +--- a/lib-python/3/smtplib.py ++++ b/lib-python/3/smtplib.py +@@ -666,6 +666,11 @@ class SMTP: + self.ehlo_resp = None + self.esmtp_features = {} + self.does_esmtp = 0 ++ else: ++ # RFC 3207: ++ # 501 Syntax error (no parameters allowed) ++ # 454 TLS not available due to temporary reason ++ raise SMTPResponseException(resp, reply) + return (resp, reply) + + def sendmail(self, from_addr, to_addrs, msg, mail_options=[], +-- +2.9.0 + diff --git a/010-disabled-HTTP-header-injections-in-http.client.patch b/010-disabled-HTTP-header-injections-in-http.client.patch new file mode 100644 index 0000000..10591d5 --- /dev/null +++ b/010-disabled-HTTP-header-injections-in-http.client.patch @@ -0,0 +1,163 @@ +From 82dc922c7c4771ef789f5b395f54a603c693b05e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= +Date: Fri, 1 Jul 2016 13:08:55 +0200 +Subject: [PATCH] Disabled HTTP header injections in http.client. + +CVE-2016-5699 python: http protocol steam injection attack +rhbz#1303699: https://bugzilla.redhat.com/show_bug.cgi?id=1303699 +rhbz#1351687: https://bugzilla.redhat.com/show_bug.cgi?id=1351687 + +Based on an upstream change by Demian Brecht and Serhiy Storchaka +- in changeset 94952:bf3e1c9b80e9 3.4 +- https://hg.python.org/cpython/rev/bf3e1c9b80e9 +--- + lib-python/3/http/client.py | 37 +++++++++++++++++++++++++ + lib-python/3/test/test_httplib.py | 57 +++++++++++++++++++++++++++++++++++++++ + 2 files changed, 94 insertions(+) + +diff --git a/lib-python/3/http/client.py b/lib-python/3/http/client.py +index 5466d06..1d215d8 100644 +--- a/lib-python/3/http/client.py ++++ b/lib-python/3/http/client.py +@@ -70,6 +70,7 @@ import email.parser + import email.message + import io + import os ++import re + import socket + import collections + from urllib.parse import urlsplit +@@ -207,6 +208,34 @@ MAXAMOUNT = 1048576 + # maximal line length when calling readline(). + _MAXLINE = 65536 + ++# Header name/value ABNF (http://tools.ietf.org/html/rfc7230#section-3.2) ++# ++# VCHAR = %x21-7E ++# obs-text = %x80-FF ++# header-field = field-name ":" OWS field-value OWS ++# field-name = token ++# field-value = *( field-content / obs-fold ) ++# field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ] ++# field-vchar = VCHAR / obs-text ++# ++# obs-fold = CRLF 1*( SP / HTAB ) ++# ; obsolete line folding ++# ; see Section 3.2.4 ++ ++# token = 1*tchar ++# ++# tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" ++# / "+" / "-" / "." / "^" / "_" / "`" / "|" / "~" ++# / DIGIT / ALPHA ++# ; any VCHAR, except delimiters ++# ++# VCHAR defined in http://tools.ietf.org/html/rfc5234#appendix-B.1 ++ ++# the patterns for both name and value are more leniant than RFC ++# definitions to allow for backwards compatibility ++_is_legal_header_name = re.compile(b'^[^:\s][^:\r\n]*$').match ++_is_illegal_header_value = re.compile(b'\n(?![ \t])|\r(?![ \t\n])').search ++ + class HTTPMessage(email.message.Message): + # XXX The only usage of this method is in + # http.server.CGIHTTPRequestHandler. Maybe move the code there so +@@ -953,12 +982,20 @@ class HTTPConnection: + + if hasattr(header, 'encode'): + header = header.encode('ascii') ++ ++ if not _is_legal_header_name(header): ++ raise ValueError('Invalid header name %r' % (header,)) ++ + values = list(values) + for i, one_value in enumerate(values): + if hasattr(one_value, 'encode'): + values[i] = one_value.encode('latin1') + elif isinstance(one_value, int): + values[i] = str(one_value).encode('ascii') ++ ++ if _is_illegal_header_value(values[i]): ++ raise ValueError('Invalid header value %r' % (values[i],)) ++ + value = b'\r\n\t'.join(values) + header = header + b': ' + value + self._output(header) +diff --git a/lib-python/3/test/test_httplib.py b/lib-python/3/test/test_httplib.py +index 420302c..31d3bd0 100644 +--- a/lib-python/3/test/test_httplib.py ++++ b/lib-python/3/test/test_httplib.py +@@ -134,6 +134,33 @@ class HeaderTests(TestCase): + conn.putheader('Content-length', 42) + self.assertTrue(b'Content-length: 42' in conn._buffer) + ++ conn.putheader('Foo', ' bar ') ++ self.assertIn(b'Foo: bar ', conn._buffer) ++ conn.putheader('Bar', '\tbaz\t') ++ self.assertIn(b'Bar: \tbaz\t', conn._buffer) ++ conn.putheader('Authorization', 'Bearer mytoken') ++ self.assertIn(b'Authorization: Bearer mytoken', conn._buffer) ++ conn.putheader('IterHeader', 'IterA', 'IterB') ++ self.assertIn(b'IterHeader: IterA\r\n\tIterB', conn._buffer) ++ conn.putheader('LatinHeader', b'\xFF') ++ self.assertIn(b'LatinHeader: \xFF', conn._buffer) ++ conn.putheader('Utf8Header', b'\xc3\x80') ++ self.assertIn(b'Utf8Header: \xc3\x80', conn._buffer) ++ conn.putheader('C1-Control', b'next\x85line') ++ self.assertIn(b'C1-Control: next\x85line', conn._buffer) ++ conn.putheader('Embedded-Fold-Space', 'is\r\n allowed') ++ self.assertIn(b'Embedded-Fold-Space: is\r\n allowed', conn._buffer) ++ conn.putheader('Embedded-Fold-Tab', 'is\r\n\tallowed') ++ self.assertIn(b'Embedded-Fold-Tab: is\r\n\tallowed', conn._buffer) ++ conn.putheader('Key Space', 'value') ++ self.assertIn(b'Key Space: value', conn._buffer) ++ conn.putheader('KeySpace ', 'value') ++ self.assertIn(b'KeySpace : value', conn._buffer) ++ conn.putheader(b'Nonbreak\xa0Space', 'value') ++ self.assertIn(b'Nonbreak\xa0Space: value', conn._buffer) ++ conn.putheader(b'\xa0NonbreakSpace', 'value') ++ self.assertIn(b'\xa0NonbreakSpace: value', conn._buffer) ++ + def test_ipv6host_header(self): + # Default host header on IPv6 transaction should wrapped by [] if + # its actual IPv6 address +@@ -153,6 +180,36 @@ class HeaderTests(TestCase): + conn.request('GET', '/foo') + self.assertTrue(sock.data.startswith(expected)) + ++ def test_invalid_headers(self): ++ conn = client.HTTPConnection('example.com') ++ conn.sock = FakeSocket('') ++ conn.putrequest('GET', '/') ++ ++ # http://tools.ietf.org/html/rfc7230#section-3.2.4, whitespace is no ++ # longer allowed in header names ++ cases = ( ++ (b'Invalid\r\nName', b'ValidValue'), ++ (b'Invalid\rName', b'ValidValue'), ++ (b'Invalid\nName', b'ValidValue'), ++ (b'\r\nInvalidName', b'ValidValue'), ++ (b'\rInvalidName', b'ValidValue'), ++ (b'\nInvalidName', b'ValidValue'), ++ (b' InvalidName', b'ValidValue'), ++ (b'\tInvalidName', b'ValidValue'), ++ (b'Invalid:Name', b'ValidValue'), ++ (b':InvalidName', b'ValidValue'), ++ (b'ValidName', b'Invalid\r\nValue'), ++ (b'ValidName', b'Invalid\rValue'), ++ (b'ValidName', b'Invalid\nValue'), ++ (b'ValidName', b'InvalidValue\r\n'), ++ (b'ValidName', b'InvalidValue\r'), ++ (b'ValidName', b'InvalidValue\n'), ++ ) ++ for name, value in cases: ++ with self.subTest((name, value)): ++ with self.assertRaisesRegex(ValueError, 'Invalid header'): ++ conn.putheader(name, value) ++ + + class BasicTest(TestCase): + def test_status_lines(self): +-- +2.9.0 + diff --git a/pypy3.spec b/pypy3.spec index e31b4d4..5666e56 100644 --- a/pypy3.spec +++ b/pypy3.spec @@ -1,6 +1,6 @@ Name: pypy3 Version: 2.4.0 -Release: 5%{?dist} +Release: 6%{?dist} Summary: Python 3 implementation with a Just-In-Time compiler Group: Development/Languages @@ -156,6 +156,20 @@ Patch2: 007-remove-startup-message.patch # https://bitbucket.org/pypy/pypy/commits/c4c54cb69aba Patch3: 008-maximum-recursion-depth.patch +# CVE-2016-0772 python: smtplib StartTLS stripping attack +# rhbz#1303647: https://bugzilla.redhat.com/show_bug.cgi?id=1303647 +# rhbz#1351680: https://bugzilla.redhat.com/show_bug.cgi?id=1351680 +# FIXED UPSTREAM: https://hg.python.org/cpython/rev/d590114c2394 +# Raise an error when STARTTLS fails +Patch4: 009-raise-an-error-when-STARTTLS-fails.patch + +# CVE-2016-5699 python: http protocol steam injection attack +# rhbz#1303699: https://bugzilla.redhat.com/show_bug.cgi?id=1303699 +# rhbz#1351687: https://bugzilla.redhat.com/show_bug.cgi?id=1351687 +# FIXED UPSTREAM: https://hg.python.org/cpython/rev/bf3e1c9b80e9 +# Disabled HTTP header injections in http.client +Patch5: 010-disabled-HTTP-header-injections-in-http.client.patch + # Build-time requirements: # pypy's can be rebuilt using itself, rather than with CPython; doing so @@ -842,6 +856,17 @@ CheckPyPy %{name}-stackless %changelog +* Fri Jul 01 2016 Miro Hrončok - 2.4.0-6 +- Fix for: CVE-2016-0772 python: smtplib StartTLS stripping attack +- Raise an error when STARTTLS fails +- rhbz#1303647: https://bugzilla.redhat.com/show_bug.cgi?id=1303647 +- rhbz#1351680: https://bugzilla.redhat.com/show_bug.cgi?id=1351680 +- Fixed upstream: https://hg.python.org/cpython/rev/d590114c2394 +- Fix for: CVE-2016-5699 python: http protocol steam injection attack +- rhbz#1303699: https://bugzilla.redhat.com/show_bug.cgi?id=1303699 +- rhbz#1351687: https://bugzilla.redhat.com/show_bug.cgi?id=1351687 +- Fixed upstream: https://hg.python.org/cpython/rev/bf3e1c9b80e9 + * Fri May 13 2016 Miro Hrončok - 2.4.0-5 - Fix FTBFS (#1307889) - Add patch to fix maximum recursion depth error during build