Move thread-event handlers to the new thread-local api

Thread event handlers in the fips provider create a thread-local storage
key per context, meaning we can exhaust our thread-local space quickly
by creating lots of contexts.  Avoid that by moving to the new
thread-local storage api.

Reviewed-by: Saša Nedvědický <sashan@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: Matt Caswell <matt@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/27794)
This commit is contained in:
Neil Horman 2025-06-12 13:18:41 -04:00
parent ce990ce83b
commit 2e74a3045b
4 changed files with 48 additions and 70 deletions

View File

@ -16,6 +16,7 @@
#include "internal/core.h"
#include "internal/bio.h"
#include "internal/provider.h"
#include "internal/threads_common.h"
#include "crypto/decoder.h"
#include "crypto/context.h"
@ -31,7 +32,6 @@ struct ossl_lib_ctx_st {
void *global_properties;
void *drbg;
void *drbg_nonce;
CRYPTO_THREAD_LOCAL rcu_local_key;
#ifndef FIPS_MODULE
void *provider_conf;
void *bio_core;
@ -47,7 +47,6 @@ struct ossl_lib_ctx_st {
void *threads;
#endif
#ifdef FIPS_MODULE
void *thread_event_handler;
void *fips_prov;
#endif
STACK_OF(SSL_COMP) *comp_methods;
@ -92,9 +91,6 @@ static int context_init(OSSL_LIB_CTX *ctx)
{
int exdata_done = 0;
if (!CRYPTO_THREAD_init_local(&ctx->rcu_local_key, NULL))
return 0;
ctx->lock = CRYPTO_THREAD_lock_new();
if (ctx->lock == NULL)
goto err;
@ -187,8 +183,7 @@ static int context_init(OSSL_LIB_CTX *ctx)
#endif
#ifdef FIPS_MODULE
ctx->thread_event_handler = ossl_thread_event_ctx_new(ctx);
if (ctx->thread_event_handler == NULL)
if (!ossl_thread_event_ctx_new(ctx))
goto err;
ctx->fips_prov = ossl_fips_prov_ossl_ctx_new(ctx);
@ -226,7 +221,6 @@ static int context_init(OSSL_LIB_CTX *ctx)
ossl_crypto_cleanup_all_ex_data_int(ctx);
CRYPTO_THREAD_lock_free(ctx->lock);
CRYPTO_THREAD_cleanup_local(&ctx->rcu_local_key);
memset(ctx, '\0', sizeof(*ctx));
return 0;
}
@ -331,10 +325,7 @@ static void context_deinit_objs(OSSL_LIB_CTX *ctx)
#endif
#ifdef FIPS_MODULE
if (ctx->thread_event_handler != NULL) {
ossl_thread_event_ctx_free(ctx->thread_event_handler);
ctx->thread_event_handler = NULL;
}
ossl_thread_event_ctx_free(ctx);
if (ctx->fips_prov != NULL) {
ossl_fips_prov_ossl_ctx_free(ctx->fips_prov);
@ -379,7 +370,6 @@ static int context_deinit(OSSL_LIB_CTX *ctx)
CRYPTO_THREAD_lock_free(ctx->lock);
ctx->lock = NULL;
CRYPTO_THREAD_cleanup_local(&ctx->rcu_local_key);
return 1;
}
@ -388,24 +378,15 @@ static int context_deinit(OSSL_LIB_CTX *ctx)
static OSSL_LIB_CTX default_context_int;
static CRYPTO_ONCE default_context_init = CRYPTO_ONCE_STATIC_INIT;
static CRYPTO_THREAD_LOCAL default_context_thread_local;
static int default_context_inited = 0;
DEFINE_RUN_ONCE_STATIC(default_context_do_init)
{
if (!CRYPTO_THREAD_init_local(&default_context_thread_local, NULL))
goto err;
if (!context_init(&default_context_int))
goto deinit_thread;
return 0;
default_context_inited = 1;
return 1;
deinit_thread:
CRYPTO_THREAD_cleanup_local(&default_context_thread_local);
err:
return 0;
}
void ossl_lib_ctx_default_deinit(void)
@ -413,7 +394,6 @@ void ossl_lib_ctx_default_deinit(void)
if (!default_context_inited)
return;
context_deinit(&default_context_int);
CRYPTO_THREAD_cleanup_local(&default_context_thread_local);
default_context_inited = 0;
}
@ -422,7 +402,7 @@ static OSSL_LIB_CTX *get_thread_default_context(void)
if (!RUN_ONCE(&default_context_init, default_context_do_init))
return NULL;
return CRYPTO_THREAD_get_local(&default_context_thread_local);
return CRYPTO_THREAD_get_local_ex(CRYPTO_THREAD_LOCAL_DEF_CTX_KEY, NULL);
}
static OSSL_LIB_CTX *get_default_context(void)
@ -439,7 +419,7 @@ static int set_default_context(OSSL_LIB_CTX *defctx)
if (defctx == &default_context_int)
defctx = NULL;
return CRYPTO_THREAD_set_local(&default_context_thread_local, defctx);
return CRYPTO_THREAD_set_local_ex(CRYPTO_THREAD_LOCAL_DEF_CTX_KEY, NULL, defctx);
}
#endif
@ -615,9 +595,6 @@ void *ossl_lib_ctx_get_data(OSSL_LIB_CTX *ctx, int index)
#endif
#ifdef FIPS_MODULE
case OSSL_LIB_CTX_THREAD_EVENT_HANDLER_INDEX:
return ctx->thread_event_handler;
case OSSL_LIB_CTX_FIPS_PROV_INDEX:
return ctx->fips_prov;
#endif
@ -656,14 +633,6 @@ const char *ossl_lib_ctx_get_descriptor(OSSL_LIB_CTX *libctx)
#endif
}
CRYPTO_THREAD_LOCAL *ossl_lib_ctx_get_rcukey(OSSL_LIB_CTX *libctx)
{
libctx = ossl_lib_ctx_get_concrete(libctx);
if (libctx == NULL)
return NULL;
return &libctx->rcu_local_key;
}
int OSSL_LIB_CTX_get_conf_diagnostics(OSSL_LIB_CTX *libctx)
{
libctx = ossl_lib_ctx_get_concrete(libctx);

View File

@ -12,6 +12,7 @@
#include "crypto/cryptlib.h"
#include "prov/providercommon.h"
#include "internal/thread_once.h"
#include "internal/threads_common.h"
#include "crypto/context.h"
#ifdef FIPS_MODULE
@ -90,6 +91,7 @@ static int init_thread_deregister(void *arg, int all);
#endif
static void init_thread_stop(void *arg, THREAD_EVENT_HANDLER **hands);
#ifndef FIPS_MODULE
static THREAD_EVENT_HANDLER **
init_get_thread_local(CRYPTO_THREAD_LOCAL *local, int alloc, int keep)
{
@ -106,13 +108,11 @@ init_get_thread_local(CRYPTO_THREAD_LOCAL *local, int alloc, int keep)
return NULL;
}
#ifndef FIPS_MODULE
if (!init_thread_push_handlers(hands)) {
CRYPTO_THREAD_set_local(local, NULL);
OPENSSL_free(hands);
return NULL;
}
#endif
}
} else if (!keep) {
CRYPTO_THREAD_set_local(local, NULL);
@ -121,6 +121,32 @@ init_get_thread_local(CRYPTO_THREAD_LOCAL *local, int alloc, int keep)
return hands;
}
#else
static THREAD_EVENT_HANDLER **
init_get_thread_local_ex(OSSL_LIB_CTX *ctx, int alloc, int keep)
{
THREAD_EVENT_HANDLER **hands = CRYPTO_THREAD_get_local_ex(CRYPTO_THREAD_LOCAL_TEVENT_KEY, ctx);
if (alloc) {
if (hands == NULL) {
if ((hands = OPENSSL_zalloc(sizeof(*hands))) == NULL)
return NULL;
if (!CRYPTO_THREAD_set_local_ex(CRYPTO_THREAD_LOCAL_TEVENT_KEY, ctx, hands)) {
OPENSSL_free(hands);
return NULL;
}
}
} else if (!keep) {
CRYPTO_THREAD_set_local_ex(CRYPTO_THREAD_LOCAL_TEVENT_KEY, ctx, NULL);
}
return hands;
}
#endif
#ifndef FIPS_MODULE
/*
* Since per-thread-specific-data destructors are not universally
@ -258,22 +284,15 @@ int ossl_thread_register_fips(OSSL_LIB_CTX *libctx)
libctx);
}
void *ossl_thread_event_ctx_new(OSSL_LIB_CTX *libctx)
int ossl_thread_event_ctx_new(OSSL_LIB_CTX *libctx)
{
THREAD_EVENT_HANDLER **hands = NULL;
CRYPTO_THREAD_LOCAL *tlocal = OPENSSL_zalloc(sizeof(*tlocal));
if (tlocal == NULL)
return NULL;
if (!CRYPTO_THREAD_init_local(tlocal, NULL))
goto deinit;
hands = OPENSSL_zalloc(sizeof(*hands));
if (hands == NULL)
goto err;
if (!CRYPTO_THREAD_set_local(tlocal, hands))
if (!CRYPTO_THREAD_set_local_ex(CRYPTO_THREAD_LOCAL_TEVENT_KEY, libctx, hands))
goto err;
/*
@ -286,19 +305,15 @@ void *ossl_thread_event_ctx_new(OSSL_LIB_CTX *libctx)
* function.
*/
return tlocal;
return 1;
err:
OPENSSL_free(hands);
CRYPTO_THREAD_cleanup_local(tlocal);
deinit:
OPENSSL_free(tlocal);
return NULL;
return 0;
}
void ossl_thread_event_ctx_free(void *tlocal)
void ossl_thread_event_ctx_free(OSSL_LIB_CTX *ctx)
{
CRYPTO_THREAD_cleanup_local(tlocal);
OPENSSL_free(tlocal);
CRYPTO_THREAD_set_local_ex(CRYPTO_THREAD_LOCAL_TEVENT_KEY, ctx, NULL);
}
static void ossl_arg_thread_stop(void *arg)
@ -309,12 +324,8 @@ static void ossl_arg_thread_stop(void *arg)
void ossl_ctx_thread_stop(OSSL_LIB_CTX *ctx)
{
THREAD_EVENT_HANDLER **hands;
CRYPTO_THREAD_LOCAL *local
= ossl_lib_ctx_get_data(ctx, OSSL_LIB_CTX_THREAD_EVENT_HANDLER_INDEX);
if (local == NULL)
return;
hands = init_get_thread_local(local, 0, 0);
hands = init_get_thread_local_ex(ctx, 0, 0);
init_thread_stop(ctx, hands);
OPENSSL_free(hands);
}
@ -377,8 +388,7 @@ int ossl_init_thread_start(const void *index, void *arg,
* of OSSL_LIB_CTX and thread. This is because in FIPS mode each
* OSSL_LIB_CTX gets informed about thread stop events individually.
*/
CRYPTO_THREAD_LOCAL *local
= ossl_lib_ctx_get_data(ctx, OSSL_LIB_CTX_THREAD_EVENT_HANDLER_INDEX);
hands = init_get_thread_local_ex(ctx, 1, 0);
#else
/*
* Outside of FIPS mode the list of THREAD_EVENT_HANDLERs is unique per
@ -387,9 +397,9 @@ int ossl_init_thread_start(const void *index, void *arg,
* OSSL_LIB_CTXs are informed.
*/
CRYPTO_THREAD_LOCAL *local = &destructor_key.value;
hands = init_get_thread_local(local, 1, 0);
#endif
hands = init_get_thread_local(local, 1, 0);
if (hands == NULL)
return 0;

View File

@ -23,7 +23,7 @@ void *ossl_self_test_set_callback_new(OSSL_LIB_CTX *);
void *ossl_indicator_set_callback_new(OSSL_LIB_CTX *);
void *ossl_rand_crng_ctx_new(OSSL_LIB_CTX *);
int ossl_thread_register_fips(OSSL_LIB_CTX *);
void *ossl_thread_event_ctx_new(OSSL_LIB_CTX *);
int ossl_thread_event_ctx_new(OSSL_LIB_CTX *);
void *ossl_fips_prov_ossl_ctx_new(OSSL_LIB_CTX *);
#if defined(OPENSSL_THREADS)
void *ossl_threads_ctx_new(OSSL_LIB_CTX *);
@ -42,7 +42,7 @@ void ossl_prov_drbg_nonce_ctx_free(void *);
void ossl_indicator_set_callback_free(void *cb);
void ossl_self_test_set_callback_free(void *);
void ossl_rand_crng_ctx_free(void *);
void ossl_thread_event_ctx_free(void *);
void ossl_thread_event_ctx_free(OSSL_LIB_CTX *);
void ossl_fips_prov_ossl_ctx_free(void *);
void ossl_release_default_drbg_ctx(void);
#if defined(OPENSSL_THREADS)

View File

@ -103,9 +103,9 @@ typedef struct ossl_ex_data_global_st {
# define OSSL_LIB_CTX_DRBG_INDEX 5
# define OSSL_LIB_CTX_DRBG_NONCE_INDEX 6
/* slot 7 unused, was CRNG test data and can be reused */
# ifdef FIPS_MODULE
# define OSSL_LIB_CTX_THREAD_EVENT_HANDLER_INDEX 8
# endif
/*
* slot 8 unused, was OSSL_LIB_CTX_THREAD_EVENT_HANDLER_INDEX
*/
# define OSSL_LIB_CTX_FIPS_PROV_INDEX 9
# define OSSL_LIB_CTX_ENCODER_STORE_INDEX 10
# define OSSL_LIB_CTX_DECODER_STORE_INDEX 11
@ -133,7 +133,6 @@ void ossl_lib_ctx_default_deinit(void);
OSSL_EX_DATA_GLOBAL *ossl_lib_ctx_get_ex_data_global(OSSL_LIB_CTX *ctx);
const char *ossl_lib_ctx_get_descriptor(OSSL_LIB_CTX *libctx);
CRYPTO_THREAD_LOCAL *ossl_lib_ctx_get_rcukey(OSSL_LIB_CTX *libctx);
OSSL_LIB_CTX *ossl_crypto_ex_data_get_ossl_lib_ctx(const CRYPTO_EX_DATA *ad);
int ossl_crypto_new_ex_data_ex(OSSL_LIB_CTX *ctx, int class_index, void *obj,