mirror of
https://github.com/python/cpython.git
synced 2025-12-31 04:23:37 +00:00
[3.14] gh-134698: Hold a lock when the thread state is detached in ssl (GH-134724) (GH-137107)
* [3.14] gh-134698: Hold a lock when the thread state is detached in `ssl` (GH-134724)
Lock when the thread state is detached.
(cherry picked from commit e047a35b23)
Co-authored-by: Peter Bierma <zintensitydev@gmail.com>
Co-authored-by: Gregory P. Smith <greg@krypto.org>
* Only lock the SSL context, not the SSL socket.
This solves a deadlock when a socket is blocked while waiting on data,
which ended up causing a major regression in 3.13.6 (see gh-137583).
---------
Co-authored-by: Peter Bierma <zintensitydev@gmail.com>
This commit is contained in:
parent
ed9c0c3cbe
commit
e51acb3fa6
4 changed files with 123 additions and 48 deletions
|
|
@ -1239,6 +1239,25 @@ def getpass(self):
|
||||||
# Make sure the password function isn't called if it isn't needed
|
# Make sure the password function isn't called if it isn't needed
|
||||||
ctx.load_cert_chain(CERTFILE, password=getpass_exception)
|
ctx.load_cert_chain(CERTFILE, password=getpass_exception)
|
||||||
|
|
||||||
|
@threading_helper.requires_working_threading()
|
||||||
|
def test_load_cert_chain_thread_safety(self):
|
||||||
|
# gh-134698: _ssl detaches the thread state (and as such,
|
||||||
|
# releases the GIL and critical sections) around expensive
|
||||||
|
# OpenSSL calls. Unfortunately, OpenSSL structures aren't
|
||||||
|
# thread-safe, so executing these calls concurrently led
|
||||||
|
# to crashes.
|
||||||
|
ctx = ssl.create_default_context()
|
||||||
|
|
||||||
|
def race():
|
||||||
|
ctx.load_cert_chain(CERTFILE)
|
||||||
|
|
||||||
|
threads = [threading.Thread(target=race) for _ in range(8)]
|
||||||
|
with threading_helper.catch_threading_exception() as cm:
|
||||||
|
with threading_helper.start_threads(threads):
|
||||||
|
pass
|
||||||
|
|
||||||
|
self.assertIsNone(cm.exc_value)
|
||||||
|
|
||||||
def test_load_verify_locations(self):
|
def test_load_verify_locations(self):
|
||||||
ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
|
ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
|
||||||
ctx.load_verify_locations(CERTFILE)
|
ctx.load_verify_locations(CERTFILE)
|
||||||
|
|
@ -4538,6 +4557,42 @@ def server_callback(identity):
|
||||||
with client_context.wrap_socket(socket.socket()) as s:
|
with client_context.wrap_socket(socket.socket()) as s:
|
||||||
s.connect((HOST, server.port))
|
s.connect((HOST, server.port))
|
||||||
|
|
||||||
|
def test_thread_recv_while_main_thread_sends(self):
|
||||||
|
# GH-137583: Locking was added to calls to send() and recv() on SSL
|
||||||
|
# socket objects. This seemed fine at the surface level because those
|
||||||
|
# calls weren't re-entrant, but recv() calls would implicitly mimick
|
||||||
|
# holding a lock by blocking until it received data. This means that
|
||||||
|
# if a thread started to infinitely block until data was received, calls
|
||||||
|
# to send() would deadlock, because it would wait forever on the lock
|
||||||
|
# that the recv() call held.
|
||||||
|
data = b"1" * 1024
|
||||||
|
event = threading.Event()
|
||||||
|
def background(sock):
|
||||||
|
event.set()
|
||||||
|
received = sock.recv(len(data))
|
||||||
|
self.assertEqual(received, data)
|
||||||
|
|
||||||
|
client_context, server_context, hostname = testing_context()
|
||||||
|
server = ThreadedEchoServer(context=server_context)
|
||||||
|
with server:
|
||||||
|
with client_context.wrap_socket(socket.socket(),
|
||||||
|
server_hostname=hostname) as sock:
|
||||||
|
sock.connect((HOST, server.port))
|
||||||
|
sock.settimeout(1)
|
||||||
|
sock.setblocking(1)
|
||||||
|
# Ensure that the server is ready to accept requests
|
||||||
|
sock.sendall(b"123")
|
||||||
|
self.assertEqual(sock.recv(3), b"123")
|
||||||
|
with threading_helper.catch_threading_exception() as cm:
|
||||||
|
thread = threading.Thread(target=background,
|
||||||
|
args=(sock,), daemon=True)
|
||||||
|
thread.start()
|
||||||
|
event.wait()
|
||||||
|
sock.sendall(data)
|
||||||
|
thread.join()
|
||||||
|
if cm.exc_value is not None:
|
||||||
|
raise cm.exc_value
|
||||||
|
|
||||||
|
|
||||||
@unittest.skipUnless(has_tls_version('TLSv1_3') and ssl.HAS_PHA,
|
@unittest.skipUnless(has_tls_version('TLSv1_3') and ssl.HAS_PHA,
|
||||||
"Test needs TLS 1.3 PHA")
|
"Test needs TLS 1.3 PHA")
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
Fix a crash when calling methods of :class:`ssl.SSLContext` or
|
||||||
|
:class:`ssl.SSLSocket` across multiple threads.
|
||||||
100
Modules/_ssl.c
100
Modules/_ssl.c
|
|
@ -43,14 +43,14 @@
|
||||||
/* Redefined below for Windows debug builds after important #includes */
|
/* Redefined below for Windows debug builds after important #includes */
|
||||||
#define _PySSL_FIX_ERRNO
|
#define _PySSL_FIX_ERRNO
|
||||||
|
|
||||||
#define PySSL_BEGIN_ALLOW_THREADS_S(save) \
|
#define PySSL_BEGIN_ALLOW_THREADS_S(save, mutex) \
|
||||||
do { (save) = PyEval_SaveThread(); } while(0)
|
do { (save) = PyEval_SaveThread(); PyMutex_Lock(mutex); } while(0)
|
||||||
#define PySSL_END_ALLOW_THREADS_S(save) \
|
#define PySSL_END_ALLOW_THREADS_S(save, mutex) \
|
||||||
do { PyEval_RestoreThread(save); _PySSL_FIX_ERRNO; } while(0)
|
do { PyMutex_Unlock(mutex); PyEval_RestoreThread(save); _PySSL_FIX_ERRNO; } while(0)
|
||||||
#define PySSL_BEGIN_ALLOW_THREADS { \
|
#define PySSL_BEGIN_ALLOW_THREADS(self) { \
|
||||||
PyThreadState *_save = NULL; \
|
PyThreadState *_save = NULL; \
|
||||||
PySSL_BEGIN_ALLOW_THREADS_S(_save);
|
PySSL_BEGIN_ALLOW_THREADS_S(_save, &self->tstate_mutex);
|
||||||
#define PySSL_END_ALLOW_THREADS PySSL_END_ALLOW_THREADS_S(_save); }
|
#define PySSL_END_ALLOW_THREADS(self) PySSL_END_ALLOW_THREADS_S(_save, &self->tstate_mutex); }
|
||||||
|
|
||||||
#if defined(HAVE_POLL_H)
|
#if defined(HAVE_POLL_H)
|
||||||
#include <poll.h>
|
#include <poll.h>
|
||||||
|
|
@ -309,6 +309,9 @@ typedef struct {
|
||||||
PyObject *psk_client_callback;
|
PyObject *psk_client_callback;
|
||||||
PyObject *psk_server_callback;
|
PyObject *psk_server_callback;
|
||||||
#endif
|
#endif
|
||||||
|
/* Lock to synchronize calls when the thread state is detached.
|
||||||
|
See also gh-134698. */
|
||||||
|
PyMutex tstate_mutex;
|
||||||
} PySSLContext;
|
} PySSLContext;
|
||||||
|
|
||||||
#define PySSLContext_CAST(op) ((PySSLContext *)(op))
|
#define PySSLContext_CAST(op) ((PySSLContext *)(op))
|
||||||
|
|
@ -889,9 +892,9 @@ newPySSLSocket(PySSLContext *sslctx, PySocketSockObject *sock,
|
||||||
/* Make sure the SSL error state is initialized */
|
/* Make sure the SSL error state is initialized */
|
||||||
ERR_clear_error();
|
ERR_clear_error();
|
||||||
|
|
||||||
PySSL_BEGIN_ALLOW_THREADS
|
PySSL_BEGIN_ALLOW_THREADS(sslctx)
|
||||||
self->ssl = SSL_new(ctx);
|
self->ssl = SSL_new(ctx);
|
||||||
PySSL_END_ALLOW_THREADS
|
PySSL_END_ALLOW_THREADS(sslctx)
|
||||||
if (self->ssl == NULL) {
|
if (self->ssl == NULL) {
|
||||||
Py_DECREF(self);
|
Py_DECREF(self);
|
||||||
_setSSLError(get_state_ctx(self), NULL, 0, __FILE__, __LINE__);
|
_setSSLError(get_state_ctx(self), NULL, 0, __FILE__, __LINE__);
|
||||||
|
|
@ -960,12 +963,12 @@ newPySSLSocket(PySSLContext *sslctx, PySocketSockObject *sock,
|
||||||
BIO_set_nbio(SSL_get_wbio(self->ssl), 1);
|
BIO_set_nbio(SSL_get_wbio(self->ssl), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
PySSL_BEGIN_ALLOW_THREADS
|
Py_BEGIN_ALLOW_THREADS;
|
||||||
if (socket_type == PY_SSL_CLIENT)
|
if (socket_type == PY_SSL_CLIENT)
|
||||||
SSL_set_connect_state(self->ssl);
|
SSL_set_connect_state(self->ssl);
|
||||||
else
|
else
|
||||||
SSL_set_accept_state(self->ssl);
|
SSL_set_accept_state(self->ssl);
|
||||||
PySSL_END_ALLOW_THREADS
|
Py_END_ALLOW_THREADS;
|
||||||
|
|
||||||
self->socket_type = socket_type;
|
self->socket_type = socket_type;
|
||||||
if (sock != NULL) {
|
if (sock != NULL) {
|
||||||
|
|
@ -1034,10 +1037,11 @@ _ssl__SSLSocket_do_handshake_impl(PySSLSocket *self)
|
||||||
/* Actually negotiate SSL connection */
|
/* Actually negotiate SSL connection */
|
||||||
/* XXX If SSL_do_handshake() returns 0, it's also a failure. */
|
/* XXX If SSL_do_handshake() returns 0, it's also a failure. */
|
||||||
do {
|
do {
|
||||||
PySSL_BEGIN_ALLOW_THREADS
|
Py_BEGIN_ALLOW_THREADS
|
||||||
ret = SSL_do_handshake(self->ssl);
|
ret = SSL_do_handshake(self->ssl);
|
||||||
err = _PySSL_errno(ret < 1, self->ssl, ret);
|
err = _PySSL_errno(ret < 1, self->ssl, ret);
|
||||||
PySSL_END_ALLOW_THREADS
|
Py_END_ALLOW_THREADS;
|
||||||
|
_PySSL_FIX_ERRNO;
|
||||||
self->err = err;
|
self->err = err;
|
||||||
|
|
||||||
if (PyErr_CheckSignals())
|
if (PyErr_CheckSignals())
|
||||||
|
|
@ -2414,9 +2418,10 @@ PySSL_select(PySocketSockObject *s, int writing, PyTime_t timeout)
|
||||||
ms = (int)_PyTime_AsMilliseconds(timeout, _PyTime_ROUND_CEILING);
|
ms = (int)_PyTime_AsMilliseconds(timeout, _PyTime_ROUND_CEILING);
|
||||||
assert(ms <= INT_MAX);
|
assert(ms <= INT_MAX);
|
||||||
|
|
||||||
PySSL_BEGIN_ALLOW_THREADS
|
Py_BEGIN_ALLOW_THREADS
|
||||||
rc = poll(&pollfd, 1, (int)ms);
|
rc = poll(&pollfd, 1, (int)ms);
|
||||||
PySSL_END_ALLOW_THREADS
|
Py_END_ALLOW_THREADS
|
||||||
|
_PySSL_FIX_ERRNO;
|
||||||
#else
|
#else
|
||||||
/* Guard against socket too large for select*/
|
/* Guard against socket too large for select*/
|
||||||
if (!_PyIsSelectable_fd(s->sock_fd))
|
if (!_PyIsSelectable_fd(s->sock_fd))
|
||||||
|
|
@ -2428,13 +2433,14 @@ PySSL_select(PySocketSockObject *s, int writing, PyTime_t timeout)
|
||||||
FD_SET(s->sock_fd, &fds);
|
FD_SET(s->sock_fd, &fds);
|
||||||
|
|
||||||
/* Wait until the socket becomes ready */
|
/* Wait until the socket becomes ready */
|
||||||
PySSL_BEGIN_ALLOW_THREADS
|
Py_BEGIN_ALLOW_THREADS
|
||||||
nfds = Py_SAFE_DOWNCAST(s->sock_fd+1, SOCKET_T, int);
|
nfds = Py_SAFE_DOWNCAST(s->sock_fd+1, SOCKET_T, int);
|
||||||
if (writing)
|
if (writing)
|
||||||
rc = select(nfds, NULL, &fds, NULL, &tv);
|
rc = select(nfds, NULL, &fds, NULL, &tv);
|
||||||
else
|
else
|
||||||
rc = select(nfds, &fds, NULL, NULL, &tv);
|
rc = select(nfds, &fds, NULL, NULL, &tv);
|
||||||
PySSL_END_ALLOW_THREADS
|
Py_END_ALLOW_THREADS
|
||||||
|
_PySSL_FIX_ERRNO;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Return SOCKET_TIMED_OUT on timeout, SOCKET_OPERATION_OK otherwise
|
/* Return SOCKET_TIMED_OUT on timeout, SOCKET_OPERATION_OK otherwise
|
||||||
|
|
@ -2505,10 +2511,11 @@ _ssl__SSLSocket_write_impl(PySSLSocket *self, Py_buffer *b)
|
||||||
}
|
}
|
||||||
|
|
||||||
do {
|
do {
|
||||||
PySSL_BEGIN_ALLOW_THREADS
|
Py_BEGIN_ALLOW_THREADS;
|
||||||
retval = SSL_write_ex(self->ssl, b->buf, (size_t)b->len, &count);
|
retval = SSL_write_ex(self->ssl, b->buf, (size_t)b->len, &count);
|
||||||
err = _PySSL_errno(retval == 0, self->ssl, retval);
|
err = _PySSL_errno(retval == 0, self->ssl, retval);
|
||||||
PySSL_END_ALLOW_THREADS
|
Py_END_ALLOW_THREADS;
|
||||||
|
_PySSL_FIX_ERRNO;
|
||||||
self->err = err;
|
self->err = err;
|
||||||
|
|
||||||
if (PyErr_CheckSignals())
|
if (PyErr_CheckSignals())
|
||||||
|
|
@ -2566,10 +2573,11 @@ _ssl__SSLSocket_pending_impl(PySSLSocket *self)
|
||||||
int count = 0;
|
int count = 0;
|
||||||
_PySSLError err;
|
_PySSLError err;
|
||||||
|
|
||||||
PySSL_BEGIN_ALLOW_THREADS
|
Py_BEGIN_ALLOW_THREADS;
|
||||||
count = SSL_pending(self->ssl);
|
count = SSL_pending(self->ssl);
|
||||||
err = _PySSL_errno(count < 0, self->ssl, count);
|
err = _PySSL_errno(count < 0, self->ssl, count);
|
||||||
PySSL_END_ALLOW_THREADS
|
Py_END_ALLOW_THREADS;
|
||||||
|
_PySSL_FIX_ERRNO;
|
||||||
self->err = err;
|
self->err = err;
|
||||||
|
|
||||||
if (count < 0)
|
if (count < 0)
|
||||||
|
|
@ -2660,10 +2668,11 @@ _ssl__SSLSocket_read_impl(PySSLSocket *self, Py_ssize_t len,
|
||||||
deadline = _PyDeadline_Init(timeout);
|
deadline = _PyDeadline_Init(timeout);
|
||||||
|
|
||||||
do {
|
do {
|
||||||
PySSL_BEGIN_ALLOW_THREADS
|
Py_BEGIN_ALLOW_THREADS;
|
||||||
retval = SSL_read_ex(self->ssl, mem, (size_t)len, &count);
|
retval = SSL_read_ex(self->ssl, mem, (size_t)len, &count);
|
||||||
err = _PySSL_errno(retval == 0, self->ssl, retval);
|
err = _PySSL_errno(retval == 0, self->ssl, retval);
|
||||||
PySSL_END_ALLOW_THREADS
|
Py_END_ALLOW_THREADS;
|
||||||
|
_PySSL_FIX_ERRNO;
|
||||||
self->err = err;
|
self->err = err;
|
||||||
|
|
||||||
if (PyErr_CheckSignals())
|
if (PyErr_CheckSignals())
|
||||||
|
|
@ -2762,7 +2771,7 @@ _ssl__SSLSocket_shutdown_impl(PySSLSocket *self)
|
||||||
}
|
}
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
PySSL_BEGIN_ALLOW_THREADS
|
Py_BEGIN_ALLOW_THREADS;
|
||||||
/* Disable read-ahead so that unwrap can work correctly.
|
/* Disable read-ahead so that unwrap can work correctly.
|
||||||
* Otherwise OpenSSL might read in too much data,
|
* Otherwise OpenSSL might read in too much data,
|
||||||
* eating clear text data that happens to be
|
* eating clear text data that happens to be
|
||||||
|
|
@ -2775,7 +2784,8 @@ _ssl__SSLSocket_shutdown_impl(PySSLSocket *self)
|
||||||
SSL_set_read_ahead(self->ssl, 0);
|
SSL_set_read_ahead(self->ssl, 0);
|
||||||
ret = SSL_shutdown(self->ssl);
|
ret = SSL_shutdown(self->ssl);
|
||||||
err = _PySSL_errno(ret < 0, self->ssl, ret);
|
err = _PySSL_errno(ret < 0, self->ssl, ret);
|
||||||
PySSL_END_ALLOW_THREADS
|
Py_END_ALLOW_THREADS;
|
||||||
|
_PySSL_FIX_ERRNO;
|
||||||
self->err = err;
|
self->err = err;
|
||||||
|
|
||||||
/* If err == 1, a secure shutdown with SSL_shutdown() is complete */
|
/* If err == 1, a secure shutdown with SSL_shutdown() is complete */
|
||||||
|
|
@ -3167,9 +3177,10 @@ _ssl__SSLContext_impl(PyTypeObject *type, int proto_version)
|
||||||
// no other thread can be touching this object yet.
|
// no other thread can be touching this object yet.
|
||||||
// (Technically, we can't even lock if we wanted to, as the
|
// (Technically, we can't even lock if we wanted to, as the
|
||||||
// lock hasn't been initialized yet.)
|
// lock hasn't been initialized yet.)
|
||||||
PySSL_BEGIN_ALLOW_THREADS
|
Py_BEGIN_ALLOW_THREADS
|
||||||
ctx = SSL_CTX_new(method);
|
ctx = SSL_CTX_new(method);
|
||||||
PySSL_END_ALLOW_THREADS
|
Py_END_ALLOW_THREADS
|
||||||
|
_PySSL_FIX_ERRNO;
|
||||||
|
|
||||||
if (ctx == NULL) {
|
if (ctx == NULL) {
|
||||||
_setSSLError(get_ssl_state(module), NULL, 0, __FILE__, __LINE__);
|
_setSSLError(get_ssl_state(module), NULL, 0, __FILE__, __LINE__);
|
||||||
|
|
@ -3194,6 +3205,7 @@ _ssl__SSLContext_impl(PyTypeObject *type, int proto_version)
|
||||||
self->psk_client_callback = NULL;
|
self->psk_client_callback = NULL;
|
||||||
self->psk_server_callback = NULL;
|
self->psk_server_callback = NULL;
|
||||||
#endif
|
#endif
|
||||||
|
self->tstate_mutex = (PyMutex){0};
|
||||||
|
|
||||||
/* Don't check host name by default */
|
/* Don't check host name by default */
|
||||||
if (proto_version == PY_SSL_VERSION_TLS_CLIENT) {
|
if (proto_version == PY_SSL_VERSION_TLS_CLIENT) {
|
||||||
|
|
@ -3312,9 +3324,10 @@ context_clear(PyObject *op)
|
||||||
Py_CLEAR(self->psk_server_callback);
|
Py_CLEAR(self->psk_server_callback);
|
||||||
#endif
|
#endif
|
||||||
if (self->keylog_bio != NULL) {
|
if (self->keylog_bio != NULL) {
|
||||||
PySSL_BEGIN_ALLOW_THREADS
|
Py_BEGIN_ALLOW_THREADS
|
||||||
BIO_free_all(self->keylog_bio);
|
BIO_free_all(self->keylog_bio);
|
||||||
PySSL_END_ALLOW_THREADS
|
Py_END_ALLOW_THREADS
|
||||||
|
_PySSL_FIX_ERRNO;
|
||||||
self->keylog_bio = NULL;
|
self->keylog_bio = NULL;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -4037,7 +4050,8 @@ _password_callback(char *buf, int size, int rwflag, void *userdata)
|
||||||
_PySSLPasswordInfo *pw_info = (_PySSLPasswordInfo*) userdata;
|
_PySSLPasswordInfo *pw_info = (_PySSLPasswordInfo*) userdata;
|
||||||
PyObject *fn_ret = NULL;
|
PyObject *fn_ret = NULL;
|
||||||
|
|
||||||
PySSL_END_ALLOW_THREADS_S(pw_info->thread_state);
|
pw_info->thread_state = PyThreadState_Swap(pw_info->thread_state);
|
||||||
|
_PySSL_FIX_ERRNO;
|
||||||
|
|
||||||
if (pw_info->error) {
|
if (pw_info->error) {
|
||||||
/* already failed previously. OpenSSL 3.0.0-alpha14 invokes the
|
/* already failed previously. OpenSSL 3.0.0-alpha14 invokes the
|
||||||
|
|
@ -4067,13 +4081,13 @@ _password_callback(char *buf, int size, int rwflag, void *userdata)
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
PySSL_BEGIN_ALLOW_THREADS_S(pw_info->thread_state);
|
pw_info->thread_state = PyThreadState_Swap(pw_info->thread_state);
|
||||||
memcpy(buf, pw_info->password, pw_info->size);
|
memcpy(buf, pw_info->password, pw_info->size);
|
||||||
return pw_info->size;
|
return pw_info->size;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
Py_XDECREF(fn_ret);
|
Py_XDECREF(fn_ret);
|
||||||
PySSL_BEGIN_ALLOW_THREADS_S(pw_info->thread_state);
|
pw_info->thread_state = PyThreadState_Swap(pw_info->thread_state);
|
||||||
pw_info->error = 1;
|
pw_info->error = 1;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
@ -4126,10 +4140,10 @@ _ssl__SSLContext_load_cert_chain_impl(PySSLContext *self, PyObject *certfile,
|
||||||
SSL_CTX_set_default_passwd_cb(self->ctx, _password_callback);
|
SSL_CTX_set_default_passwd_cb(self->ctx, _password_callback);
|
||||||
SSL_CTX_set_default_passwd_cb_userdata(self->ctx, &pw_info);
|
SSL_CTX_set_default_passwd_cb_userdata(self->ctx, &pw_info);
|
||||||
}
|
}
|
||||||
PySSL_BEGIN_ALLOW_THREADS_S(pw_info.thread_state);
|
PySSL_BEGIN_ALLOW_THREADS_S(pw_info.thread_state, &self->tstate_mutex);
|
||||||
r = SSL_CTX_use_certificate_chain_file(self->ctx,
|
r = SSL_CTX_use_certificate_chain_file(self->ctx,
|
||||||
PyBytes_AS_STRING(certfile_bytes));
|
PyBytes_AS_STRING(certfile_bytes));
|
||||||
PySSL_END_ALLOW_THREADS_S(pw_info.thread_state);
|
PySSL_END_ALLOW_THREADS_S(pw_info.thread_state, &self->tstate_mutex);
|
||||||
if (r != 1) {
|
if (r != 1) {
|
||||||
if (pw_info.error) {
|
if (pw_info.error) {
|
||||||
ERR_clear_error();
|
ERR_clear_error();
|
||||||
|
|
@ -4144,11 +4158,11 @@ _ssl__SSLContext_load_cert_chain_impl(PySSLContext *self, PyObject *certfile,
|
||||||
}
|
}
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
PySSL_BEGIN_ALLOW_THREADS_S(pw_info.thread_state);
|
PySSL_BEGIN_ALLOW_THREADS_S(pw_info.thread_state, &self->tstate_mutex);
|
||||||
r = SSL_CTX_use_PrivateKey_file(self->ctx,
|
r = SSL_CTX_use_PrivateKey_file(self->ctx,
|
||||||
PyBytes_AS_STRING(keyfile ? keyfile_bytes : certfile_bytes),
|
PyBytes_AS_STRING(keyfile ? keyfile_bytes : certfile_bytes),
|
||||||
SSL_FILETYPE_PEM);
|
SSL_FILETYPE_PEM);
|
||||||
PySSL_END_ALLOW_THREADS_S(pw_info.thread_state);
|
PySSL_END_ALLOW_THREADS_S(pw_info.thread_state, &self->tstate_mutex);
|
||||||
Py_CLEAR(keyfile_bytes);
|
Py_CLEAR(keyfile_bytes);
|
||||||
Py_CLEAR(certfile_bytes);
|
Py_CLEAR(certfile_bytes);
|
||||||
if (r != 1) {
|
if (r != 1) {
|
||||||
|
|
@ -4165,9 +4179,9 @@ _ssl__SSLContext_load_cert_chain_impl(PySSLContext *self, PyObject *certfile,
|
||||||
}
|
}
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
PySSL_BEGIN_ALLOW_THREADS_S(pw_info.thread_state);
|
PySSL_BEGIN_ALLOW_THREADS_S(pw_info.thread_state, &self->tstate_mutex);
|
||||||
r = SSL_CTX_check_private_key(self->ctx);
|
r = SSL_CTX_check_private_key(self->ctx);
|
||||||
PySSL_END_ALLOW_THREADS_S(pw_info.thread_state);
|
PySSL_END_ALLOW_THREADS_S(pw_info.thread_state, &self->tstate_mutex);
|
||||||
if (r != 1) {
|
if (r != 1) {
|
||||||
_setSSLError(get_state_ctx(self), NULL, 0, __FILE__, __LINE__);
|
_setSSLError(get_state_ctx(self), NULL, 0, __FILE__, __LINE__);
|
||||||
goto error;
|
goto error;
|
||||||
|
|
@ -4384,9 +4398,9 @@ _ssl__SSLContext_load_verify_locations_impl(PySSLContext *self,
|
||||||
cafile_buf = PyBytes_AS_STRING(cafile_bytes);
|
cafile_buf = PyBytes_AS_STRING(cafile_bytes);
|
||||||
if (capath)
|
if (capath)
|
||||||
capath_buf = PyBytes_AS_STRING(capath_bytes);
|
capath_buf = PyBytes_AS_STRING(capath_bytes);
|
||||||
PySSL_BEGIN_ALLOW_THREADS
|
PySSL_BEGIN_ALLOW_THREADS(self)
|
||||||
r = SSL_CTX_load_verify_locations(self->ctx, cafile_buf, capath_buf);
|
r = SSL_CTX_load_verify_locations(self->ctx, cafile_buf, capath_buf);
|
||||||
PySSL_END_ALLOW_THREADS
|
PySSL_END_ALLOW_THREADS(self)
|
||||||
if (r != 1) {
|
if (r != 1) {
|
||||||
if (errno != 0) {
|
if (errno != 0) {
|
||||||
PyErr_SetFromErrno(PyExc_OSError);
|
PyErr_SetFromErrno(PyExc_OSError);
|
||||||
|
|
@ -4438,10 +4452,11 @@ _ssl__SSLContext_load_dh_params_impl(PySSLContext *self, PyObject *filepath)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
errno = 0;
|
errno = 0;
|
||||||
PySSL_BEGIN_ALLOW_THREADS
|
Py_BEGIN_ALLOW_THREADS
|
||||||
dh = PEM_read_DHparams(f, NULL, NULL, NULL);
|
dh = PEM_read_DHparams(f, NULL, NULL, NULL);
|
||||||
fclose(f);
|
fclose(f);
|
||||||
PySSL_END_ALLOW_THREADS
|
Py_END_ALLOW_THREADS
|
||||||
|
_PySSL_FIX_ERRNO;
|
||||||
if (dh == NULL) {
|
if (dh == NULL) {
|
||||||
if (errno != 0) {
|
if (errno != 0) {
|
||||||
PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, filepath);
|
PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, filepath);
|
||||||
|
|
@ -4593,6 +4608,7 @@ _ssl__SSLContext_set_default_verify_paths_impl(PySSLContext *self)
|
||||||
Py_BEGIN_ALLOW_THREADS
|
Py_BEGIN_ALLOW_THREADS
|
||||||
rc = SSL_CTX_set_default_verify_paths(self->ctx);
|
rc = SSL_CTX_set_default_verify_paths(self->ctx);
|
||||||
Py_END_ALLOW_THREADS
|
Py_END_ALLOW_THREADS
|
||||||
|
_PySSL_FIX_ERRNO;
|
||||||
if (!rc) {
|
if (!rc) {
|
||||||
_setSSLError(get_state_ctx(self), NULL, 0, __FILE__, __LINE__);
|
_setSSLError(get_state_ctx(self), NULL, 0, __FILE__, __LINE__);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
|
||||||
|
|
@ -140,13 +140,14 @@ _PySSL_keylog_callback(const SSL *ssl, const char *line)
|
||||||
* critical debug helper.
|
* critical debug helper.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
PySSL_BEGIN_ALLOW_THREADS
|
Py_BEGIN_ALLOW_THREADS
|
||||||
PyThread_acquire_lock(lock, 1);
|
PyThread_acquire_lock(lock, 1);
|
||||||
res = BIO_printf(ssl_obj->ctx->keylog_bio, "%s\n", line);
|
res = BIO_printf(ssl_obj->ctx->keylog_bio, "%s\n", line);
|
||||||
e = errno;
|
e = errno;
|
||||||
(void)BIO_flush(ssl_obj->ctx->keylog_bio);
|
(void)BIO_flush(ssl_obj->ctx->keylog_bio);
|
||||||
PyThread_release_lock(lock);
|
PyThread_release_lock(lock);
|
||||||
PySSL_END_ALLOW_THREADS
|
Py_END_ALLOW_THREADS
|
||||||
|
_PySSL_FIX_ERRNO;
|
||||||
|
|
||||||
if (res == -1) {
|
if (res == -1) {
|
||||||
errno = e;
|
errno = e;
|
||||||
|
|
@ -187,9 +188,10 @@ _PySSLContext_set_keylog_filename(PyObject *op, PyObject *arg,
|
||||||
if (self->keylog_bio != NULL) {
|
if (self->keylog_bio != NULL) {
|
||||||
BIO *bio = self->keylog_bio;
|
BIO *bio = self->keylog_bio;
|
||||||
self->keylog_bio = NULL;
|
self->keylog_bio = NULL;
|
||||||
PySSL_BEGIN_ALLOW_THREADS
|
Py_BEGIN_ALLOW_THREADS
|
||||||
BIO_free_all(bio);
|
BIO_free_all(bio);
|
||||||
PySSL_END_ALLOW_THREADS
|
Py_END_ALLOW_THREADS
|
||||||
|
_PySSL_FIX_ERRNO;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (arg == Py_None) {
|
if (arg == Py_None) {
|
||||||
|
|
@ -211,13 +213,13 @@ _PySSLContext_set_keylog_filename(PyObject *op, PyObject *arg,
|
||||||
self->keylog_filename = Py_NewRef(arg);
|
self->keylog_filename = Py_NewRef(arg);
|
||||||
|
|
||||||
/* Write a header for seekable, empty files (this excludes pipes). */
|
/* Write a header for seekable, empty files (this excludes pipes). */
|
||||||
PySSL_BEGIN_ALLOW_THREADS
|
PySSL_BEGIN_ALLOW_THREADS(self)
|
||||||
if (BIO_tell(self->keylog_bio) == 0) {
|
if (BIO_tell(self->keylog_bio) == 0) {
|
||||||
BIO_puts(self->keylog_bio,
|
BIO_puts(self->keylog_bio,
|
||||||
"# TLS secrets log file, generated by OpenSSL / Python\n");
|
"# TLS secrets log file, generated by OpenSSL / Python\n");
|
||||||
(void)BIO_flush(self->keylog_bio);
|
(void)BIO_flush(self->keylog_bio);
|
||||||
}
|
}
|
||||||
PySSL_END_ALLOW_THREADS
|
PySSL_END_ALLOW_THREADS(self)
|
||||||
SSL_CTX_set_keylog_callback(self->ctx, _PySSL_keylog_callback);
|
SSL_CTX_set_keylog_callback(self->ctx, _PySSL_keylog_callback);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue