diff options
author | Hugo Landau <hlandau@openssl.org> | 2022-05-17 13:47:57 +0100 |
---|---|---|
committer | Tomas Mraz <tomas@openssl.org> | 2022-06-01 15:17:45 +0200 |
commit | f9f3096fd26ade6c188ae878a627920c0ddbd803 (patch) | |
tree | b7a6743bfc6725b142a5e96d1bdbb651f62fe7aa /crypto | |
parent | bd4ed81faa3469fddecd273cafa49bd9996d4a88 (diff) |
Make OSSL_LIB_CTX_load_config thread safe
Fixes #18226.
Reviewed-by: Matt Caswell <matt@openssl.org>
Reviewed-by: Paul Dale <pauli@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/18331)
(cherry picked from commit ef7a9b44f04ef18b652cb47cd9eb3826301cca9e)
Diffstat (limited to 'crypto')
-rw-r--r-- | crypto/conf/conf_mod.c | 106 |
1 files changed, 88 insertions, 18 deletions
diff --git a/crypto/conf/conf_mod.c b/crypto/conf/conf_mod.c index 36b054ca51..6286282108 100644 --- a/crypto/conf/conf_mod.c +++ b/crypto/conf/conf_mod.c @@ -62,8 +62,10 @@ struct conf_imodule_st { void *usr_data; }; -static STACK_OF(CONF_MODULE) *supported_modules = NULL; -static STACK_OF(CONF_IMODULE) *initialized_modules = NULL; +static CRYPTO_ONCE init_module_list_lock = CRYPTO_ONCE_STATIC_INIT; +static CRYPTO_RWLOCK *module_list_lock = NULL; +static STACK_OF(CONF_MODULE) *supported_modules = NULL; /* protected by lock */ +static STACK_OF(CONF_IMODULE) *initialized_modules = NULL; /* protected by lock */ static CRYPTO_ONCE load_builtin_modules = CRYPTO_ONCE_STATIC_INIT; @@ -80,6 +82,29 @@ static int module_init(CONF_MODULE *pmod, const char *name, const char *value, static CONF_MODULE *module_load_dso(const CONF *cnf, const char *name, const char *value); +static void module_lists_free(void) +{ + CRYPTO_THREAD_lock_free(module_list_lock); + module_list_lock = NULL; + + sk_CONF_MODULE_free(supported_modules); + supported_modules = NULL; + + sk_CONF_IMODULE_free(initialized_modules); + initialized_modules = NULL; +} + +DEFINE_RUN_ONCE_STATIC(do_init_module_list_lock) +{ + module_list_lock = CRYPTO_THREAD_lock_new(); + if (module_list_lock == NULL) { + ERR_raise(ERR_LIB_CONF, ERR_R_MALLOC_FAILURE); + return 0; + } + + return 1; +} + static int conf_diagnostics(const CONF *cnf) { return _CONF_get_number(cnf, NULL, "config_diagnostics") != 0; @@ -294,31 +319,42 @@ static CONF_MODULE *module_add(DSO *dso, const char *name, conf_init_func *ifunc, conf_finish_func *ffunc) { CONF_MODULE *tmod = NULL; + + if (!RUN_ONCE(&init_module_list_lock, do_init_module_list_lock)) + return NULL; + + if (!CRYPTO_THREAD_write_lock(module_list_lock)) + return NULL; + if (supported_modules == NULL) supported_modules = sk_CONF_MODULE_new_null(); if (supported_modules == NULL) - return NULL; + goto err; if ((tmod = OPENSSL_zalloc(sizeof(*tmod))) == NULL) { ERR_raise(ERR_LIB_CONF, ERR_R_MALLOC_FAILURE); - return NULL; + goto err; } tmod->dso = dso; tmod->name = OPENSSL_strdup(name); tmod->init = ifunc; tmod->finish = ffunc; - if (tmod->name == NULL) { - OPENSSL_free(tmod); - return NULL; - } + if (tmod->name == NULL) + goto err; + + if (!sk_CONF_MODULE_push(supported_modules, tmod)) + goto err; - if (!sk_CONF_MODULE_push(supported_modules, tmod)) { + CRYPTO_THREAD_unlock(module_list_lock); + return tmod; + + err: + CRYPTO_THREAD_unlock(module_list_lock); + if (tmod != NULL) { OPENSSL_free(tmod->name); OPENSSL_free(tmod); - return NULL; } - - return tmod; + return NULL; } /* @@ -339,14 +375,22 @@ static CONF_MODULE *module_find(const char *name) else nchar = strlen(name); + if (!RUN_ONCE(&init_module_list_lock, do_init_module_list_lock)) + return NULL; + + if (!CRYPTO_THREAD_read_lock(module_list_lock)) + return NULL; + for (i = 0; i < sk_CONF_MODULE_num(supported_modules); i++) { tmod = sk_CONF_MODULE_value(supported_modules, i); - if (strncmp(tmod->name, name, nchar) == 0) + if (strncmp(tmod->name, name, nchar) == 0) { + CRYPTO_THREAD_unlock(module_list_lock); return tmod; + } } + CRYPTO_THREAD_unlock(module_list_lock); return NULL; - } /* initialize a module */ @@ -379,21 +423,30 @@ static int module_init(CONF_MODULE *pmod, const char *name, const char *value, goto err; } + if (!RUN_ONCE(&init_module_list_lock, do_init_module_list_lock)) + goto err; + + if (!CRYPTO_THREAD_write_lock(module_list_lock)) + goto err; + if (initialized_modules == NULL) { initialized_modules = sk_CONF_IMODULE_new_null(); - if (!initialized_modules) { + if (initialized_modules == NULL) { + CRYPTO_THREAD_unlock(module_list_lock); ERR_raise(ERR_LIB_CONF, ERR_R_MALLOC_FAILURE); goto err; } } if (!sk_CONF_IMODULE_push(initialized_modules, imod)) { + CRYPTO_THREAD_unlock(module_list_lock); ERR_raise(ERR_LIB_CONF, ERR_R_MALLOC_FAILURE); goto err; } pmod->links++; + CRYPTO_THREAD_unlock(module_list_lock); return ret; err: @@ -423,7 +476,12 @@ void CONF_modules_unload(int all) { int i; CONF_MODULE *md; - CONF_modules_finish(); + + CONF_modules_finish(); /* also inits module list lock */ + + if (!CRYPTO_THREAD_write_lock(module_list_lock)) + return; + /* unload modules in reverse order */ for (i = sk_CONF_MODULE_num(supported_modules) - 1; i >= 0; i--) { md = sk_CONF_MODULE_value(supported_modules, i); @@ -434,10 +492,13 @@ void CONF_modules_unload(int all) (void)sk_CONF_MODULE_delete(supported_modules, i); module_free(md); } + if (sk_CONF_MODULE_num(supported_modules) == 0) { sk_CONF_MODULE_free(supported_modules); supported_modules = NULL; } + + CRYPTO_THREAD_unlock(module_list_lock); } /* unload a single module */ @@ -453,12 +514,21 @@ static void module_free(CONF_MODULE *md) void CONF_modules_finish(void) { CONF_IMODULE *imod; + + if (!RUN_ONCE(&init_module_list_lock, do_init_module_list_lock)) + return; + + if (!CRYPTO_THREAD_write_lock(module_list_lock)) + return; + while (sk_CONF_IMODULE_num(initialized_modules) > 0) { imod = sk_CONF_IMODULE_pop(initialized_modules); module_finish(imod); } sk_CONF_IMODULE_free(initialized_modules); initialized_modules = NULL; + + CRYPTO_THREAD_unlock(module_list_lock); } /* finish a module instance */ @@ -488,8 +558,8 @@ int CONF_module_add(const char *name, conf_init_func *ifunc, void ossl_config_modules_free(void) { - CONF_modules_finish(); - CONF_modules_unload(1); + CONF_modules_unload(1); /* calls CONF_modules_finish */ + module_lists_free(); } /* Utility functions */ |