From: Nikos Mavrogiannopoulos Date: Sun, 19 Feb 2017 08:57:39 +0000 (+0100) Subject: random: keep global list of initialized contexts X-Git-Tag: gnutls_3_6_0~896 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=11aeb4a61dfd1b68a446b276ab1f8cd5d4f12ddf;p=thirdparty%2Fgnutls.git random: keep global list of initialized contexts This allows to properly deinitialize all random generator contexts on library deinitialization. Signed-off-by: Nikos Mavrogiannopoulos --- 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;