@@ -3296,6 +3296,9 @@ context_dealloc(PySSLContext *self)
32963296 /* bpo-31095: UnTrack is needed before calling any callbacks */
32973297 PyObject_GC_UnTrack (self );
32983298 context_clear (self );
3299+ /* The SSL_CTX may outlive this object as the session_ctx of sockets that
3300+ were switched to another context; leave no Python callback behind. */
3301+ SSL_CTX_set_tlsext_servername_callback (self -> ctx , NULL );
32993302 SSL_CTX_free (self -> ctx );
33003303 PyMem_FREE (self -> alpn_protocols );
33013304 Py_TYPE (self )-> tp_free (self );
@@ -4606,27 +4609,42 @@ _ssl__SSLContext_set_ecdh_curve_impl(PySSLContext *self, PyObject *name)
46064609}
46074610
46084611static int
4609- _servername_callback (SSL * s , int * al , void * args )
4612+ _servername_callback (SSL * s , int * al , void * Py_UNUSED ( args ) )
46104613{
46114614 int ret ;
4612- PySSLContext * sslctx = ( PySSLContext * ) args ;
4615+ PySSLContext * sslctx ;
46134616 PySSLSocket * ssl ;
46144617 PyObject * result ;
46154618 /* The high-level ssl.SSLSocket object */
4616- PyObject * ssl_socket ;
4619+ PyObject * ssl_socket = NULL ;
4620+ PyObject * sni_cb ;
46174621 const char * servername = SSL_get_servername (s , TLSEXT_NAMETYPE_host_name );
46184622 PyGILState_STATE gstate = PyGILState_Ensure ();
46194623
4620- if (sslctx -> set_sni_cb == NULL ) {
4621- /* remove race condition in this the call back while if removing the
4622- * callback is in progress */
4624+ /* Do not use the SSL_CTX's servername arg to find the context: it is a
4625+ borrowed pointer to whichever _SSLContext installed the callback, and
4626+ that object may already be gone while OpenSSL still reaches this
4627+ callback through the connection's session_ctx (e.g. on the second
4628+ ClientHello after a HelloRetryRequest, once sni_callback has switched
4629+ the socket to another context). The socket's current context is
4630+ always alive; hold strong references to it and to the callback while
4631+ they are used here. */
4632+ ssl = SSL_get_app_data (s );
4633+ assert (ssl != NULL );
4634+ Py_BEGIN_CRITICAL_SECTION (ssl );
4635+ sslctx = (PySSLContext * )Py_NewRef (ssl -> ctx );
4636+ Py_END_CRITICAL_SECTION ();
4637+ assert (Py_IS_TYPE (ssl , get_state_ctx (sslctx )-> PySSLSocket_Type ));
4638+
4639+ Py_BEGIN_CRITICAL_SECTION (sslctx );
4640+ sni_cb = Py_XNewRef (sslctx -> set_sni_cb );
4641+ Py_END_CRITICAL_SECTION ();
4642+ if (sni_cb == NULL ) {
4643+ Py_DECREF (sslctx );
46234644 PyGILState_Release (gstate );
46244645 return SSL_TLSEXT_ERR_OK ;
46254646 }
46264647
4627- ssl = SSL_get_app_data (s );
4628- assert (Py_IS_TYPE (ssl , get_state_ctx (sslctx )-> PySSLSocket_Type ));
4629-
46304648 /* The servername callback expects an argument that represents the current
46314649 * SSL connection and that has a .context attribute that can be changed to
46324650 * identify the requested hostname. Since the official API is the Python
@@ -4646,7 +4664,7 @@ _servername_callback(SSL *s, int *al, void *args)
46464664 goto error ;
46474665
46484666 if (servername == NULL ) {
4649- result = PyObject_CallFunctionObjArgs (sslctx -> set_sni_cb , ssl_socket ,
4667+ result = PyObject_CallFunctionObjArgs (sni_cb , ssl_socket ,
46504668 Py_None , sslctx , NULL );
46514669 }
46524670 else {
@@ -4669,14 +4687,14 @@ _servername_callback(SSL *s, int *al, void *args)
46694687 }
46704688 Py_DECREF (servername_bytes );
46714689 result = PyObject_CallFunctionObjArgs (
4672- sslctx -> set_sni_cb , ssl_socket , servername_str ,
4690+ sni_cb , ssl_socket , servername_str ,
46734691 sslctx , NULL );
46744692 Py_DECREF (servername_str );
46754693 }
46764694 Py_DECREF (ssl_socket );
46774695
46784696 if (result == NULL ) {
4679- PyErr_WriteUnraisable (sslctx -> set_sni_cb );
4697+ PyErr_WriteUnraisable (sni_cb );
46804698 * al = SSL_AD_HANDSHAKE_FAILURE ;
46814699 ret = SSL_TLSEXT_ERR_ALERT_FATAL ;
46824700 }
@@ -4697,11 +4715,15 @@ _servername_callback(SSL *s, int *al, void *args)
46974715 Py_DECREF (result );
46984716 }
46994717
4718+ Py_DECREF (sni_cb );
4719+ Py_DECREF (sslctx );
47004720 PyGILState_Release (gstate );
47014721 return ret ;
47024722
47034723error :
47044724 Py_XDECREF (ssl_socket );
4725+ Py_DECREF (sni_cb );
4726+ Py_DECREF (sslctx );
47054727 * al = SSL_AD_INTERNAL_ERROR ;
47064728 ret = SSL_TLSEXT_ERR_ALERT_FATAL ;
47074729 PyGILState_Release (gstate );
@@ -4761,7 +4783,6 @@ _ssl__SSLContext_sni_callback_set_impl(PySSLContext *self, PyObject *value)
47614783 }
47624784 self -> set_sni_cb = Py_NewRef (value );
47634785 SSL_CTX_set_tlsext_servername_callback (self -> ctx , _servername_callback );
4764- SSL_CTX_set_tlsext_servername_arg (self -> ctx , self );
47654786 }
47664787 return 0 ;
47674788}
0 commit comments