/* Redefined below for Windows debug builds after important #includes */
#define _PySSL_FIX_ERRNO
-#define PySSL_BEGIN_ALLOW_THREADS_S(save) \
- do { (save) = PyEval_SaveThread(); } while(0)
-#define PySSL_END_ALLOW_THREADS_S(save) \
- do { PyEval_RestoreThread(save); _PySSL_FIX_ERRNO; } while(0)
-#define PySSL_BEGIN_ALLOW_THREADS { \
+#define PySSL_BEGIN_ALLOW_THREADS_S(save, mutex) \
+ do { (save) = PyEval_SaveThread(); PyMutex_Lock(mutex); } while(0)
+#define PySSL_END_ALLOW_THREADS_S(save, mutex) \
+ do { PyMutex_Unlock(mutex); PyEval_RestoreThread(save); _PySSL_FIX_ERRNO; } while(0)
+#define PySSL_BEGIN_ALLOW_THREADS(self) { \
PyThreadState *_save = NULL; \
- PySSL_BEGIN_ALLOW_THREADS_S(_save);
-#define PySSL_END_ALLOW_THREADS PySSL_END_ALLOW_THREADS_S(_save); }
+ PySSL_BEGIN_ALLOW_THREADS_S(_save, &self->tstate_mutex);
+#define PySSL_END_ALLOW_THREADS(self) PySSL_END_ALLOW_THREADS_S(_save, &self->tstate_mutex); }
#if defined(HAVE_POLL_H)
#include <poll.h>
PyObject *psk_client_callback;
PyObject *psk_server_callback;
#endif
+ /* Lock to synchronize calls when the thread state is detached.
+ See also gh-134698. */
+ PyMutex tstate_mutex;
} PySSLContext;
#define PySSLContext_CAST(op) ((PySSLContext *)(op))
* and shutdown methods check for chained exceptions.
*/
PyObject *exc;
+ /* Lock to synchronize calls when the thread state is detached.
+ See also gh-134698. */
+ PyMutex tstate_mutex;
} PySSLSocket;
#define PySSLSocket_CAST(op) ((PySSLSocket *)(op))
self->server_hostname = NULL;
self->err = err;
self->exc = NULL;
+ self->tstate_mutex = (PyMutex){0};
/* Make sure the SSL error state is initialized */
ERR_clear_error();
- PySSL_BEGIN_ALLOW_THREADS
+ PySSL_BEGIN_ALLOW_THREADS(sslctx)
self->ssl = SSL_new(ctx);
- PySSL_END_ALLOW_THREADS
+ PySSL_END_ALLOW_THREADS(sslctx)
if (self->ssl == NULL) {
Py_DECREF(self);
_setSSLError(get_state_ctx(self), NULL, 0, __FILE__, __LINE__);
BIO_set_nbio(SSL_get_wbio(self->ssl), 1);
}
- PySSL_BEGIN_ALLOW_THREADS
+ PySSL_BEGIN_ALLOW_THREADS(self)
if (socket_type == PY_SSL_CLIENT)
SSL_set_connect_state(self->ssl);
else
SSL_set_accept_state(self->ssl);
- PySSL_END_ALLOW_THREADS
+ PySSL_END_ALLOW_THREADS(self)
self->socket_type = socket_type;
if (sock != NULL) {
/* Actually negotiate SSL connection */
/* XXX If SSL_do_handshake() returns 0, it's also a failure. */
do {
- PySSL_BEGIN_ALLOW_THREADS
+ PySSL_BEGIN_ALLOW_THREADS(self)
ret = SSL_do_handshake(self->ssl);
err = _PySSL_errno(ret < 1, self->ssl, ret);
- PySSL_END_ALLOW_THREADS
+ PySSL_END_ALLOW_THREADS(self)
self->err = err;
if (PyErr_CheckSignals())
ms = (int)_PyTime_AsMilliseconds(timeout, _PyTime_ROUND_CEILING);
assert(ms <= INT_MAX);
- PySSL_BEGIN_ALLOW_THREADS
+ Py_BEGIN_ALLOW_THREADS
rc = poll(&pollfd, 1, (int)ms);
- PySSL_END_ALLOW_THREADS
+ Py_END_ALLOW_THREADS
+ _PySSL_FIX_ERRNO;
#else
/* Guard against socket too large for select*/
if (!_PyIsSelectable_fd(s->sock_fd))
FD_SET(s->sock_fd, &fds);
/* 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);
if (writing)
rc = select(nfds, NULL, &fds, NULL, &tv);
else
rc = select(nfds, &fds, NULL, NULL, &tv);
- PySSL_END_ALLOW_THREADS
+ Py_END_ALLOW_THREADS
+ _PySSL_FIX_ERRNO;
#endif
/* Return SOCKET_TIMED_OUT on timeout, SOCKET_OPERATION_OK otherwise
}
do {
- PySSL_BEGIN_ALLOW_THREADS
+ PySSL_BEGIN_ALLOW_THREADS(self)
retval = SSL_sendfile(self->ssl, fd, (off_t)offset, size, flags);
err = _PySSL_errno(retval < 0, self->ssl, (int)retval);
- PySSL_END_ALLOW_THREADS
+ PySSL_END_ALLOW_THREADS(self)
self->err = err;
if (PyErr_CheckSignals()) {
}
do {
- PySSL_BEGIN_ALLOW_THREADS
+ PySSL_BEGIN_ALLOW_THREADS(self)
retval = SSL_write_ex(self->ssl, b->buf, (size_t)b->len, &count);
err = _PySSL_errno(retval == 0, self->ssl, retval);
- PySSL_END_ALLOW_THREADS
+ PySSL_END_ALLOW_THREADS(self)
self->err = err;
if (PyErr_CheckSignals())
int count = 0;
_PySSLError err;
- PySSL_BEGIN_ALLOW_THREADS
+ PySSL_BEGIN_ALLOW_THREADS(self)
count = SSL_pending(self->ssl);
err = _PySSL_errno(count < 0, self->ssl, count);
- PySSL_END_ALLOW_THREADS
+ PySSL_END_ALLOW_THREADS(self)
self->err = err;
if (count < 0)
deadline = _PyDeadline_Init(timeout);
do {
- PySSL_BEGIN_ALLOW_THREADS
+ PySSL_BEGIN_ALLOW_THREADS(self)
retval = SSL_read_ex(self->ssl, mem, (size_t)len, &count);
err = _PySSL_errno(retval == 0, self->ssl, retval);
- PySSL_END_ALLOW_THREADS
+ PySSL_END_ALLOW_THREADS(self)
self->err = err;
if (PyErr_CheckSignals())
}
while (1) {
- PySSL_BEGIN_ALLOW_THREADS
+ PySSL_BEGIN_ALLOW_THREADS(self)
/* Disable read-ahead so that unwrap can work correctly.
* Otherwise OpenSSL might read in too much data,
* eating clear text data that happens to be
SSL_set_read_ahead(self->ssl, 0);
ret = SSL_shutdown(self->ssl);
err = _PySSL_errno(ret < 0, self->ssl, ret);
- PySSL_END_ALLOW_THREADS
+ PySSL_END_ALLOW_THREADS(self)
self->err = err;
/* If err == 1, a secure shutdown with SSL_shutdown() is complete */
// no other thread can be touching this object yet.
// (Technically, we can't even lock if we wanted to, as the
// lock hasn't been initialized yet.)
- PySSL_BEGIN_ALLOW_THREADS
+ Py_BEGIN_ALLOW_THREADS
ctx = SSL_CTX_new(method);
- PySSL_END_ALLOW_THREADS
+ Py_END_ALLOW_THREADS
+ _PySSL_FIX_ERRNO;
if (ctx == NULL) {
_setSSLError(get_ssl_state(module), NULL, 0, __FILE__, __LINE__);
self->psk_client_callback = NULL;
self->psk_server_callback = NULL;
#endif
+ self->tstate_mutex = (PyMutex){0};
/* Don't check host name by default */
if (proto_version == PY_SSL_VERSION_TLS_CLIENT) {
Py_CLEAR(self->psk_server_callback);
#endif
if (self->keylog_bio != NULL) {
- PySSL_BEGIN_ALLOW_THREADS
+ Py_BEGIN_ALLOW_THREADS
BIO_free_all(self->keylog_bio);
- PySSL_END_ALLOW_THREADS
+ Py_END_ALLOW_THREADS
+ _PySSL_FIX_ERRNO;
self->keylog_bio = NULL;
}
return 0;
_PySSLPasswordInfo *pw_info = (_PySSLPasswordInfo*) userdata;
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) {
/* already failed previously. OpenSSL 3.0.0-alpha14 invokes the
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);
return pw_info->size;
error:
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;
return -1;
}
SSL_CTX_set_default_passwd_cb(self->ctx, _password_callback);
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,
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 (pw_info.error) {
ERR_clear_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,
PyBytes_AS_STRING(keyfile ? keyfile_bytes : certfile_bytes),
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(certfile_bytes);
if (r != 1) {
}
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);
- PySSL_END_ALLOW_THREADS_S(pw_info.thread_state);
+ PySSL_END_ALLOW_THREADS_S(pw_info.thread_state, &self->tstate_mutex);
if (r != 1) {
_setSSLError(get_state_ctx(self), NULL, 0, __FILE__, __LINE__);
goto error;
cafile_buf = PyBytes_AS_STRING(cafile_bytes);
if (capath)
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);
- PySSL_END_ALLOW_THREADS
+ PySSL_END_ALLOW_THREADS(self)
if (r != 1) {
if (errno != 0) {
PyErr_SetFromErrno(PyExc_OSError);
return NULL;
errno = 0;
- PySSL_BEGIN_ALLOW_THREADS
+ Py_BEGIN_ALLOW_THREADS
dh = PEM_read_DHparams(f, NULL, NULL, NULL);
fclose(f);
- PySSL_END_ALLOW_THREADS
+ Py_END_ALLOW_THREADS
+ _PySSL_FIX_ERRNO;
if (dh == NULL) {
if (errno != 0) {
PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, filepath);
Py_BEGIN_ALLOW_THREADS
rc = SSL_CTX_set_default_verify_paths(self->ctx);
Py_END_ALLOW_THREADS
+ _PySSL_FIX_ERRNO;
if (!rc) {
_setSSLError(get_state_ctx(self), NULL, 0, __FILE__, __LINE__);
return NULL;