diff options
author | Nikos Mavrogiannopoulos <nmav@redhat.com> | 2017-02-19 09:57:39 +0100 |
---|---|---|
committer | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2017-03-06 22:24:33 +0100 |
commit | 11aeb4a61dfd1b68a446b276ab1f8cd5d4f12ddf (patch) | |
tree | 667c2ec121b50d20ca057e0f95bc354d2ea5c9ab | |
parent | c665b226dfcb0815d51283bdf7232f75d96fff4d (diff) | |
download | gnutls-11aeb4a61dfd1b68a446b276ab1f8cd5d4f12ddf.tar.gz |
random: keep global list of initialized contexts
This allows to properly deinitialize all random generator
contexts on library deinitialization.
Signed-off-by: Nikos Mavrogiannopoulos <nmav@redhat.com>
-rw-r--r-- | lib/random.c | 54 |
1 files changed, 50 insertions, 4 deletions
diff --git a/lib/random.c b/lib/random.c index 73fb143d7f..2fe82adc7d 100644 --- a/lib/random.c +++ b/lib/random.c @@ -37,13 +37,41 @@ # error Unsupported platform #endif -static _Thread_local void *gnutls_rnd_ctx; +/* Per thread context of random generator, and a flag to indicate initialization */ +static _Thread_local void *gnutls_rnd_ctx; static _Thread_local unsigned rnd_initialized = 0; +struct rnd_ctx_list_st { + void *ctx; + struct rnd_ctx_list_st *next; +}; + +/* A global list of all allocated contexts - to be + * used during deinitialization. */ +GNUTLS_STATIC_MUTEX(gnutls_rnd_ctx_list_mutex); +static struct rnd_ctx_list_st *head = NULL; + +static int append(void *ctx) +{ + struct rnd_ctx_list_st *e = gnutls_malloc(sizeof(*e)); + + if (e == NULL) + return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); + + e->ctx = ctx; + e->next = head; + + head = e; + + return 0; +} + inline static int _gnutls_rnd_init(void) { if (unlikely(!rnd_initialized)) { + int ret; + if (_gnutls_rnd_ops.init == NULL) { rnd_initialized = 1; return 0; @@ -53,6 +81,16 @@ inline static int _gnutls_rnd_init(void) gnutls_assert(); return GNUTLS_E_RANDOM_FAILED; } + + GNUTLS_STATIC_MUTEX_LOCK(gnutls_rnd_ctx_list_mutex); + ret = append(gnutls_rnd_ctx); + GNUTLS_STATIC_MUTEX_UNLOCK(gnutls_rnd_ctx_list_mutex); + if (ret < 0) { + gnutls_assert(); + _gnutls_rnd_ops.deinit(gnutls_rnd_ctx); + return ret; + } + rnd_initialized = 1; } return 0; @@ -84,11 +122,19 @@ int _gnutls_rnd_preinit(void) void _gnutls_rnd_deinit(void) { - if (rnd_initialized && _gnutls_rnd_ops.deinit != NULL) { - _gnutls_rnd_ops.deinit(gnutls_rnd_ctx); + if (_gnutls_rnd_ops.deinit != NULL) { + struct rnd_ctx_list_st *e = head, *next; + + while(e != NULL) { + next = e->next; + _gnutls_rnd_ops.deinit(e->ctx); + gnutls_free(e); + e = next; + } + head = NULL; } - rnd_initialized = 0; + rnd_initialized = 0; _rnd_system_entropy_deinit(); return; |