int ret;
QCTX ctx;
SSL *conn_ssl = NULL;
+ SSL *conn_ssl_tmp = NULL;
SSL_CONNECTION *conn = NULL;
QUIC_CHANNEL *new_ch = NULL;
- QUIC_CONNECTION *qc;
+ QUIC_CONNECTION *qc = NULL;
int no_block = ((flags & SSL_ACCEPT_CONNECTION_NO_BLOCK) != 0);
if (!expect_quic_listener(ssl, &ctx))
* bound to new_ch. If channel constructor fails to create any item here
* it just fails to create channel.
*/
- if (!ossl_assert((conn_ssl = ossl_quic_channel_get0_tls(new_ch)) != NULL)
- || !ossl_assert((conn = SSL_CONNECTION_FROM_SSL(conn_ssl)) != NULL)
- || !ossl_assert((conn_ssl = SSL_CONNECTION_GET_USER_SSL(conn)) != NULL))
+ if (!ossl_assert((conn_ssl_tmp = ossl_quic_channel_get0_tls(new_ch)) != NULL)
+ || !ossl_assert((conn = SSL_CONNECTION_FROM_SSL(conn_ssl_tmp)) != NULL)
+ || !ossl_assert((conn_ssl_tmp = SSL_CONNECTION_GET_USER_SSL(conn)) != NULL))
goto out;
- qc = (QUIC_CONNECTION *)conn_ssl;
- qc->pending = 0;
- if (!SSL_up_ref(&ctx.ql->obj.ssl)) {
- /*
- * You might expect ossl_quic_channel_free() to be called here. Be
- * assured it happens, The process goes as follows:
- * - The SSL_free() here is being handled by ossl_quic_free().
- * - The very last step of ossl_quic_free() is call to qc_cleanup()
- * where channel gets freed.
- */
- SSL_free(conn_ssl);
+ qc = (QUIC_CONNECTION *)conn_ssl_tmp;
+ if (SSL_up_ref(&ctx.ql->obj.ssl)) {
+ qc->listener = ctx.ql;
+ conn_ssl = conn_ssl_tmp;
+ conn_ssl_tmp = NULL;
+ qc->pending = 0;
}
- qc->listener = ctx.ql;
out:
qctx_unlock(&ctx);
+ /*
+ * You might expect ossl_quic_channel_free() to be called here. Be
+ * assured it happens, The process goes as follows:
+ * - The SSL_free() here is being handled by ossl_quic_free().
+ * - The very last step of ossl_quic_free() is call to qc_cleanup()
+ * where channel gets freed.
+ * NOTE: We defer this SSL_free until after the call to qctx_unlock above
+ * to avoid the deadlock that would occur when ossl_quic_free attempts to
+ * re-acquire this mutex. We also do the gymnastics with conn_ssl and
+ * conn_ssl_tmp above so that we only actually do the free on the SSL
+ * object if the up-ref above fails, in such a way that we don't unbalance
+ * the listener refcount (i.e. if the up-ref fails above, we don't set the
+ * listener pointer so that we don't then drop the ref-count erroneously
+ * during the free operation.
+ */
+ SSL_free(conn_ssl_tmp);
return conn_ssl;
}
goto err;
/* Call SSL_accept() and SSL_connect() until we are connected */
- if (!TEST_true(create_bare_ssl_connection(serverssl, clientssl,
- SSL_ERROR_NONE, 0, 0)))
+ if (!TEST_true(create_bare_ssl_connection(serverssl, clientssl, SSL_ERROR_NONE, 0, 0)))
/*
* Ensure that, now that we have used SSL_listen_ex, SSL_accept_connection
serverssl = SSL_accept_connection(qlistener, 0);
/* Call SSL_accept() and SSL_connect() until we are connected */
- if (!TEST_true(create_bare_ssl_connection(serverssl, clientssl,
- SSL_ERROR_NONE, 0, 0)))
+ if (!TEST_ptr(serverssl)
+ || !TEST_true(create_bare_ssl_connection(serverssl, clientssl, SSL_ERROR_NONE, 0, 0)))
goto err;
testresult = 1;
serverssl = SSL_accept_connection(qlistener, 0);
/* Call SSL_accept() and SSL_connect() until we are connected */
- if (!TEST_true(create_bare_ssl_connection(serverssl, clientssl,
- SSL_ERROR_NONE, 0, 0)))
+ if (!TEST_ptr(serverssl)
+ || !TEST_true(create_bare_ssl_connection(serverssl, clientssl, SSL_ERROR_NONE, 0, 0)))
goto err;
testresult = 1;