Merge branch 'c8' into a8
This commit is contained in:
		
						commit
						bd2db93423
					
				
							
								
								
									
										648
									
								
								SOURCES/00404-cve-2023-40217.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										648
									
								
								SOURCES/00404-cve-2023-40217.patch
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,648 @@
 | 
				
			|||||||
 | 
					From 9f39318072b5775cf527f83daf8cb5d64678ac86 Mon Sep 17 00:00:00 2001
 | 
				
			||||||
 | 
					From: =?UTF-8?q?=C5=81ukasz=20Langa?= <lukasz@langa.pl>
 | 
				
			||||||
 | 
					Date: Tue, 22 Aug 2023 19:57:01 +0200
 | 
				
			||||||
 | 
					Subject: [PATCH 1/4] gh-108310: Fix CVE-2023-40217: Check for & avoid the ssl
 | 
				
			||||||
 | 
					 pre-close flaw (#108321)
 | 
				
			||||||
 | 
					MIME-Version: 1.0
 | 
				
			||||||
 | 
					Content-Type: text/plain; charset=UTF-8
 | 
				
			||||||
 | 
					Content-Transfer-Encoding: 8bit
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					gh-108310: Fix CVE-2023-40217: Check for & avoid the ssl pre-close flaw
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Instances of `ssl.SSLSocket` were vulnerable to a bypass of the TLS handshake
 | 
				
			||||||
 | 
					and included protections (like certificate verification) and treating sent
 | 
				
			||||||
 | 
					unencrypted data as if it were post-handshake TLS encrypted data.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The vulnerability is caused when a socket is connected, data is sent by the
 | 
				
			||||||
 | 
					malicious peer and stored in a buffer, and then the malicious peer closes the
 | 
				
			||||||
 | 
					socket within a small timing window before the other peers’ TLS handshake can
 | 
				
			||||||
 | 
					begin. After this sequence of events the closed socket will not immediately
 | 
				
			||||||
 | 
					attempt a TLS handshake due to not being connected but will also allow the
 | 
				
			||||||
 | 
					buffered data to be read as if a successful TLS handshake had occurred.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Co-authored-by: Gregory P. Smith [Google LLC] <greg@krypto.org>
 | 
				
			||||||
 | 
					---
 | 
				
			||||||
 | 
					 Lib/ssl.py                                    |  31 ++-
 | 
				
			||||||
 | 
					 Lib/test/test_ssl.py                          | 214 ++++++++++++++++++
 | 
				
			||||||
 | 
					 ...-08-22-17-39-12.gh-issue-108310.fVM3sg.rst |   7 +
 | 
				
			||||||
 | 
					 3 files changed, 251 insertions(+), 1 deletion(-)
 | 
				
			||||||
 | 
					 create mode 100644 Misc/NEWS.d/next/Security/2023-08-22-17-39-12.gh-issue-108310.fVM3sg.rst
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					diff --git a/Lib/ssl.py b/Lib/ssl.py
 | 
				
			||||||
 | 
					index c5c5529..288f237 100644
 | 
				
			||||||
 | 
					--- a/Lib/ssl.py
 | 
				
			||||||
 | 
					+++ b/Lib/ssl.py
 | 
				
			||||||
 | 
					@@ -741,7 +741,7 @@ class SSLSocket(socket):
 | 
				
			||||||
 | 
					                             type=sock.type,
 | 
				
			||||||
 | 
					                             proto=sock.proto,
 | 
				
			||||||
 | 
					                             fileno=sock.fileno())
 | 
				
			||||||
 | 
					-            self.settimeout(sock.gettimeout())
 | 
				
			||||||
 | 
					+            sock_timeout = sock.gettimeout()
 | 
				
			||||||
 | 
					             sock.detach()
 | 
				
			||||||
 | 
					         elif fileno is not None:
 | 
				
			||||||
 | 
					             socket.__init__(self, fileno=fileno)
 | 
				
			||||||
 | 
					@@ -755,9 +755,38 @@ class SSLSocket(socket):
 | 
				
			||||||
 | 
					             if e.errno != errno.ENOTCONN:
 | 
				
			||||||
 | 
					                 raise
 | 
				
			||||||
 | 
					             connected = False
 | 
				
			||||||
 | 
					+            blocking = self.getblocking()
 | 
				
			||||||
 | 
					+            self.setblocking(False)
 | 
				
			||||||
 | 
					+            try:
 | 
				
			||||||
 | 
					+                # We are not connected so this is not supposed to block, but
 | 
				
			||||||
 | 
					+                # testing revealed otherwise on macOS and Windows so we do
 | 
				
			||||||
 | 
					+                # the non-blocking dance regardless. Our raise when any data
 | 
				
			||||||
 | 
					+                # is found means consuming the data is harmless.
 | 
				
			||||||
 | 
					+                notconn_pre_handshake_data = self.recv(1)
 | 
				
			||||||
 | 
					+            except OSError as e:
 | 
				
			||||||
 | 
					+                # EINVAL occurs for recv(1) on non-connected on unix sockets.
 | 
				
			||||||
 | 
					+                if e.errno not in (errno.ENOTCONN, errno.EINVAL):
 | 
				
			||||||
 | 
					+                    raise
 | 
				
			||||||
 | 
					+                notconn_pre_handshake_data = b''
 | 
				
			||||||
 | 
					+            self.setblocking(blocking)
 | 
				
			||||||
 | 
					+            if notconn_pre_handshake_data:
 | 
				
			||||||
 | 
					+                # This prevents pending data sent to the socket before it was
 | 
				
			||||||
 | 
					+                # closed from escaping to the caller who could otherwise
 | 
				
			||||||
 | 
					+                # presume it came through a successful TLS connection.
 | 
				
			||||||
 | 
					+                reason = "Closed before TLS handshake with data in recv buffer."
 | 
				
			||||||
 | 
					+                notconn_pre_handshake_data_error = SSLError(e.errno, reason)
 | 
				
			||||||
 | 
					+                # Add the SSLError attributes that _ssl.c always adds.
 | 
				
			||||||
 | 
					+                notconn_pre_handshake_data_error.reason = reason
 | 
				
			||||||
 | 
					+                notconn_pre_handshake_data_error.library = None
 | 
				
			||||||
 | 
					+                try:
 | 
				
			||||||
 | 
					+                    self.close()
 | 
				
			||||||
 | 
					+                except OSError:
 | 
				
			||||||
 | 
					+                    pass
 | 
				
			||||||
 | 
					+                raise notconn_pre_handshake_data_error
 | 
				
			||||||
 | 
					         else:
 | 
				
			||||||
 | 
					             connected = True
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					+        self.settimeout(sock_timeout)  # Must come after setblocking() calls.
 | 
				
			||||||
 | 
					         self._closed = False
 | 
				
			||||||
 | 
					         self._sslobj = None
 | 
				
			||||||
 | 
					         self._connected = connected
 | 
				
			||||||
 | 
					diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py
 | 
				
			||||||
 | 
					index b35db25..e24d11b 100644
 | 
				
			||||||
 | 
					--- a/Lib/test/test_ssl.py
 | 
				
			||||||
 | 
					+++ b/Lib/test/test_ssl.py
 | 
				
			||||||
 | 
					@@ -3,11 +3,14 @@
 | 
				
			||||||
 | 
					 import sys
 | 
				
			||||||
 | 
					 import unittest
 | 
				
			||||||
 | 
					 from test import support
 | 
				
			||||||
 | 
					+import re
 | 
				
			||||||
 | 
					 import socket
 | 
				
			||||||
 | 
					 import select
 | 
				
			||||||
 | 
					+import struct
 | 
				
			||||||
 | 
					 import time
 | 
				
			||||||
 | 
					 import datetime
 | 
				
			||||||
 | 
					 import gc
 | 
				
			||||||
 | 
					+import http.client
 | 
				
			||||||
 | 
					 import os
 | 
				
			||||||
 | 
					 import errno
 | 
				
			||||||
 | 
					 import pprint
 | 
				
			||||||
 | 
					@@ -3940,6 +3943,217 @@ class TestPostHandshakeAuth(unittest.TestCase):
 | 
				
			||||||
 | 
					                 # server cert has not been validated
 | 
				
			||||||
 | 
					                 self.assertEqual(s.getpeercert(), {})
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					+def set_socket_so_linger_on_with_zero_timeout(sock):
 | 
				
			||||||
 | 
					+    sock.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, struct.pack('ii', 1, 0))
 | 
				
			||||||
 | 
					+
 | 
				
			||||||
 | 
					+
 | 
				
			||||||
 | 
					+class TestPreHandshakeClose(unittest.TestCase):
 | 
				
			||||||
 | 
					+    """Verify behavior of close sockets with received data before to the handshake.
 | 
				
			||||||
 | 
					+    """
 | 
				
			||||||
 | 
					+
 | 
				
			||||||
 | 
					+    class SingleConnectionTestServerThread(threading.Thread):
 | 
				
			||||||
 | 
					+
 | 
				
			||||||
 | 
					+        def __init__(self, *, name, call_after_accept):
 | 
				
			||||||
 | 
					+            self.call_after_accept = call_after_accept
 | 
				
			||||||
 | 
					+            self.received_data = b''  # set by .run()
 | 
				
			||||||
 | 
					+            self.wrap_error = None  # set by .run()
 | 
				
			||||||
 | 
					+            self.listener = None  # set by .start()
 | 
				
			||||||
 | 
					+            self.port = None  # set by .start()
 | 
				
			||||||
 | 
					+            super().__init__(name=name)
 | 
				
			||||||
 | 
					+
 | 
				
			||||||
 | 
					+        def __enter__(self):
 | 
				
			||||||
 | 
					+            self.start()
 | 
				
			||||||
 | 
					+            return self
 | 
				
			||||||
 | 
					+
 | 
				
			||||||
 | 
					+        def __exit__(self, *args):
 | 
				
			||||||
 | 
					+            try:
 | 
				
			||||||
 | 
					+                if self.listener:
 | 
				
			||||||
 | 
					+                    self.listener.close()
 | 
				
			||||||
 | 
					+            except OSError:
 | 
				
			||||||
 | 
					+                pass
 | 
				
			||||||
 | 
					+            self.join()
 | 
				
			||||||
 | 
					+            self.wrap_error = None  # avoid dangling references
 | 
				
			||||||
 | 
					+
 | 
				
			||||||
 | 
					+        def start(self):
 | 
				
			||||||
 | 
					+            self.ssl_ctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
 | 
				
			||||||
 | 
					+            self.ssl_ctx.verify_mode = ssl.CERT_REQUIRED
 | 
				
			||||||
 | 
					+            self.ssl_ctx.load_verify_locations(cafile=ONLYCERT)
 | 
				
			||||||
 | 
					+            self.ssl_ctx.load_cert_chain(certfile=ONLYCERT, keyfile=ONLYKEY)
 | 
				
			||||||
 | 
					+            self.listener = socket.socket()
 | 
				
			||||||
 | 
					+            self.port = support.bind_port(self.listener)
 | 
				
			||||||
 | 
					+            self.listener.settimeout(2.0)
 | 
				
			||||||
 | 
					+            self.listener.listen(1)
 | 
				
			||||||
 | 
					+            super().start()
 | 
				
			||||||
 | 
					+
 | 
				
			||||||
 | 
					+        def run(self):
 | 
				
			||||||
 | 
					+            conn, address = self.listener.accept()
 | 
				
			||||||
 | 
					+            self.listener.close()
 | 
				
			||||||
 | 
					+            with conn:
 | 
				
			||||||
 | 
					+                if self.call_after_accept(conn):
 | 
				
			||||||
 | 
					+                    return
 | 
				
			||||||
 | 
					+                try:
 | 
				
			||||||
 | 
					+                    tls_socket = self.ssl_ctx.wrap_socket(conn, server_side=True)
 | 
				
			||||||
 | 
					+                except OSError as err:  # ssl.SSLError inherits from OSError
 | 
				
			||||||
 | 
					+                    self.wrap_error = err
 | 
				
			||||||
 | 
					+                else:
 | 
				
			||||||
 | 
					+                    try:
 | 
				
			||||||
 | 
					+                        self.received_data = tls_socket.recv(400)
 | 
				
			||||||
 | 
					+                    except OSError:
 | 
				
			||||||
 | 
					+                        pass  # closed, protocol error, etc.
 | 
				
			||||||
 | 
					+
 | 
				
			||||||
 | 
					+    def non_linux_skip_if_other_okay_error(self, err):
 | 
				
			||||||
 | 
					+        if sys.platform == "linux":
 | 
				
			||||||
 | 
					+            return  # Expect the full test setup to always work on Linux.
 | 
				
			||||||
 | 
					+        if (isinstance(err, ConnectionResetError) or
 | 
				
			||||||
 | 
					+            (isinstance(err, OSError) and err.errno == errno.EINVAL) or
 | 
				
			||||||
 | 
					+            re.search('wrong.version.number', getattr(err, "reason", ""), re.I)):
 | 
				
			||||||
 | 
					+            # On Windows the TCP RST leads to a ConnectionResetError
 | 
				
			||||||
 | 
					+            # (ECONNRESET) which Linux doesn't appear to surface to userspace.
 | 
				
			||||||
 | 
					+            # If wrap_socket() winds up on the "if connected:" path and doing
 | 
				
			||||||
 | 
					+            # the actual wrapping... we get an SSLError from OpenSSL. Typically
 | 
				
			||||||
 | 
					+            # WRONG_VERSION_NUMBER. While appropriate, neither is the scenario
 | 
				
			||||||
 | 
					+            # we're specifically trying to test. The way this test is written
 | 
				
			||||||
 | 
					+            # is known to work on Linux. We'll skip it anywhere else that it
 | 
				
			||||||
 | 
					+            # does not present as doing so.
 | 
				
			||||||
 | 
					+            self.skipTest("Could not recreate conditions on {}: \
 | 
				
			||||||
 | 
					+                          err={}".format(sys.platform,err))
 | 
				
			||||||
 | 
					+        # If maintaining this conditional winds up being a problem.
 | 
				
			||||||
 | 
					+        # just turn this into an unconditional skip anything but Linux.
 | 
				
			||||||
 | 
					+        # The important thing is that our CI has the logic covered.
 | 
				
			||||||
 | 
					+
 | 
				
			||||||
 | 
					+    def test_preauth_data_to_tls_server(self):
 | 
				
			||||||
 | 
					+        server_accept_called = threading.Event()
 | 
				
			||||||
 | 
					+        ready_for_server_wrap_socket = threading.Event()
 | 
				
			||||||
 | 
					+
 | 
				
			||||||
 | 
					+        def call_after_accept(unused):
 | 
				
			||||||
 | 
					+            server_accept_called.set()
 | 
				
			||||||
 | 
					+            if not ready_for_server_wrap_socket.wait(2.0):
 | 
				
			||||||
 | 
					+                raise RuntimeError("wrap_socket event never set, test may fail.")
 | 
				
			||||||
 | 
					+            return False  # Tell the server thread to continue.
 | 
				
			||||||
 | 
					+
 | 
				
			||||||
 | 
					+        server = self.SingleConnectionTestServerThread(
 | 
				
			||||||
 | 
					+                call_after_accept=call_after_accept,
 | 
				
			||||||
 | 
					+                name="preauth_data_to_tls_server")
 | 
				
			||||||
 | 
					+        server.__enter__()  # starts it
 | 
				
			||||||
 | 
					+        self.addCleanup(server.__exit__)  # ... & unittest.TestCase stops it.
 | 
				
			||||||
 | 
					+
 | 
				
			||||||
 | 
					+        with socket.socket() as client:
 | 
				
			||||||
 | 
					+            client.connect(server.listener.getsockname())
 | 
				
			||||||
 | 
					+            # This forces an immediate connection close via RST on .close().
 | 
				
			||||||
 | 
					+            set_socket_so_linger_on_with_zero_timeout(client)
 | 
				
			||||||
 | 
					+            client.setblocking(False)
 | 
				
			||||||
 | 
					+
 | 
				
			||||||
 | 
					+            server_accept_called.wait()
 | 
				
			||||||
 | 
					+            client.send(b"DELETE /data HTTP/1.0\r\n\r\n")
 | 
				
			||||||
 | 
					+            client.close()  # RST
 | 
				
			||||||
 | 
					+
 | 
				
			||||||
 | 
					+        ready_for_server_wrap_socket.set()
 | 
				
			||||||
 | 
					+        server.join()
 | 
				
			||||||
 | 
					+        wrap_error = server.wrap_error
 | 
				
			||||||
 | 
					+        self.assertEqual(b"", server.received_data)
 | 
				
			||||||
 | 
					+        self.assertIsInstance(wrap_error, OSError)  # All platforms.
 | 
				
			||||||
 | 
					+        self.non_linux_skip_if_other_okay_error(wrap_error)
 | 
				
			||||||
 | 
					+        self.assertIsInstance(wrap_error, ssl.SSLError)
 | 
				
			||||||
 | 
					+        self.assertIn("before TLS handshake with data", wrap_error.args[1])
 | 
				
			||||||
 | 
					+        self.assertIn("before TLS handshake with data", wrap_error.reason)
 | 
				
			||||||
 | 
					+        self.assertNotEqual(0, wrap_error.args[0])
 | 
				
			||||||
 | 
					+        self.assertIsNone(wrap_error.library, msg="attr must exist")
 | 
				
			||||||
 | 
					+
 | 
				
			||||||
 | 
					+    def test_preauth_data_to_tls_client(self):
 | 
				
			||||||
 | 
					+        client_can_continue_with_wrap_socket = threading.Event()
 | 
				
			||||||
 | 
					+
 | 
				
			||||||
 | 
					+        def call_after_accept(conn_to_client):
 | 
				
			||||||
 | 
					+            # This forces an immediate connection close via RST on .close().
 | 
				
			||||||
 | 
					+            set_socket_so_linger_on_with_zero_timeout(conn_to_client)
 | 
				
			||||||
 | 
					+            conn_to_client.send(
 | 
				
			||||||
 | 
					+                    b"HTTP/1.0 307 Temporary Redirect\r\n"
 | 
				
			||||||
 | 
					+                    b"Location: https://example.com/someone-elses-server\r\n"
 | 
				
			||||||
 | 
					+                    b"\r\n")
 | 
				
			||||||
 | 
					+            conn_to_client.close()  # RST
 | 
				
			||||||
 | 
					+            client_can_continue_with_wrap_socket.set()
 | 
				
			||||||
 | 
					+            return True  # Tell the server to stop.
 | 
				
			||||||
 | 
					+
 | 
				
			||||||
 | 
					+        server = self.SingleConnectionTestServerThread(
 | 
				
			||||||
 | 
					+                call_after_accept=call_after_accept,
 | 
				
			||||||
 | 
					+                name="preauth_data_to_tls_client")
 | 
				
			||||||
 | 
					+        server.__enter__()  # starts it
 | 
				
			||||||
 | 
					+        self.addCleanup(server.__exit__)  # ... & unittest.TestCase stops it.
 | 
				
			||||||
 | 
					+
 | 
				
			||||||
 | 
					+        # Redundant; call_after_accept sets SO_LINGER on the accepted conn.
 | 
				
			||||||
 | 
					+        set_socket_so_linger_on_with_zero_timeout(server.listener)
 | 
				
			||||||
 | 
					+
 | 
				
			||||||
 | 
					+        with socket.socket() as client:
 | 
				
			||||||
 | 
					+            client.connect(server.listener.getsockname())
 | 
				
			||||||
 | 
					+            if not client_can_continue_with_wrap_socket.wait(2.0):
 | 
				
			||||||
 | 
					+                self.fail("test server took too long.")
 | 
				
			||||||
 | 
					+            ssl_ctx = ssl.create_default_context()
 | 
				
			||||||
 | 
					+            try:
 | 
				
			||||||
 | 
					+                tls_client = ssl_ctx.wrap_socket(
 | 
				
			||||||
 | 
					+                        client, server_hostname="localhost")
 | 
				
			||||||
 | 
					+            except OSError as err:  # SSLError inherits from OSError
 | 
				
			||||||
 | 
					+                wrap_error = err
 | 
				
			||||||
 | 
					+                received_data = b""
 | 
				
			||||||
 | 
					+            else:
 | 
				
			||||||
 | 
					+                wrap_error = None
 | 
				
			||||||
 | 
					+                received_data = tls_client.recv(400)
 | 
				
			||||||
 | 
					+                tls_client.close()
 | 
				
			||||||
 | 
					+
 | 
				
			||||||
 | 
					+        server.join()
 | 
				
			||||||
 | 
					+        self.assertEqual(b"", received_data)
 | 
				
			||||||
 | 
					+        self.assertIsInstance(wrap_error, OSError)  # All platforms.
 | 
				
			||||||
 | 
					+        self.non_linux_skip_if_other_okay_error(wrap_error)
 | 
				
			||||||
 | 
					+        self.assertIsInstance(wrap_error, ssl.SSLError)
 | 
				
			||||||
 | 
					+        self.assertIn("before TLS handshake with data", wrap_error.args[1])
 | 
				
			||||||
 | 
					+        self.assertIn("before TLS handshake with data", wrap_error.reason)
 | 
				
			||||||
 | 
					+        self.assertNotEqual(0, wrap_error.args[0])
 | 
				
			||||||
 | 
					+        self.assertIsNone(wrap_error.library, msg="attr must exist")
 | 
				
			||||||
 | 
					+
 | 
				
			||||||
 | 
					+    def test_https_client_non_tls_response_ignored(self):
 | 
				
			||||||
 | 
					+
 | 
				
			||||||
 | 
					+        server_responding = threading.Event()
 | 
				
			||||||
 | 
					+
 | 
				
			||||||
 | 
					+        class SynchronizedHTTPSConnection(http.client.HTTPSConnection):
 | 
				
			||||||
 | 
					+            def connect(self):
 | 
				
			||||||
 | 
					+                http.client.HTTPConnection.connect(self)
 | 
				
			||||||
 | 
					+                # Wait for our fault injection server to have done its thing.
 | 
				
			||||||
 | 
					+                if not server_responding.wait(1.0) and support.verbose:
 | 
				
			||||||
 | 
					+                    sys.stdout.write("server_responding event never set.")
 | 
				
			||||||
 | 
					+                self.sock = self._context.wrap_socket(
 | 
				
			||||||
 | 
					+                        self.sock, server_hostname=self.host)
 | 
				
			||||||
 | 
					+
 | 
				
			||||||
 | 
					+        def call_after_accept(conn_to_client):
 | 
				
			||||||
 | 
					+            # This forces an immediate connection close via RST on .close().
 | 
				
			||||||
 | 
					+            set_socket_so_linger_on_with_zero_timeout(conn_to_client)
 | 
				
			||||||
 | 
					+            conn_to_client.send(
 | 
				
			||||||
 | 
					+                    b"HTTP/1.0 402 Payment Required\r\n"
 | 
				
			||||||
 | 
					+                    b"\r\n")
 | 
				
			||||||
 | 
					+            conn_to_client.close()  # RST
 | 
				
			||||||
 | 
					+            server_responding.set()
 | 
				
			||||||
 | 
					+            return True  # Tell the server to stop.
 | 
				
			||||||
 | 
					+
 | 
				
			||||||
 | 
					+        server = self.SingleConnectionTestServerThread(
 | 
				
			||||||
 | 
					+                call_after_accept=call_after_accept,
 | 
				
			||||||
 | 
					+                name="non_tls_http_RST_responder")
 | 
				
			||||||
 | 
					+        server.__enter__()  # starts it
 | 
				
			||||||
 | 
					+        self.addCleanup(server.__exit__)  # ... & unittest.TestCase stops it.
 | 
				
			||||||
 | 
					+        # Redundant; call_after_accept sets SO_LINGER on the accepted conn.
 | 
				
			||||||
 | 
					+        set_socket_so_linger_on_with_zero_timeout(server.listener)
 | 
				
			||||||
 | 
					+
 | 
				
			||||||
 | 
					+        connection = SynchronizedHTTPSConnection(
 | 
				
			||||||
 | 
					+                f"localhost",
 | 
				
			||||||
 | 
					+                port=server.port,
 | 
				
			||||||
 | 
					+                context=ssl.create_default_context(),
 | 
				
			||||||
 | 
					+                timeout=2.0,
 | 
				
			||||||
 | 
					+        )
 | 
				
			||||||
 | 
					+        # There are lots of reasons this raises as desired, long before this
 | 
				
			||||||
 | 
					+        # test was added. Sending the request requires a successful TLS wrapped
 | 
				
			||||||
 | 
					+        # socket; that fails if the connection is broken. It may seem pointless
 | 
				
			||||||
 | 
					+        # to test this. It serves as an illustration of something that we never
 | 
				
			||||||
 | 
					+        # want to happen... properly not happening.
 | 
				
			||||||
 | 
					+        with self.assertRaises(OSError) as err_ctx:
 | 
				
			||||||
 | 
					+            connection.request("HEAD", "/test", headers={"Host": "localhost"})
 | 
				
			||||||
 | 
					+            response = connection.getresponse()
 | 
				
			||||||
 | 
					+
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					 def test_main(verbose=False):
 | 
				
			||||||
 | 
					     if support.verbose:
 | 
				
			||||||
 | 
					diff --git a/Misc/NEWS.d/next/Security/2023-08-22-17-39-12.gh-issue-108310.fVM3sg.rst b/Misc/NEWS.d/next/Security/2023-08-22-17-39-12.gh-issue-108310.fVM3sg.rst
 | 
				
			||||||
 | 
					new file mode 100644
 | 
				
			||||||
 | 
					index 0000000..403c77a
 | 
				
			||||||
 | 
					--- /dev/null
 | 
				
			||||||
 | 
					+++ b/Misc/NEWS.d/next/Security/2023-08-22-17-39-12.gh-issue-108310.fVM3sg.rst
 | 
				
			||||||
 | 
					@@ -0,0 +1,7 @@
 | 
				
			||||||
 | 
					+Fixed an issue where instances of :class:`ssl.SSLSocket` were vulnerable to
 | 
				
			||||||
 | 
					+a bypass of the TLS handshake and included protections (like certificate
 | 
				
			||||||
 | 
					+verification) and treating sent unencrypted data as if it were
 | 
				
			||||||
 | 
					+post-handshake TLS encrypted data.  Security issue reported as
 | 
				
			||||||
 | 
					+`CVE-2023-40217
 | 
				
			||||||
 | 
					+<https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-40217>`_ by
 | 
				
			||||||
 | 
					+Aapo Oksman. Patch by Gregory P. Smith.
 | 
				
			||||||
 | 
					-- 
 | 
				
			||||||
 | 
					2.41.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					From 6fbb37c0b7ab8ce1db8e2e78df62d6e5c1e56766 Mon Sep 17 00:00:00 2001
 | 
				
			||||||
 | 
					From: "Miss Islington (bot)"
 | 
				
			||||||
 | 
					 <31488909+miss-islington@users.noreply.github.com>
 | 
				
			||||||
 | 
					Date: Wed, 23 Aug 2023 03:10:56 -0700
 | 
				
			||||||
 | 
					Subject: [PATCH 2/4] gh-108342: Break ref cycle in SSLSocket._create() exc
 | 
				
			||||||
 | 
					 (GH-108344) (#108352)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Explicitly break a reference cycle when SSLSocket._create() raises an
 | 
				
			||||||
 | 
					exception. Clear the variable storing the exception, since the
 | 
				
			||||||
 | 
					exception traceback contains the variables and so creates a reference
 | 
				
			||||||
 | 
					cycle.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This test leak was introduced by the test added for the fix of GH-108310.
 | 
				
			||||||
 | 
					(cherry picked from commit 64f99350351bc46e016b2286f36ba7cd669b79e3)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Co-authored-by: Victor Stinner <vstinner@python.org>
 | 
				
			||||||
 | 
					---
 | 
				
			||||||
 | 
					 Lib/ssl.py | 6 +++++-
 | 
				
			||||||
 | 
					 1 file changed, 5 insertions(+), 1 deletion(-)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					diff --git a/Lib/ssl.py b/Lib/ssl.py
 | 
				
			||||||
 | 
					index 288f237..67869c9 100644
 | 
				
			||||||
 | 
					--- a/Lib/ssl.py
 | 
				
			||||||
 | 
					+++ b/Lib/ssl.py
 | 
				
			||||||
 | 
					@@ -782,7 +782,11 @@ class SSLSocket(socket):
 | 
				
			||||||
 | 
					                     self.close()
 | 
				
			||||||
 | 
					                 except OSError:
 | 
				
			||||||
 | 
					                     pass
 | 
				
			||||||
 | 
					-                raise notconn_pre_handshake_data_error
 | 
				
			||||||
 | 
					+                try:
 | 
				
			||||||
 | 
					+                    raise notconn_pre_handshake_data_error
 | 
				
			||||||
 | 
					+                finally:
 | 
				
			||||||
 | 
					+                    # Explicitly break the reference cycle.
 | 
				
			||||||
 | 
					+                    notconn_pre_handshake_data_error = None
 | 
				
			||||||
 | 
					         else:
 | 
				
			||||||
 | 
					             connected = True
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					-- 
 | 
				
			||||||
 | 
					2.41.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					From 579d809e60e569f06c00844cc3a3f06a0e359603 Mon Sep 17 00:00:00 2001
 | 
				
			||||||
 | 
					From: =?UTF-8?q?=C5=81ukasz=20Langa?= <lukasz@langa.pl>
 | 
				
			||||||
 | 
					Date: Thu, 24 Aug 2023 12:09:30 +0200
 | 
				
			||||||
 | 
					Subject: [PATCH 3/4] gh-108342: Make ssl TestPreHandshakeClose more reliable
 | 
				
			||||||
 | 
					 (GH-108370) (#108408)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* In preauth tests of test_ssl, explicitly break reference cycles
 | 
				
			||||||
 | 
					  invoving SingleConnectionTestServerThread to make sure that the
 | 
				
			||||||
 | 
					  thread is deleted. Otherwise, the test marks the environment as
 | 
				
			||||||
 | 
					  altered because the threading module sees a "dangling thread"
 | 
				
			||||||
 | 
					  (SingleConnectionTestServerThread). This test leak was introduced
 | 
				
			||||||
 | 
					  by the test added for the fix of issue gh-108310.
 | 
				
			||||||
 | 
					* Use support.SHORT_TIMEOUT instead of hardcoded 1.0 or 2.0 seconds
 | 
				
			||||||
 | 
					  timeout.
 | 
				
			||||||
 | 
					* SingleConnectionTestServerThread.run() catchs TimeoutError
 | 
				
			||||||
 | 
					* Fix a race condition (missing synchronization) in
 | 
				
			||||||
 | 
					  test_preauth_data_to_tls_client(): the server now waits until the
 | 
				
			||||||
 | 
					  client connect() completed in call_after_accept().
 | 
				
			||||||
 | 
					* test_https_client_non_tls_response_ignored() calls server.join()
 | 
				
			||||||
 | 
					  explicitly.
 | 
				
			||||||
 | 
					* Replace "localhost" with server.listener.getsockname()[0].
 | 
				
			||||||
 | 
					(cherry picked from commit 592bacb6fc0833336c0453e818e9b95016e9fd47)
 | 
				
			||||||
 | 
					---
 | 
				
			||||||
 | 
					 Lib/test/test_ssl.py | 102 ++++++++++++++++++++++++++++++-------------
 | 
				
			||||||
 | 
					 1 file changed, 71 insertions(+), 31 deletions(-)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py
 | 
				
			||||||
 | 
					index e24d11b..6332330 100644
 | 
				
			||||||
 | 
					--- a/Lib/test/test_ssl.py
 | 
				
			||||||
 | 
					+++ b/Lib/test/test_ssl.py
 | 
				
			||||||
 | 
					@@ -3953,12 +3953,16 @@ class TestPreHandshakeClose(unittest.TestCase):
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					     class SingleConnectionTestServerThread(threading.Thread):
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					-        def __init__(self, *, name, call_after_accept):
 | 
				
			||||||
 | 
					+        def __init__(self, *, name, call_after_accept, timeout=None):
 | 
				
			||||||
 | 
					             self.call_after_accept = call_after_accept
 | 
				
			||||||
 | 
					             self.received_data = b''  # set by .run()
 | 
				
			||||||
 | 
					             self.wrap_error = None  # set by .run()
 | 
				
			||||||
 | 
					             self.listener = None  # set by .start()
 | 
				
			||||||
 | 
					             self.port = None  # set by .start()
 | 
				
			||||||
 | 
					+            if timeout is None:
 | 
				
			||||||
 | 
					+                self.timeout = support.SHORT_TIMEOUT
 | 
				
			||||||
 | 
					+            else:
 | 
				
			||||||
 | 
					+                self.timeout = timeout
 | 
				
			||||||
 | 
					             super().__init__(name=name)
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					         def __enter__(self):
 | 
				
			||||||
 | 
					@@ -3981,13 +3985,19 @@ class TestPreHandshakeClose(unittest.TestCase):
 | 
				
			||||||
 | 
					             self.ssl_ctx.load_cert_chain(certfile=ONLYCERT, keyfile=ONLYKEY)
 | 
				
			||||||
 | 
					             self.listener = socket.socket()
 | 
				
			||||||
 | 
					             self.port = support.bind_port(self.listener)
 | 
				
			||||||
 | 
					-            self.listener.settimeout(2.0)
 | 
				
			||||||
 | 
					+            self.listener.settimeout(self.timeout)
 | 
				
			||||||
 | 
					             self.listener.listen(1)
 | 
				
			||||||
 | 
					             super().start()
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					         def run(self):
 | 
				
			||||||
 | 
					-            conn, address = self.listener.accept()
 | 
				
			||||||
 | 
					-            self.listener.close()
 | 
				
			||||||
 | 
					+            try:
 | 
				
			||||||
 | 
					+                conn, address = self.listener.accept()
 | 
				
			||||||
 | 
					+            except TimeoutError:
 | 
				
			||||||
 | 
					+                # on timeout, just close the listener
 | 
				
			||||||
 | 
					+                return
 | 
				
			||||||
 | 
					+            finally:
 | 
				
			||||||
 | 
					+                self.listener.close()
 | 
				
			||||||
 | 
					+
 | 
				
			||||||
 | 
					             with conn:
 | 
				
			||||||
 | 
					                 if self.call_after_accept(conn):
 | 
				
			||||||
 | 
					                     return
 | 
				
			||||||
 | 
					@@ -4015,8 +4025,13 @@ class TestPreHandshakeClose(unittest.TestCase):
 | 
				
			||||||
 | 
					             # we're specifically trying to test. The way this test is written
 | 
				
			||||||
 | 
					             # is known to work on Linux. We'll skip it anywhere else that it
 | 
				
			||||||
 | 
					             # does not present as doing so.
 | 
				
			||||||
 | 
					-            self.skipTest("Could not recreate conditions on {}: \
 | 
				
			||||||
 | 
					-                          err={}".format(sys.platform,err))
 | 
				
			||||||
 | 
					+            try:
 | 
				
			||||||
 | 
					+                self.skipTest("Could not recreate conditions on {}: \
 | 
				
			||||||
 | 
					+                              err={}".format(sys.platform,err))
 | 
				
			||||||
 | 
					+            finally:
 | 
				
			||||||
 | 
					+                # gh-108342: Explicitly break the reference cycle
 | 
				
			||||||
 | 
					+                err = None
 | 
				
			||||||
 | 
					+
 | 
				
			||||||
 | 
					         # If maintaining this conditional winds up being a problem.
 | 
				
			||||||
 | 
					         # just turn this into an unconditional skip anything but Linux.
 | 
				
			||||||
 | 
					         # The important thing is that our CI has the logic covered.
 | 
				
			||||||
 | 
					@@ -4027,7 +4042,7 @@ class TestPreHandshakeClose(unittest.TestCase):
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					         def call_after_accept(unused):
 | 
				
			||||||
 | 
					             server_accept_called.set()
 | 
				
			||||||
 | 
					-            if not ready_for_server_wrap_socket.wait(2.0):
 | 
				
			||||||
 | 
					+            if not ready_for_server_wrap_socket.wait(support.SHORT_TIMEOUT):
 | 
				
			||||||
 | 
					                 raise RuntimeError("wrap_socket event never set, test may fail.")
 | 
				
			||||||
 | 
					             return False  # Tell the server thread to continue.
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					@@ -4049,20 +4064,31 @@ class TestPreHandshakeClose(unittest.TestCase):
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					         ready_for_server_wrap_socket.set()
 | 
				
			||||||
 | 
					         server.join()
 | 
				
			||||||
 | 
					+
 | 
				
			||||||
 | 
					         wrap_error = server.wrap_error
 | 
				
			||||||
 | 
					-        self.assertEqual(b"", server.received_data)
 | 
				
			||||||
 | 
					-        self.assertIsInstance(wrap_error, OSError)  # All platforms.
 | 
				
			||||||
 | 
					-        self.non_linux_skip_if_other_okay_error(wrap_error)
 | 
				
			||||||
 | 
					-        self.assertIsInstance(wrap_error, ssl.SSLError)
 | 
				
			||||||
 | 
					-        self.assertIn("before TLS handshake with data", wrap_error.args[1])
 | 
				
			||||||
 | 
					-        self.assertIn("before TLS handshake with data", wrap_error.reason)
 | 
				
			||||||
 | 
					-        self.assertNotEqual(0, wrap_error.args[0])
 | 
				
			||||||
 | 
					-        self.assertIsNone(wrap_error.library, msg="attr must exist")
 | 
				
			||||||
 | 
					+        server.wrap_error = None
 | 
				
			||||||
 | 
					+        try:
 | 
				
			||||||
 | 
					+            self.assertEqual(b"", server.received_data)
 | 
				
			||||||
 | 
					+            self.assertIsInstance(wrap_error, OSError)  # All platforms.
 | 
				
			||||||
 | 
					+            self.non_linux_skip_if_other_okay_error(wrap_error)
 | 
				
			||||||
 | 
					+            self.assertIsInstance(wrap_error, ssl.SSLError)
 | 
				
			||||||
 | 
					+            self.assertIn("before TLS handshake with data", wrap_error.args[1])
 | 
				
			||||||
 | 
					+            self.assertIn("before TLS handshake with data", wrap_error.reason)
 | 
				
			||||||
 | 
					+            self.assertNotEqual(0, wrap_error.args[0])
 | 
				
			||||||
 | 
					+            self.assertIsNone(wrap_error.library, msg="attr must exist")
 | 
				
			||||||
 | 
					+        finally:
 | 
				
			||||||
 | 
					+            # gh-108342: Explicitly break the reference cycle
 | 
				
			||||||
 | 
					+            wrap_error = None
 | 
				
			||||||
 | 
					+            server = None
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					     def test_preauth_data_to_tls_client(self):
 | 
				
			||||||
 | 
					+        server_can_continue_with_wrap_socket = threading.Event()
 | 
				
			||||||
 | 
					         client_can_continue_with_wrap_socket = threading.Event()
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					         def call_after_accept(conn_to_client):
 | 
				
			||||||
 | 
					+            if not server_can_continue_with_wrap_socket.wait(support.SHORT_TIMEOUT):
 | 
				
			||||||
 | 
					+                print("ERROR: test client took too long")
 | 
				
			||||||
 | 
					+
 | 
				
			||||||
 | 
					             # This forces an immediate connection close via RST on .close().
 | 
				
			||||||
 | 
					             set_socket_so_linger_on_with_zero_timeout(conn_to_client)
 | 
				
			||||||
 | 
					             conn_to_client.send(
 | 
				
			||||||
 | 
					@@ -4084,8 +4110,10 @@ class TestPreHandshakeClose(unittest.TestCase):
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					         with socket.socket() as client:
 | 
				
			||||||
 | 
					             client.connect(server.listener.getsockname())
 | 
				
			||||||
 | 
					-            if not client_can_continue_with_wrap_socket.wait(2.0):
 | 
				
			||||||
 | 
					-                self.fail("test server took too long.")
 | 
				
			||||||
 | 
					+            server_can_continue_with_wrap_socket.set()
 | 
				
			||||||
 | 
					+
 | 
				
			||||||
 | 
					+            if not client_can_continue_with_wrap_socket.wait(support.SHORT_TIMEOUT):
 | 
				
			||||||
 | 
					+                self.fail("test server took too long")
 | 
				
			||||||
 | 
					             ssl_ctx = ssl.create_default_context()
 | 
				
			||||||
 | 
					             try:
 | 
				
			||||||
 | 
					                 tls_client = ssl_ctx.wrap_socket(
 | 
				
			||||||
 | 
					@@ -4099,24 +4127,31 @@ class TestPreHandshakeClose(unittest.TestCase):
 | 
				
			||||||
 | 
					                 tls_client.close()
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					         server.join()
 | 
				
			||||||
 | 
					-        self.assertEqual(b"", received_data)
 | 
				
			||||||
 | 
					-        self.assertIsInstance(wrap_error, OSError)  # All platforms.
 | 
				
			||||||
 | 
					-        self.non_linux_skip_if_other_okay_error(wrap_error)
 | 
				
			||||||
 | 
					-        self.assertIsInstance(wrap_error, ssl.SSLError)
 | 
				
			||||||
 | 
					-        self.assertIn("before TLS handshake with data", wrap_error.args[1])
 | 
				
			||||||
 | 
					-        self.assertIn("before TLS handshake with data", wrap_error.reason)
 | 
				
			||||||
 | 
					-        self.assertNotEqual(0, wrap_error.args[0])
 | 
				
			||||||
 | 
					-        self.assertIsNone(wrap_error.library, msg="attr must exist")
 | 
				
			||||||
 | 
					+        try:
 | 
				
			||||||
 | 
					+            self.assertEqual(b"", received_data)
 | 
				
			||||||
 | 
					+            self.assertIsInstance(wrap_error, OSError)  # All platforms.
 | 
				
			||||||
 | 
					+            self.non_linux_skip_if_other_okay_error(wrap_error)
 | 
				
			||||||
 | 
					+            self.assertIsInstance(wrap_error, ssl.SSLError)
 | 
				
			||||||
 | 
					+            self.assertIn("before TLS handshake with data", wrap_error.args[1])
 | 
				
			||||||
 | 
					+            self.assertIn("before TLS handshake with data", wrap_error.reason)
 | 
				
			||||||
 | 
					+            self.assertNotEqual(0, wrap_error.args[0])
 | 
				
			||||||
 | 
					+            self.assertIsNone(wrap_error.library, msg="attr must exist")
 | 
				
			||||||
 | 
					+        finally:
 | 
				
			||||||
 | 
					+            # gh-108342: Explicitly break the reference cycle
 | 
				
			||||||
 | 
					+            wrap_error = None
 | 
				
			||||||
 | 
					+            server = None
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					     def test_https_client_non_tls_response_ignored(self):
 | 
				
			||||||
 | 
					-
 | 
				
			||||||
 | 
					         server_responding = threading.Event()
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					         class SynchronizedHTTPSConnection(http.client.HTTPSConnection):
 | 
				
			||||||
 | 
					             def connect(self):
 | 
				
			||||||
 | 
					+                # Call clear text HTTP connect(), not the encrypted HTTPS (TLS)
 | 
				
			||||||
 | 
					+                # connect(): wrap_socket() is called manually below.
 | 
				
			||||||
 | 
					                 http.client.HTTPConnection.connect(self)
 | 
				
			||||||
 | 
					+
 | 
				
			||||||
 | 
					                 # Wait for our fault injection server to have done its thing.
 | 
				
			||||||
 | 
					-                if not server_responding.wait(1.0) and support.verbose:
 | 
				
			||||||
 | 
					+                if not server_responding.wait(support.SHORT_TIMEOUT) and support.verbose:
 | 
				
			||||||
 | 
					                     sys.stdout.write("server_responding event never set.")
 | 
				
			||||||
 | 
					                 self.sock = self._context.wrap_socket(
 | 
				
			||||||
 | 
					                         self.sock, server_hostname=self.host)
 | 
				
			||||||
 | 
					@@ -4131,29 +4166,34 @@ class TestPreHandshakeClose(unittest.TestCase):
 | 
				
			||||||
 | 
					             server_responding.set()
 | 
				
			||||||
 | 
					             return True  # Tell the server to stop.
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					+        timeout = 2.0
 | 
				
			||||||
 | 
					         server = self.SingleConnectionTestServerThread(
 | 
				
			||||||
 | 
					                 call_after_accept=call_after_accept,
 | 
				
			||||||
 | 
					-                name="non_tls_http_RST_responder")
 | 
				
			||||||
 | 
					+                name="non_tls_http_RST_responder",
 | 
				
			||||||
 | 
					+                timeout=timeout)
 | 
				
			||||||
 | 
					         server.__enter__()  # starts it
 | 
				
			||||||
 | 
					         self.addCleanup(server.__exit__)  # ... & unittest.TestCase stops it.
 | 
				
			||||||
 | 
					         # Redundant; call_after_accept sets SO_LINGER on the accepted conn.
 | 
				
			||||||
 | 
					         set_socket_so_linger_on_with_zero_timeout(server.listener)
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					         connection = SynchronizedHTTPSConnection(
 | 
				
			||||||
 | 
					-                f"localhost",
 | 
				
			||||||
 | 
					+                server.listener.getsockname()[0],
 | 
				
			||||||
 | 
					                 port=server.port,
 | 
				
			||||||
 | 
					                 context=ssl.create_default_context(),
 | 
				
			||||||
 | 
					-                timeout=2.0,
 | 
				
			||||||
 | 
					+                timeout=timeout,
 | 
				
			||||||
 | 
					         )
 | 
				
			||||||
 | 
					+
 | 
				
			||||||
 | 
					         # There are lots of reasons this raises as desired, long before this
 | 
				
			||||||
 | 
					         # test was added. Sending the request requires a successful TLS wrapped
 | 
				
			||||||
 | 
					         # socket; that fails if the connection is broken. It may seem pointless
 | 
				
			||||||
 | 
					         # to test this. It serves as an illustration of something that we never
 | 
				
			||||||
 | 
					         # want to happen... properly not happening.
 | 
				
			||||||
 | 
					-        with self.assertRaises(OSError) as err_ctx:
 | 
				
			||||||
 | 
					+        with self.assertRaises(OSError):
 | 
				
			||||||
 | 
					             connection.request("HEAD", "/test", headers={"Host": "localhost"})
 | 
				
			||||||
 | 
					             response = connection.getresponse()
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					+        server.join()
 | 
				
			||||||
 | 
					+
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					 def test_main(verbose=False):
 | 
				
			||||||
 | 
					     if support.verbose:
 | 
				
			||||||
 | 
					-- 
 | 
				
			||||||
 | 
					2.41.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					From 2e8776245e9fb8ede784077df26684b4b53df0bc Mon Sep 17 00:00:00 2001
 | 
				
			||||||
 | 
					From: Charalampos Stratakis <cstratak@redhat.com>
 | 
				
			||||||
 | 
					Date: Mon, 25 Sep 2023 21:55:29 +0200
 | 
				
			||||||
 | 
					Subject: [PATCH 4/4] Downstream: Additional fixup for 3.6:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Use alternative for self.getblocking(), which was added in Python 3.7
 | 
				
			||||||
 | 
					see: https://docs.python.org/3/library/socket.html#socket.socket.getblocking
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Set self._sslobj early to avoid AttributeError
 | 
				
			||||||
 | 
					---
 | 
				
			||||||
 | 
					 Lib/ssl.py | 3 ++-
 | 
				
			||||||
 | 
					 1 file changed, 2 insertions(+), 1 deletion(-)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					diff --git a/Lib/ssl.py b/Lib/ssl.py
 | 
				
			||||||
 | 
					index 67869c9..daedc82 100644
 | 
				
			||||||
 | 
					--- a/Lib/ssl.py
 | 
				
			||||||
 | 
					+++ b/Lib/ssl.py
 | 
				
			||||||
 | 
					@@ -690,6 +690,7 @@ class SSLSocket(socket):
 | 
				
			||||||
 | 
					                  suppress_ragged_eofs=True, npn_protocols=None, ciphers=None,
 | 
				
			||||||
 | 
					                  server_hostname=None,
 | 
				
			||||||
 | 
					                  _context=None, _session=None):
 | 
				
			||||||
 | 
					+        self._sslobj = None
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					         if _context:
 | 
				
			||||||
 | 
					             self._context = _context
 | 
				
			||||||
 | 
					@@ -755,7 +756,7 @@ class SSLSocket(socket):
 | 
				
			||||||
 | 
					             if e.errno != errno.ENOTCONN:
 | 
				
			||||||
 | 
					                 raise
 | 
				
			||||||
 | 
					             connected = False
 | 
				
			||||||
 | 
					-            blocking = self.getblocking()
 | 
				
			||||||
 | 
					+            blocking = (self.gettimeout() != 0)
 | 
				
			||||||
 | 
					             self.setblocking(False)
 | 
				
			||||||
 | 
					             try:
 | 
				
			||||||
 | 
					                 # We are not connected so this is not supposed to block, but
 | 
				
			||||||
 | 
					-- 
 | 
				
			||||||
 | 
					2.41.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -1,6 +1,7 @@
 | 
				
			|||||||
# ==================
 | 
					# ==================
 | 
				
			||||||
# Top-level metadata
 | 
					# Top-level metadata
 | 
				
			||||||
# ==================
 | 
					# ==================
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Name: python3
 | 
					Name: python3
 | 
				
			||||||
Summary: Interpreter of the Python programming language
 | 
					Summary: Interpreter of the Python programming language
 | 
				
			||||||
URL: https://www.python.org/
 | 
					URL: https://www.python.org/
 | 
				
			||||||
@ -13,7 +14,7 @@ URL: https://www.python.org/
 | 
				
			|||||||
#  WARNING  When rebasing to a new Python version,
 | 
					#  WARNING  When rebasing to a new Python version,
 | 
				
			||||||
#           remember to update the python3-docs package as well
 | 
					#           remember to update the python3-docs package as well
 | 
				
			||||||
Version: %{pybasever}.8
 | 
					Version: %{pybasever}.8
 | 
				
			||||||
Release: 51%{?dist}.1.alma
 | 
					Release: 51%{?dist}.2.alma.1
 | 
				
			||||||
License: Python
 | 
					License: Python
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -776,6 +777,18 @@ Patch394: 00394-cve-2022-45061-cpu-denial-of-service-via-inefficient-idna-decode
 | 
				
			|||||||
# Backported from Python 3.12
 | 
					# Backported from Python 3.12
 | 
				
			||||||
Patch399: 00399-cve-2023-24329.patch
 | 
					Patch399: 00399-cve-2023-24329.patch
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# 00404 #
 | 
				
			||||||
 | 
					# CVE-2023-40217
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Security fix for CVE-2023-40217: Bypass TLS handshake on closed sockets
 | 
				
			||||||
 | 
					# Resolved upstream: https://github.com/python/cpython/issues/108310
 | 
				
			||||||
 | 
					# Fixups added on top:
 | 
				
			||||||
 | 
					# https://github.com/python/cpython/pull/108352
 | 
				
			||||||
 | 
					# https://github.com/python/cpython/pull/108408
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Backported from Python 3.8
 | 
				
			||||||
 | 
					Patch404: 00404-cve-2023-40217.patch
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# (New patches go here ^^^)
 | 
					# (New patches go here ^^^)
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
# When adding new patches to "python" and "python3" in Fedora, EL, etc.,
 | 
					# When adding new patches to "python" and "python3" in Fedora, EL, etc.,
 | 
				
			||||||
@ -1123,6 +1136,7 @@ git apply %{PATCH351}
 | 
				
			|||||||
%patch387 -p1
 | 
					%patch387 -p1
 | 
				
			||||||
%patch394 -p1
 | 
					%patch394 -p1
 | 
				
			||||||
%patch399 -p1
 | 
					%patch399 -p1
 | 
				
			||||||
 | 
					%patch404 -p1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
%patch1000 -p1
 | 
					%patch1000 -p1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -2056,11 +2070,16 @@ fi
 | 
				
			|||||||
# ======================================================
 | 
					# ======================================================
 | 
				
			||||||
 | 
					
 | 
				
			||||||
%changelog
 | 
					%changelog
 | 
				
			||||||
* Thu Jun 22 2023 Andrew Lukoshko <alukoshko@almalinux.org> - 3.6.8-51.1.alma
 | 
					* Tue Oct 24 2023 Andrew Lukoshko <alukoshko@almalinux.org> - 3.6.8-51.2.alma.1
 | 
				
			||||||
- Add AlmaLinux to supported distros
 | 
					- Add AlmaLinux to supported distros
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* Wed Sep 27 2023 Masahiro Matsuya <mmatsuya@redhat.com> - 3.6.8-51.2
 | 
				
			||||||
 | 
					- Security fix for CVE-2023-40217
 | 
				
			||||||
 | 
					Resolves: RHEL-2933
 | 
				
			||||||
 | 
					
 | 
				
			||||||
* Wed May 31 2023 Charalampos Stratakis <cstratak@redhat.com> - 3.6.8-51.1
 | 
					* Wed May 31 2023 Charalampos Stratakis <cstratak@redhat.com> - 3.6.8-51.1
 | 
				
			||||||
- Security fix for CVE-2023-24329
 | 
					- Security fix for CVE-2023-24329
 | 
				
			||||||
 | 
					Resolves: rhbz#2173917
 | 
				
			||||||
 | 
					
 | 
				
			||||||
* Tue Jan 24 2023 Charalampos Stratakis <cstratak@redhat.com> - 3.6.8-51
 | 
					* Tue Jan 24 2023 Charalampos Stratakis <cstratak@redhat.com> - 3.6.8-51
 | 
				
			||||||
- Properly strip the LTO bytecode from python.o
 | 
					- Properly strip the LTO bytecode from python.o
 | 
				
			||||||
@ -2082,6 +2101,7 @@ Resolves: rhbz#2136435
 | 
				
			|||||||
* Tue Jun 14 2022 Charalampos Stratakis <cstratak@redhat.com> - 3.6.8-47
 | 
					* Tue Jun 14 2022 Charalampos Stratakis <cstratak@redhat.com> - 3.6.8-47
 | 
				
			||||||
- Security fix for CVE-2015-20107
 | 
					- Security fix for CVE-2015-20107
 | 
				
			||||||
Resolves: rhbz#2075390
 | 
					Resolves: rhbz#2075390
 | 
				
			||||||
 | 
					
 | 
				
			||||||
* Wed Mar 09 2022 Charalampos Stratakis <cstratak@redhat.com> - 3.6.8-46
 | 
					* Wed Mar 09 2022 Charalampos Stratakis <cstratak@redhat.com> - 3.6.8-46
 | 
				
			||||||
- Security fix for CVE-2022-0391: urlparse does not sanitize URLs containing ASCII newline and tabs
 | 
					- Security fix for CVE-2022-0391: urlparse does not sanitize URLs containing ASCII newline and tabs
 | 
				
			||||||
- Fix the test suite support for Expat >= 2.4.5
 | 
					- Fix the test suite support for Expat >= 2.4.5
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user