mirror of
https://github.com/python/cpython.git
synced 2025-08-28 12:45:07 +00:00
gh-113280: Always close socket if SSLSocket creation failed (GH-114659)
Co-authored-by: Thomas Grainger <tagrain@gmail.com>
This commit is contained in:
parent
ecabff98c4
commit
0ea366240b
3 changed files with 81 additions and 67 deletions
15
Lib/ssl.py
15
Lib/ssl.py
|
@ -994,15 +994,16 @@ class SSLSocket(socket):
|
||||||
if context.check_hostname and not server_hostname:
|
if context.check_hostname and not server_hostname:
|
||||||
raise ValueError("check_hostname requires server_hostname")
|
raise ValueError("check_hostname requires server_hostname")
|
||||||
|
|
||||||
|
sock_timeout = sock.gettimeout()
|
||||||
kwargs = dict(
|
kwargs = dict(
|
||||||
family=sock.family, type=sock.type, proto=sock.proto,
|
family=sock.family, type=sock.type, proto=sock.proto,
|
||||||
fileno=sock.fileno()
|
fileno=sock.fileno()
|
||||||
)
|
)
|
||||||
self = cls.__new__(cls, **kwargs)
|
self = cls.__new__(cls, **kwargs)
|
||||||
super(SSLSocket, self).__init__(**kwargs)
|
super(SSLSocket, self).__init__(**kwargs)
|
||||||
sock_timeout = sock.gettimeout()
|
|
||||||
sock.detach()
|
sock.detach()
|
||||||
|
# Now SSLSocket is responsible for closing the file descriptor.
|
||||||
|
try:
|
||||||
self._context = context
|
self._context = context
|
||||||
self._session = session
|
self._session = session
|
||||||
self._closed = False
|
self._closed = False
|
||||||
|
@ -1042,10 +1043,6 @@ class SSLSocket(socket):
|
||||||
# Add the SSLError attributes that _ssl.c always adds.
|
# Add the SSLError attributes that _ssl.c always adds.
|
||||||
notconn_pre_handshake_data_error.reason = reason
|
notconn_pre_handshake_data_error.reason = reason
|
||||||
notconn_pre_handshake_data_error.library = None
|
notconn_pre_handshake_data_error.library = None
|
||||||
try:
|
|
||||||
self.close()
|
|
||||||
except OSError:
|
|
||||||
pass
|
|
||||||
try:
|
try:
|
||||||
raise notconn_pre_handshake_data_error
|
raise notconn_pre_handshake_data_error
|
||||||
finally:
|
finally:
|
||||||
|
@ -1058,7 +1055,6 @@ class SSLSocket(socket):
|
||||||
self._connected = connected
|
self._connected = connected
|
||||||
if connected:
|
if connected:
|
||||||
# create the SSL object
|
# create the SSL object
|
||||||
try:
|
|
||||||
self._sslobj = self._context._wrap_socket(
|
self._sslobj = self._context._wrap_socket(
|
||||||
self, server_side, self.server_hostname,
|
self, server_side, self.server_hostname,
|
||||||
owner=self, session=self._session,
|
owner=self, session=self._session,
|
||||||
|
@ -1069,8 +1065,11 @@ class SSLSocket(socket):
|
||||||
# non-blocking
|
# non-blocking
|
||||||
raise ValueError("do_handshake_on_connect should not be specified for non-blocking sockets")
|
raise ValueError("do_handshake_on_connect should not be specified for non-blocking sockets")
|
||||||
self.do_handshake()
|
self.do_handshake()
|
||||||
except (OSError, ValueError):
|
except:
|
||||||
|
try:
|
||||||
self.close()
|
self.close()
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
raise
|
raise
|
||||||
return self
|
return self
|
||||||
|
|
||||||
|
|
|
@ -2206,6 +2206,7 @@ def _test_get_server_certificate(test, host, port, cert=None):
|
||||||
sys.stdout.write("\nVerified certificate for %s:%s is\n%s\n" % (host, port ,pem))
|
sys.stdout.write("\nVerified certificate for %s:%s is\n%s\n" % (host, port ,pem))
|
||||||
|
|
||||||
def _test_get_server_certificate_fail(test, host, port):
|
def _test_get_server_certificate_fail(test, host, port):
|
||||||
|
with warnings_helper.check_no_resource_warning(test):
|
||||||
try:
|
try:
|
||||||
pem = ssl.get_server_certificate((host, port), ca_certs=CERTFILE)
|
pem = ssl.get_server_certificate((host, port), ca_certs=CERTFILE)
|
||||||
except ssl.SSLError as x:
|
except ssl.SSLError as x:
|
||||||
|
@ -3026,6 +3027,16 @@ class ThreadedTests(unittest.TestCase):
|
||||||
server_hostname="python.example.org") as s:
|
server_hostname="python.example.org") as s:
|
||||||
with self.assertRaises(ssl.CertificateError):
|
with self.assertRaises(ssl.CertificateError):
|
||||||
s.connect((HOST, server.port))
|
s.connect((HOST, server.port))
|
||||||
|
with ThreadedEchoServer(context=server_context, chatty=True) as server:
|
||||||
|
with warnings_helper.check_no_resource_warning(self):
|
||||||
|
with self.assertRaises(UnicodeError):
|
||||||
|
context.wrap_socket(socket.socket(),
|
||||||
|
server_hostname='.pythontest.net')
|
||||||
|
with ThreadedEchoServer(context=server_context, chatty=True) as server:
|
||||||
|
with warnings_helper.check_no_resource_warning(self):
|
||||||
|
with self.assertRaises(UnicodeDecodeError):
|
||||||
|
context.wrap_socket(socket.socket(),
|
||||||
|
server_hostname=b'k\xf6nig.idn.pythontest.net')
|
||||||
|
|
||||||
def test_wrong_cert_tls12(self):
|
def test_wrong_cert_tls12(self):
|
||||||
"""Connecting when the server rejects the client's certificate
|
"""Connecting when the server rejects the client's certificate
|
||||||
|
@ -4983,6 +4994,7 @@ class TestPreHandshakeClose(unittest.TestCase):
|
||||||
self.assertIsNone(wrap_error.library, msg="attr must exist")
|
self.assertIsNone(wrap_error.library, msg="attr must exist")
|
||||||
finally:
|
finally:
|
||||||
# gh-108342: Explicitly break the reference cycle
|
# gh-108342: Explicitly break the reference cycle
|
||||||
|
with warnings_helper.check_no_resource_warning(self):
|
||||||
wrap_error = None
|
wrap_error = None
|
||||||
server = None
|
server = None
|
||||||
|
|
||||||
|
@ -5032,7 +5044,8 @@ class TestPreHandshakeClose(unittest.TestCase):
|
||||||
# socket; that fails if the connection is broken. It may seem pointless
|
# 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
|
# to test this. It serves as an illustration of something that we never
|
||||||
# want to happen... properly not happening.
|
# want to happen... properly not happening.
|
||||||
with self.assertRaises(OSError):
|
with warnings_helper.check_no_resource_warning(self), \
|
||||||
|
self.assertRaises(OSError):
|
||||||
connection.request("HEAD", "/test", headers={"Host": "localhost"})
|
connection.request("HEAD", "/test", headers={"Host": "localhost"})
|
||||||
response = connection.getresponse()
|
response = connection.getresponse()
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
Fix a leak of open socket in rare cases when error occurred in
|
||||||
|
:class:`ssl.SSLSocket` creation.
|
Loading…
Add table
Add a link
Reference in a new issue