From 17723a58f59145d774afc66018129e437518cdaf Mon Sep 17 00:00:00 2001 From: ordinary-jamie <101677823+ordinary-jamie@users.noreply.github.com> Date: Mon, 15 Jan 2024 18:47:41 +1100 Subject: [PATCH 1/2] gh-109534: fix reference leak when SSL handshake fails --- Lib/asyncio/selector_events.py | 4 ++++ Lib/asyncio/sslproto.py | 18 +++++++----------- ...4-01-15-18-42-44.gh-issue-109534.wYaLMZ.rst | 3 +++ 3 files changed, 14 insertions(+), 11 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2024-01-15-18-42-44.gh-issue-109534.wYaLMZ.rst diff --git a/Lib/asyncio/selector_events.py b/Lib/asyncio/selector_events.py index dcd5e0aa345029..10fbdd76e93f79 100644 --- a/Lib/asyncio/selector_events.py +++ b/Lib/asyncio/selector_events.py @@ -235,6 +235,10 @@ async def _accept_connection2( await waiter except BaseException: transport.close() + # gh-109534: When an exception is raised by the SSLProtocol object the + # exception set in this future can keep the protocol object alive and + # cause a reference cycle. + waiter = None raise # It's now up to the protocol to handle the connection. diff --git a/Lib/asyncio/sslproto.py b/Lib/asyncio/sslproto.py index 599e91ba0003d1..4781651e88a7ab 100644 --- a/Lib/asyncio/sslproto.py +++ b/Lib/asyncio/sslproto.py @@ -461,7 +461,7 @@ def eof_received(self): logger.debug("%r received EOF", self) if self._state == SSLProtocolState.DO_HANDSHAKE: - self._on_handshake_complete(ConnectionResetError) + self._on_handshake_complete(ConnectionResetError()) elif self._state == SSLProtocolState.WRAPPED: self._set_state(SSLProtocolState.FLUSHING) @@ -571,21 +571,17 @@ def _on_handshake_complete(self, handshake_exc): self._handshake_timeout_handle = None sslobj = self._sslobj - try: - if handshake_exc is None: - self._set_state(SSLProtocolState.WRAPPED) - else: - raise handshake_exc - + if handshake_exc is None: + self._set_state(SSLProtocolState.WRAPPED) peercert = sslobj.getpeercert() - except Exception as exc: + else: self._set_state(SSLProtocolState.UNWRAPPED) - if isinstance(exc, ssl.CertificateError): + if isinstance(handshake_exc, ssl.CertificateError): msg = 'SSL handshake failed on verifying the certificate' else: msg = 'SSL handshake failed' - self._fatal_error(exc, msg) - self._wakeup_waiter(exc) + self._fatal_error(handshake_exc, msg) + self._wakeup_waiter(handshake_exc) return if self._loop.get_debug(): diff --git a/Misc/NEWS.d/next/Library/2024-01-15-18-42-44.gh-issue-109534.wYaLMZ.rst b/Misc/NEWS.d/next/Library/2024-01-15-18-42-44.gh-issue-109534.wYaLMZ.rst new file mode 100644 index 00000000000000..fc9a765a230037 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-01-15-18-42-44.gh-issue-109534.wYaLMZ.rst @@ -0,0 +1,3 @@ +Fix a reference leak in +:class:`asyncio.selector_events.BaseSelectorEventLoop` when SSL handshakes +fail. Patch contributed by Jamie Phan. From e77579de6705a7bb590c179dc37d4d752878c0d4 Mon Sep 17 00:00:00 2001 From: ordinary-jamie <101677823+ordinary-jamie@users.noreply.github.com> Date: Tue, 16 Jan 2024 06:52:09 +1100 Subject: [PATCH 2/2] Revert _on_handshake_complete changes and clear exception ref --- Lib/asyncio/sslproto.py | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/Lib/asyncio/sslproto.py b/Lib/asyncio/sslproto.py index 4781651e88a7ab..fa99d4533aa0a6 100644 --- a/Lib/asyncio/sslproto.py +++ b/Lib/asyncio/sslproto.py @@ -461,7 +461,7 @@ def eof_received(self): logger.debug("%r received EOF", self) if self._state == SSLProtocolState.DO_HANDSHAKE: - self._on_handshake_complete(ConnectionResetError()) + self._on_handshake_complete(ConnectionResetError) elif self._state == SSLProtocolState.WRAPPED: self._set_state(SSLProtocolState.FLUSHING) @@ -571,17 +571,22 @@ def _on_handshake_complete(self, handshake_exc): self._handshake_timeout_handle = None sslobj = self._sslobj - if handshake_exc is None: - self._set_state(SSLProtocolState.WRAPPED) + try: + if handshake_exc is None: + self._set_state(SSLProtocolState.WRAPPED) + else: + raise handshake_exc + peercert = sslobj.getpeercert() - else: + except Exception as exc: + handshake_exc = None self._set_state(SSLProtocolState.UNWRAPPED) - if isinstance(handshake_exc, ssl.CertificateError): + if isinstance(exc, ssl.CertificateError): msg = 'SSL handshake failed on verifying the certificate' else: msg = 'SSL handshake failed' - self._fatal_error(handshake_exc, msg) - self._wakeup_waiter(handshake_exc) + self._fatal_error(exc, msg) + self._wakeup_waiter(exc) return if self._loop.get_debug(): pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy