mirror of
https://github.com/python/cpython.git
synced 2025-10-06 15:11:58 +00:00
[3.13] gh-124984: Enhance ssl
thread safety (GH-124993) (#125780)
Make SSL objects thread safe in Free Theaded build by
using critical sections.
(cherry picked from commit 4c53b25775
)
Co-authored-by: Peter Bierma <zintensitydev@gmail.com>
Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com>
This commit is contained in:
parent
d9ac6b3ef7
commit
b1051577de
4 changed files with 1700 additions and 247 deletions
|
@ -3,6 +3,8 @@
|
||||||
import sys
|
import sys
|
||||||
import unittest
|
import unittest
|
||||||
import unittest.mock
|
import unittest.mock
|
||||||
|
from ast import literal_eval
|
||||||
|
from threading import Thread
|
||||||
from test import support
|
from test import support
|
||||||
from test.support import import_helper
|
from test.support import import_helper
|
||||||
from test.support import os_helper
|
from test.support import os_helper
|
||||||
|
@ -304,11 +306,19 @@ def test_wrap_socket(sock, *,
|
||||||
return context.wrap_socket(sock, **kwargs)
|
return context.wrap_socket(sock, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
USE_SAME_TEST_CONTEXT = False
|
||||||
|
_TEST_CONTEXT = None
|
||||||
|
|
||||||
def testing_context(server_cert=SIGNED_CERTFILE, *, server_chain=True):
|
def testing_context(server_cert=SIGNED_CERTFILE, *, server_chain=True):
|
||||||
"""Create context
|
"""Create context
|
||||||
|
|
||||||
client_context, server_context, hostname = testing_context()
|
client_context, server_context, hostname = testing_context()
|
||||||
"""
|
"""
|
||||||
|
global _TEST_CONTEXT
|
||||||
|
if USE_SAME_TEST_CONTEXT:
|
||||||
|
if _TEST_CONTEXT is not None:
|
||||||
|
return _TEST_CONTEXT
|
||||||
|
|
||||||
if server_cert == SIGNED_CERTFILE:
|
if server_cert == SIGNED_CERTFILE:
|
||||||
hostname = SIGNED_CERTFILE_HOSTNAME
|
hostname = SIGNED_CERTFILE_HOSTNAME
|
||||||
elif server_cert == SIGNED_CERTFILE2:
|
elif server_cert == SIGNED_CERTFILE2:
|
||||||
|
@ -326,6 +336,10 @@ def testing_context(server_cert=SIGNED_CERTFILE, *, server_chain=True):
|
||||||
if server_chain:
|
if server_chain:
|
||||||
server_context.load_verify_locations(SIGNING_CA)
|
server_context.load_verify_locations(SIGNING_CA)
|
||||||
|
|
||||||
|
if USE_SAME_TEST_CONTEXT:
|
||||||
|
if _TEST_CONTEXT is not None:
|
||||||
|
_TEST_CONTEXT = client_context, server_context, hostname
|
||||||
|
|
||||||
return client_context, server_context, hostname
|
return client_context, server_context, hostname
|
||||||
|
|
||||||
|
|
||||||
|
@ -2834,6 +2848,44 @@ class ThreadedTests(unittest.TestCase):
|
||||||
'Cannot create a client socket with a PROTOCOL_TLS_SERVER context',
|
'Cannot create a client socket with a PROTOCOL_TLS_SERVER context',
|
||||||
str(e.exception))
|
str(e.exception))
|
||||||
|
|
||||||
|
@unittest.skipUnless(support.Py_GIL_DISABLED, "test is only useful if the GIL is disabled")
|
||||||
|
def test_ssl_in_multiple_threads(self):
|
||||||
|
# See GH-124984: OpenSSL is not thread safe.
|
||||||
|
threads = []
|
||||||
|
|
||||||
|
global USE_SAME_TEST_CONTEXT
|
||||||
|
USE_SAME_TEST_CONTEXT = True
|
||||||
|
try:
|
||||||
|
for func in (
|
||||||
|
self.test_echo,
|
||||||
|
self.test_alpn_protocols,
|
||||||
|
self.test_getpeercert,
|
||||||
|
self.test_crl_check,
|
||||||
|
self.test_check_hostname_idn,
|
||||||
|
self.test_wrong_cert_tls12,
|
||||||
|
self.test_wrong_cert_tls13,
|
||||||
|
):
|
||||||
|
# Be careful with the number of threads here.
|
||||||
|
# Too many can result in failing tests.
|
||||||
|
for num in range(5):
|
||||||
|
with self.subTest(func=func, num=num):
|
||||||
|
threads.append(Thread(target=func))
|
||||||
|
|
||||||
|
with threading_helper.catch_threading_exception() as cm:
|
||||||
|
for thread in threads:
|
||||||
|
with self.subTest(thread=thread):
|
||||||
|
thread.start()
|
||||||
|
|
||||||
|
for thread in threads:
|
||||||
|
with self.subTest(thread=thread):
|
||||||
|
thread.join()
|
||||||
|
if cm.exc_value is not None:
|
||||||
|
# Some threads can skip their test
|
||||||
|
if not isinstance(cm.exc_value, unittest.SkipTest):
|
||||||
|
raise cm.exc_value
|
||||||
|
finally:
|
||||||
|
USE_SAME_TEST_CONTEXT = False
|
||||||
|
|
||||||
def test_getpeercert(self):
|
def test_getpeercert(self):
|
||||||
if support.verbose:
|
if support.verbose:
|
||||||
sys.stdout.write("\n")
|
sys.stdout.write("\n")
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Fixed thread safety in :mod:`ssl` in the free-threaded build. OpenSSL operations are now protected by a per-object lock.
|
693
Modules/_ssl.c
693
Modules/_ssl.c
File diff suppressed because it is too large
Load diff
1201
Modules/clinic/_ssl.c.h
generated
1201
Modules/clinic/_ssl.c.h
generated
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue