lol

python313: revert commit that locks ssl sockets (#432368)

authored by

Martin Weinelt and committed by
GitHub
3e0f5100 6191a4bf

+382 -2
+373
pkgs/development/interpreters/python/cpython/3.13/revert-gh134724.patch
··· 1 + commit 4a37dd6cef1556c64c2665061b5e01bbd2bb3a82 2 + Author: Gregory P. Smith <68491+gpshead@users.noreply.github.com> 3 + Date: Sun Jul 27 08:30:25 2025 -0700 4 + 5 + [3.13] gh-134698: Hold a lock when the thread state is detached in ssl (GH-134724) (#137126) 6 + 7 + Lock when the thread state is detached. 8 + (cherry picked from commit e047a35b23c1aa69ab8d5da56f36319cec4d36b8) or really from the 3.14 backport fd565fdfc9c0001900d03d627e2fda83f1bcca90 9 + 10 + Co-authored-by: Peter Bierma <zintensitydev@gmail.com> 11 + 12 + diff --git b/Modules/_ssl.c a/Modules/_ssl.c 13 + index 981c3d6a936..aa846f68641 100644 14 + --- b/Modules/_ssl.c 15 + +++ a/Modules/_ssl.c 16 + @@ -42,14 +42,14 @@ 17 + /* Redefined below for Windows debug builds after important #includes */ 18 + #define _PySSL_FIX_ERRNO 19 + 20 + -#define PySSL_BEGIN_ALLOW_THREADS_S(save, mutex) \ 21 + - do { (save) = PyEval_SaveThread(); PyMutex_Lock(mutex); } while(0) 22 + -#define PySSL_END_ALLOW_THREADS_S(save, mutex) \ 23 + - do { PyMutex_Unlock(mutex); PyEval_RestoreThread(save); _PySSL_FIX_ERRNO; } while(0) 24 + -#define PySSL_BEGIN_ALLOW_THREADS(self) { \ 25 + +#define PySSL_BEGIN_ALLOW_THREADS_S(save) \ 26 + + do { (save) = PyEval_SaveThread(); } while(0) 27 + +#define PySSL_END_ALLOW_THREADS_S(save) \ 28 + + do { PyEval_RestoreThread(save); _PySSL_FIX_ERRNO; } while(0) 29 + +#define PySSL_BEGIN_ALLOW_THREADS { \ 30 + PyThreadState *_save = NULL; \ 31 + - PySSL_BEGIN_ALLOW_THREADS_S(_save, &self->tstate_mutex); 32 + -#define PySSL_END_ALLOW_THREADS(self) PySSL_END_ALLOW_THREADS_S(_save, &self->tstate_mutex); } 33 + + PySSL_BEGIN_ALLOW_THREADS_S(_save); 34 + +#define PySSL_END_ALLOW_THREADS PySSL_END_ALLOW_THREADS_S(_save); } 35 + 36 + #if defined(HAVE_POLL_H) 37 + #include <poll.h> 38 + @@ -304,9 +304,6 @@ typedef struct { 39 + PyObject *psk_client_callback; 40 + PyObject *psk_server_callback; 41 + #endif 42 + - /* Lock to synchronize calls when the thread state is detached. 43 + - See also gh-134698. */ 44 + - PyMutex tstate_mutex; 45 + } PySSLContext; 46 + 47 + typedef struct { 48 + @@ -332,9 +329,6 @@ typedef struct { 49 + * and shutdown methods check for chained exceptions. 50 + */ 51 + PyObject *exc; 52 + - /* Lock to synchronize calls when the thread state is detached. 53 + - See also gh-134698. */ 54 + - PyMutex tstate_mutex; 55 + } PySSLSocket; 56 + 57 + typedef struct { 58 + @@ -846,14 +840,13 @@ newPySSLSocket(PySSLContext *sslctx, PySocketSockObject *sock, 59 + self->server_hostname = NULL; 60 + self->err = err; 61 + self->exc = NULL; 62 + - self->tstate_mutex = (PyMutex){0}; 63 + 64 + /* Make sure the SSL error state is initialized */ 65 + ERR_clear_error(); 66 + 67 + - PySSL_BEGIN_ALLOW_THREADS(sslctx) 68 + + PySSL_BEGIN_ALLOW_THREADS 69 + self->ssl = SSL_new(ctx); 70 + - PySSL_END_ALLOW_THREADS(sslctx) 71 + + PySSL_END_ALLOW_THREADS 72 + if (self->ssl == NULL) { 73 + Py_DECREF(self); 74 + _setSSLError(get_state_ctx(self), NULL, 0, __FILE__, __LINE__); 75 + @@ -919,12 +912,12 @@ newPySSLSocket(PySSLContext *sslctx, PySocketSockObject *sock, 76 + BIO_set_nbio(SSL_get_wbio(self->ssl), 1); 77 + } 78 + 79 + - PySSL_BEGIN_ALLOW_THREADS(self) 80 + + PySSL_BEGIN_ALLOW_THREADS 81 + if (socket_type == PY_SSL_CLIENT) 82 + SSL_set_connect_state(self->ssl); 83 + else 84 + SSL_set_accept_state(self->ssl); 85 + - PySSL_END_ALLOW_THREADS(self) 86 + + PySSL_END_ALLOW_THREADS 87 + 88 + self->socket_type = socket_type; 89 + if (sock != NULL) { 90 + @@ -993,10 +986,10 @@ _ssl__SSLSocket_do_handshake_impl(PySSLSocket *self) 91 + /* Actually negotiate SSL connection */ 92 + /* XXX If SSL_do_handshake() returns 0, it's also a failure. */ 93 + do { 94 + - PySSL_BEGIN_ALLOW_THREADS(self) 95 + + PySSL_BEGIN_ALLOW_THREADS 96 + ret = SSL_do_handshake(self->ssl); 97 + err = _PySSL_errno(ret < 1, self->ssl, ret); 98 + - PySSL_END_ALLOW_THREADS(self) 99 + + PySSL_END_ALLOW_THREADS 100 + self->err = err; 101 + 102 + if (PyErr_CheckSignals()) 103 + @@ -2369,10 +2362,9 @@ PySSL_select(PySocketSockObject *s, int writing, PyTime_t timeout) 104 + ms = (int)_PyTime_AsMilliseconds(timeout, _PyTime_ROUND_CEILING); 105 + assert(ms <= INT_MAX); 106 + 107 + - Py_BEGIN_ALLOW_THREADS 108 + + PySSL_BEGIN_ALLOW_THREADS 109 + rc = poll(&pollfd, 1, (int)ms); 110 + - Py_END_ALLOW_THREADS 111 + - _PySSL_FIX_ERRNO; 112 + + PySSL_END_ALLOW_THREADS 113 + #else 114 + /* Guard against socket too large for select*/ 115 + if (!_PyIsSelectable_fd(s->sock_fd)) 116 + @@ -2384,14 +2376,13 @@ PySSL_select(PySocketSockObject *s, int writing, PyTime_t timeout) 117 + FD_SET(s->sock_fd, &fds); 118 + 119 + /* Wait until the socket becomes ready */ 120 + - Py_BEGIN_ALLOW_THREADS 121 + + PySSL_BEGIN_ALLOW_THREADS 122 + nfds = Py_SAFE_DOWNCAST(s->sock_fd+1, SOCKET_T, int); 123 + if (writing) 124 + rc = select(nfds, NULL, &fds, NULL, &tv); 125 + else 126 + rc = select(nfds, &fds, NULL, NULL, &tv); 127 + - Py_END_ALLOW_THREADS 128 + - _PySSL_FIX_ERRNO; 129 + + PySSL_END_ALLOW_THREADS 130 + #endif 131 + 132 + /* Return SOCKET_TIMED_OUT on timeout, SOCKET_OPERATION_OK otherwise 133 + @@ -2462,10 +2453,10 @@ _ssl__SSLSocket_write_impl(PySSLSocket *self, Py_buffer *b) 134 + } 135 + 136 + do { 137 + - PySSL_BEGIN_ALLOW_THREADS(self) 138 + + PySSL_BEGIN_ALLOW_THREADS 139 + retval = SSL_write_ex(self->ssl, b->buf, (size_t)b->len, &count); 140 + err = _PySSL_errno(retval == 0, self->ssl, retval); 141 + - PySSL_END_ALLOW_THREADS(self) 142 + + PySSL_END_ALLOW_THREADS 143 + self->err = err; 144 + 145 + if (PyErr_CheckSignals()) 146 + @@ -2523,10 +2514,10 @@ _ssl__SSLSocket_pending_impl(PySSLSocket *self) 147 + int count = 0; 148 + _PySSLError err; 149 + 150 + - PySSL_BEGIN_ALLOW_THREADS(self) 151 + + PySSL_BEGIN_ALLOW_THREADS 152 + count = SSL_pending(self->ssl); 153 + err = _PySSL_errno(count < 0, self->ssl, count); 154 + - PySSL_END_ALLOW_THREADS(self) 155 + + PySSL_END_ALLOW_THREADS 156 + self->err = err; 157 + 158 + if (count < 0) 159 + @@ -2617,10 +2608,10 @@ _ssl__SSLSocket_read_impl(PySSLSocket *self, Py_ssize_t len, 160 + deadline = _PyDeadline_Init(timeout); 161 + 162 + do { 163 + - PySSL_BEGIN_ALLOW_THREADS(self) 164 + + PySSL_BEGIN_ALLOW_THREADS 165 + retval = SSL_read_ex(self->ssl, mem, (size_t)len, &count); 166 + err = _PySSL_errno(retval == 0, self->ssl, retval); 167 + - PySSL_END_ALLOW_THREADS(self) 168 + + PySSL_END_ALLOW_THREADS 169 + self->err = err; 170 + 171 + if (PyErr_CheckSignals()) 172 + @@ -2719,7 +2710,7 @@ _ssl__SSLSocket_shutdown_impl(PySSLSocket *self) 173 + } 174 + 175 + while (1) { 176 + - PySSL_BEGIN_ALLOW_THREADS(self) 177 + + PySSL_BEGIN_ALLOW_THREADS 178 + /* Disable read-ahead so that unwrap can work correctly. 179 + * Otherwise OpenSSL might read in too much data, 180 + * eating clear text data that happens to be 181 + @@ -2732,7 +2723,7 @@ _ssl__SSLSocket_shutdown_impl(PySSLSocket *self) 182 + SSL_set_read_ahead(self->ssl, 0); 183 + ret = SSL_shutdown(self->ssl); 184 + err = _PySSL_errno(ret < 0, self->ssl, ret); 185 + - PySSL_END_ALLOW_THREADS(self) 186 + + PySSL_END_ALLOW_THREADS 187 + self->err = err; 188 + 189 + /* If err == 1, a secure shutdown with SSL_shutdown() is complete */ 190 + @@ -3124,10 +3115,9 @@ _ssl__SSLContext_impl(PyTypeObject *type, int proto_version) 191 + // no other thread can be touching this object yet. 192 + // (Technically, we can't even lock if we wanted to, as the 193 + // lock hasn't been initialized yet.) 194 + - Py_BEGIN_ALLOW_THREADS 195 + + PySSL_BEGIN_ALLOW_THREADS 196 + ctx = SSL_CTX_new(method); 197 + - Py_END_ALLOW_THREADS 198 + - _PySSL_FIX_ERRNO; 199 + + PySSL_END_ALLOW_THREADS 200 + 201 + if (ctx == NULL) { 202 + _setSSLError(get_ssl_state(module), NULL, 0, __FILE__, __LINE__); 203 + @@ -3153,7 +3143,6 @@ _ssl__SSLContext_impl(PyTypeObject *type, int proto_version) 204 + self->psk_client_callback = NULL; 205 + self->psk_server_callback = NULL; 206 + #endif 207 + - self->tstate_mutex = (PyMutex){0}; 208 + 209 + /* Don't check host name by default */ 210 + if (proto_version == PY_SSL_VERSION_TLS_CLIENT) { 211 + @@ -3270,10 +3259,9 @@ context_clear(PySSLContext *self) 212 + Py_CLEAR(self->psk_server_callback); 213 + #endif 214 + if (self->keylog_bio != NULL) { 215 + - Py_BEGIN_ALLOW_THREADS 216 + + PySSL_BEGIN_ALLOW_THREADS 217 + BIO_free_all(self->keylog_bio); 218 + - Py_END_ALLOW_THREADS 219 + - _PySSL_FIX_ERRNO; 220 + + PySSL_END_ALLOW_THREADS 221 + self->keylog_bio = NULL; 222 + } 223 + return 0; 224 + @@ -3992,8 +3980,7 @@ _password_callback(char *buf, int size, int rwflag, void *userdata) 225 + _PySSLPasswordInfo *pw_info = (_PySSLPasswordInfo*) userdata; 226 + PyObject *fn_ret = NULL; 227 + 228 + - pw_info->thread_state = PyThreadState_Swap(pw_info->thread_state); 229 + - _PySSL_FIX_ERRNO; 230 + + PySSL_END_ALLOW_THREADS_S(pw_info->thread_state); 231 + 232 + if (pw_info->error) { 233 + /* already failed previously. OpenSSL 3.0.0-alpha14 invokes the 234 + @@ -4023,13 +4010,13 @@ _password_callback(char *buf, int size, int rwflag, void *userdata) 235 + goto error; 236 + } 237 + 238 + - pw_info->thread_state = PyThreadState_Swap(pw_info->thread_state); 239 + + PySSL_BEGIN_ALLOW_THREADS_S(pw_info->thread_state); 240 + memcpy(buf, pw_info->password, pw_info->size); 241 + return pw_info->size; 242 + 243 + error: 244 + Py_XDECREF(fn_ret); 245 + - pw_info->thread_state = PyThreadState_Swap(pw_info->thread_state); 246 + + PySSL_BEGIN_ALLOW_THREADS_S(pw_info->thread_state); 247 + pw_info->error = 1; 248 + return -1; 249 + } 250 + @@ -4082,10 +4069,10 @@ _ssl__SSLContext_load_cert_chain_impl(PySSLContext *self, PyObject *certfile, 251 + SSL_CTX_set_default_passwd_cb(self->ctx, _password_callback); 252 + SSL_CTX_set_default_passwd_cb_userdata(self->ctx, &pw_info); 253 + } 254 + - PySSL_BEGIN_ALLOW_THREADS_S(pw_info.thread_state, &self->tstate_mutex); 255 + + PySSL_BEGIN_ALLOW_THREADS_S(pw_info.thread_state); 256 + r = SSL_CTX_use_certificate_chain_file(self->ctx, 257 + PyBytes_AS_STRING(certfile_bytes)); 258 + - PySSL_END_ALLOW_THREADS_S(pw_info.thread_state, &self->tstate_mutex); 259 + + PySSL_END_ALLOW_THREADS_S(pw_info.thread_state); 260 + if (r != 1) { 261 + if (pw_info.error) { 262 + ERR_clear_error(); 263 + @@ -4100,11 +4087,11 @@ _ssl__SSLContext_load_cert_chain_impl(PySSLContext *self, PyObject *certfile, 264 + } 265 + goto error; 266 + } 267 + - PySSL_BEGIN_ALLOW_THREADS_S(pw_info.thread_state, &self->tstate_mutex); 268 + + PySSL_BEGIN_ALLOW_THREADS_S(pw_info.thread_state); 269 + r = SSL_CTX_use_PrivateKey_file(self->ctx, 270 + PyBytes_AS_STRING(keyfile ? keyfile_bytes : certfile_bytes), 271 + SSL_FILETYPE_PEM); 272 + - PySSL_END_ALLOW_THREADS_S(pw_info.thread_state, &self->tstate_mutex); 273 + + PySSL_END_ALLOW_THREADS_S(pw_info.thread_state); 274 + Py_CLEAR(keyfile_bytes); 275 + Py_CLEAR(certfile_bytes); 276 + if (r != 1) { 277 + @@ -4121,9 +4108,9 @@ _ssl__SSLContext_load_cert_chain_impl(PySSLContext *self, PyObject *certfile, 278 + } 279 + goto error; 280 + } 281 + - PySSL_BEGIN_ALLOW_THREADS_S(pw_info.thread_state, &self->tstate_mutex); 282 + + PySSL_BEGIN_ALLOW_THREADS_S(pw_info.thread_state); 283 + r = SSL_CTX_check_private_key(self->ctx); 284 + - PySSL_END_ALLOW_THREADS_S(pw_info.thread_state, &self->tstate_mutex); 285 + + PySSL_END_ALLOW_THREADS_S(pw_info.thread_state); 286 + if (r != 1) { 287 + _setSSLError(get_state_ctx(self), NULL, 0, __FILE__, __LINE__); 288 + goto error; 289 + @@ -4340,9 +4327,9 @@ _ssl__SSLContext_load_verify_locations_impl(PySSLContext *self, 290 + cafile_buf = PyBytes_AS_STRING(cafile_bytes); 291 + if (capath) 292 + capath_buf = PyBytes_AS_STRING(capath_bytes); 293 + - PySSL_BEGIN_ALLOW_THREADS(self) 294 + + PySSL_BEGIN_ALLOW_THREADS 295 + r = SSL_CTX_load_verify_locations(self->ctx, cafile_buf, capath_buf); 296 + - PySSL_END_ALLOW_THREADS(self) 297 + + PySSL_END_ALLOW_THREADS 298 + if (r != 1) { 299 + if (errno != 0) { 300 + PyErr_SetFromErrno(PyExc_OSError); 301 + @@ -4394,11 +4381,10 @@ _ssl__SSLContext_load_dh_params_impl(PySSLContext *self, PyObject *filepath) 302 + return NULL; 303 + 304 + errno = 0; 305 + - Py_BEGIN_ALLOW_THREADS 306 + + PySSL_BEGIN_ALLOW_THREADS 307 + dh = PEM_read_DHparams(f, NULL, NULL, NULL); 308 + fclose(f); 309 + - Py_END_ALLOW_THREADS 310 + - _PySSL_FIX_ERRNO; 311 + + PySSL_END_ALLOW_THREADS 312 + if (dh == NULL) { 313 + if (errno != 0) { 314 + PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, filepath); 315 + @@ -4550,7 +4536,6 @@ _ssl__SSLContext_set_default_verify_paths_impl(PySSLContext *self) 316 + Py_BEGIN_ALLOW_THREADS 317 + rc = SSL_CTX_set_default_verify_paths(self->ctx); 318 + Py_END_ALLOW_THREADS 319 + - _PySSL_FIX_ERRNO; 320 + if (!rc) { 321 + _setSSLError(get_state_ctx(self), NULL, 0, __FILE__, __LINE__); 322 + return NULL; 323 + diff --git b/Modules/_ssl/debughelpers.c a/Modules/_ssl/debughelpers.c 324 + index fb8ae7c4e0b..5fc69a07184 100644 325 + --- b/Modules/_ssl/debughelpers.c 326 + +++ a/Modules/_ssl/debughelpers.c 327 + @@ -135,15 +135,13 @@ _PySSL_keylog_callback(const SSL *ssl, const char *line) 328 + * critical debug helper. 329 + */ 330 + 331 + - assert(PyMutex_IsLocked(&ssl_obj->tstate_mutex)); 332 + - Py_BEGIN_ALLOW_THREADS 333 + + PySSL_BEGIN_ALLOW_THREADS 334 + PyThread_acquire_lock(lock, 1); 335 + res = BIO_printf(ssl_obj->ctx->keylog_bio, "%s\n", line); 336 + e = errno; 337 + (void)BIO_flush(ssl_obj->ctx->keylog_bio); 338 + PyThread_release_lock(lock); 339 + - Py_END_ALLOW_THREADS 340 + - _PySSL_FIX_ERRNO; 341 + + PySSL_END_ALLOW_THREADS 342 + 343 + if (res == -1) { 344 + errno = e; 345 + @@ -179,10 +177,9 @@ _PySSLContext_set_keylog_filename(PySSLContext *self, PyObject *arg, void *c) { 346 + if (self->keylog_bio != NULL) { 347 + BIO *bio = self->keylog_bio; 348 + self->keylog_bio = NULL; 349 + - Py_BEGIN_ALLOW_THREADS 350 + + PySSL_BEGIN_ALLOW_THREADS 351 + BIO_free_all(bio); 352 + - Py_END_ALLOW_THREADS 353 + - _PySSL_FIX_ERRNO; 354 + + PySSL_END_ALLOW_THREADS 355 + } 356 + 357 + if (arg == Py_None) { 358 + @@ -204,13 +201,13 @@ _PySSLContext_set_keylog_filename(PySSLContext *self, PyObject *arg, void *c) { 359 + self->keylog_filename = Py_NewRef(arg); 360 + 361 + /* Write a header for seekable, empty files (this excludes pipes). */ 362 + - PySSL_BEGIN_ALLOW_THREADS(self) 363 + + PySSL_BEGIN_ALLOW_THREADS 364 + if (BIO_tell(self->keylog_bio) == 0) { 365 + BIO_puts(self->keylog_bio, 366 + "# TLS secrets log file, generated by OpenSSL / Python\n"); 367 + (void)BIO_flush(self->keylog_bio); 368 + } 369 + - PySSL_END_ALLOW_THREADS(self) 370 + + PySSL_END_ALLOW_THREADS 371 + SSL_CTX_set_keylog_callback(self->ctx, _PySSL_keylog_callback); 372 + return 0; 373 + }
+4
pkgs/development/interpreters/python/cpython/default.nix
··· 365 365 ++ optionals (pythonAtLeast "3.13") [ 366 366 ./3.13/virtualenv-permissions.patch 367 367 ] 368 + ++ optionals isPy313 [ 369 + # https://github.com/python/cpython/issues/137583 370 + ./3.13/revert-gh134724.patch 371 + ] 368 372 ++ optionals mimetypesSupport [ 369 373 # Make the mimetypes module refer to the right file 370 374 ./mimetypes.patch
+4
pkgs/development/python-modules/sentence-stream/default.nix
··· 28 28 regex 29 29 ]; 30 30 31 + pythonRelaxDeps = [ 32 + "regex" 33 + ]; 34 + 31 35 nativeCheckInputs = [ 32 36 pytest-asyncio 33 37 pytestCheckHook
+1 -2
pkgs/development/python-modules/websockets/default.nix
··· 61 61 ''; 62 62 63 63 # Tests fail on Darwin with `OSError: AF_UNIX path too long` 64 - # https://github.com/python-websockets/websockets/issues/1648 65 - doCheck = pythonOlder "3.13" && !stdenv.hostPlatform.isDarwin; 64 + doCheck = !stdenv.hostPlatform.isDarwin; 66 65 67 66 pythonImportsCheck = [ "websockets" ]; 68 67