The branch openssl-3.0 has been updated via 81c11349c2a0e945aa3dfc6bd81c957363dd2011 (commit) from fd6a1e21f906883d0cc7ebef7826cf2f55f87832 (commit)
- Log ----------------------------------------------------------------- commit 81c11349c2a0e945aa3dfc6bd81c957363dd2011 Author: Bernd Edlinger <bernd.edlin...@hotmail.de> Date: Fri Nov 19 11:33:34 2021 +0100 Avoid loading of a dynamic engine twice Use the address of the bind function as a DYNAMIC_ID, since the true name of the engine is not known before the bind function returns, but invoking the bind function before the engine is unloaded results in memory corruption. Fixes #17023 Reviewed-by: Tomas Mraz <to...@openssl.org> Reviewed-by: Dmitry Belyavskiy <beld...@gmail.com> (Merged from https://github.com/openssl/openssl/pull/17073) (cherry picked from commit e2571e02d2b0cd83ed1c79d384fe941f27e603c0) ----------------------------------------------------------------------- Summary of changes: crypto/engine/eng_dyn.c | 4 ++- crypto/engine/eng_lib.c | 2 ++ crypto/engine/eng_list.c | 87 +++++++++++++++++++++++++++++++++++++++++++++++ crypto/engine/eng_local.h | 9 +++++ 4 files changed, 101 insertions(+), 1 deletion(-) diff --git a/crypto/engine/eng_dyn.c b/crypto/engine/eng_dyn.c index f401063d37..c8a54f7d44 100644 --- a/crypto/engine/eng_dyn.c +++ b/crypto/engine/eng_dyn.c @@ -484,7 +484,9 @@ static int dynamic_load(ENGINE *e, dynamic_data_ctx *ctx) engine_set_all_null(e); /* Try to bind the ENGINE onto our own ENGINE structure */ - if (!ctx->bind_engine(e, ctx->engine_id, &fns)) { + if (!engine_add_dynamic_id(e, (ENGINE_DYNAMIC_ID)ctx->bind_engine, 1) + || !ctx->bind_engine(e, ctx->engine_id, &fns)) { + engine_remove_dynamic_id(e, 1); ctx->bind_engine = NULL; ctx->v_check = NULL; DSO_free(ctx->dynamic_dso); diff --git a/crypto/engine/eng_lib.c b/crypto/engine/eng_lib.c index 44e997e77b..05c6a67c1e 100644 --- a/crypto/engine/eng_lib.c +++ b/crypto/engine/eng_lib.c @@ -65,6 +65,7 @@ void engine_set_all_null(ENGINE *e) e->load_pubkey = NULL; e->cmd_defns = NULL; e->flags = 0; + e->dynamic_id = NULL; } int engine_free_util(ENGINE *e, int not_locked) @@ -90,6 +91,7 @@ int engine_free_util(ENGINE *e, int not_locked) */ if (e->destroy) e->destroy(e); + engine_remove_dynamic_id(e, not_locked); CRYPTO_free_ex_data(CRYPTO_EX_INDEX_ENGINE, e, &e->ex_data); OPENSSL_free(e); return 1; diff --git a/crypto/engine/eng_list.c b/crypto/engine/eng_list.c index fec0ef7129..04c73c7628 100644 --- a/crypto/engine/eng_list.c +++ b/crypto/engine/eng_list.c @@ -27,6 +27,12 @@ static ENGINE *engine_list_head = NULL; static ENGINE *engine_list_tail = NULL; +/* + * The linked list of currently loaded dynamic engines. + */ +static ENGINE *engine_dyn_list_head = NULL; +static ENGINE *engine_dyn_list_tail = NULL; + /* * This cleanup function is only needed internally. If it should be called, * we register it with the "engine_cleanup_int()" stack to be called during @@ -128,6 +134,85 @@ static int engine_list_remove(ENGINE *e) return 1; } +/* Add engine to dynamic engine list. */ +int engine_add_dynamic_id(ENGINE *e, ENGINE_DYNAMIC_ID dynamic_id, + int not_locked) +{ + int result = 0; + ENGINE *iterator = NULL; + + if (e == NULL) + return 0; + + if (e->dynamic_id == NULL && dynamic_id == NULL) + return 0; + + if (not_locked && !CRYPTO_THREAD_write_lock(global_engine_lock)) + return 0; + + if (dynamic_id != NULL) { + iterator = engine_dyn_list_head; + while (iterator != NULL) { + if (iterator->dynamic_id == dynamic_id) + goto err; + iterator = iterator->next; + } + if (e->dynamic_id != NULL) + goto err; + e->dynamic_id = dynamic_id; + } + + if (engine_dyn_list_head == NULL) { + /* We are adding to an empty list. */ + if (engine_dyn_list_tail != NULL) + goto err; + engine_dyn_list_head = e; + e->prev_dyn = NULL; + } else { + /* We are adding to the tail of an existing list. */ + if (engine_dyn_list_tail == NULL + || engine_dyn_list_tail->next_dyn != NULL) + goto err; + engine_dyn_list_tail->next_dyn = e; + e->prev_dyn = engine_dyn_list_tail; + } + + engine_dyn_list_tail = e; + e->next_dyn = NULL; + result = 1; + + err: + if (not_locked) + CRYPTO_THREAD_unlock(global_engine_lock); + return result; +} + +/* Remove engine from dynamic engine list. */ +void engine_remove_dynamic_id(ENGINE *e, int not_locked) +{ + if (e == NULL || e->dynamic_id == NULL) + return; + + if (not_locked && !CRYPTO_THREAD_write_lock(global_engine_lock)) + return; + + e->dynamic_id = NULL; + + /* un-link e from the chain. */ + if (e->next_dyn != NULL) + e->next_dyn->prev_dyn = e->prev_dyn; + if (e->prev_dyn != NULL) + e->prev_dyn->next_dyn = e->next_dyn; + /* Correct our head/tail if necessary. */ + if (engine_dyn_list_head == e) + engine_dyn_list_head = e->next_dyn; + if (engine_dyn_list_tail == e) + engine_dyn_list_tail = e->prev_dyn; + + if (not_locked) + CRYPTO_THREAD_unlock(global_engine_lock); +} + /* Get the first/last "ENGINE" type available. */ ENGINE *ENGINE_get_first(void) { @@ -278,6 +363,8 @@ static void engine_cpy(ENGINE *dest, const ENGINE *src) dest->load_pubkey = src->load_pubkey; dest->cmd_defns = src->cmd_defns; dest->flags = src->flags; + dest->dynamic_id = src->dynamic_id; + engine_add_dynamic_id(dest, NULL, 0); } ENGINE *ENGINE_by_id(const char *id) diff --git a/crypto/engine/eng_local.h b/crypto/engine/eng_local.h index 455dc1fdb7..03a86299cf 100644 --- a/crypto/engine/eng_local.h +++ b/crypto/engine/eng_local.h @@ -99,6 +99,11 @@ void engine_pkey_asn1_meths_free(ENGINE *e); extern CRYPTO_ONCE engine_lock_init; DECLARE_RUN_ONCE(do_engine_lock_init) +typedef void (*ENGINE_DYNAMIC_ID)(void); +int engine_add_dynamic_id(ENGINE *e, ENGINE_DYNAMIC_ID dynamic_id, + int not_locked); +void engine_remove_dynamic_id(ENGINE *e, int not_locked); + /* * This is a structure for storing implementations of various crypto * algorithms and functions. @@ -143,6 +148,10 @@ struct engine_st { /* Used to maintain the linked-list of engines. */ struct engine_st *prev; struct engine_st *next; + /* Used to maintain the linked-list of dynamic engines. */ + struct engine_st *prev_dyn; + struct engine_st *next_dyn; + ENGINE_DYNAMIC_ID dynamic_id; }; typedef struct st_engine_pile ENGINE_PILE;