--- crypto/fips/fips_entropy.c | 40 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) --- a/crypto/fips/fips_entropy.c +++ b/crypto/fips/fips_entropy.c @@ -4,35 +4,71 @@ #include "jitterentropy.h" static struct rand_data* ec = NULL; +static CRYPTO_RWLOCK *jent_lock = NULL; +static int stop = 0; struct rand_data* FIPS_entropy_init(void) { - if (ec != NULL) + if (ec != NULL) { /* Entropy source has been initiated and collector allocated */ return ec; + } + if (stop != 0) { + /* FIPS_entropy_cleanup() already called, don't initialize it again */ + return NULL; + } + if (jent_lock == NULL) { + /* Allocates a new lock to serialize access to jent library */ + jent_lock = CRYPTO_THREAD_lock_new(); + if (jent_lock == NULL) { + return NULL; + } + } + if (CRYPTO_THREAD_write_lock(jent_lock) == 0) { + return NULL; + } /* If the initialization is successful, the call returns with 0 */ if (jent_entropy_init_ex(1, JENT_FORCE_FIPS) == 0) /* Allocate entropy collector */ ec = jent_entropy_collector_alloc(1, JENT_FORCE_FIPS); + CRYPTO_THREAD_unlock(jent_lock); return ec; } void FIPS_entropy_cleanup(void) { + if (jent_lock != NULL && stop == 0) { + CRYPTO_THREAD_write_lock(jent_lock); + } + /* Disable re-initialization in FIPS_entropy_init() */ + stop = 1; /* Free entropy collector */ if (ec != NULL) { jent_entropy_collector_free(ec); ec = NULL; } + CRYPTO_THREAD_lock_free(jent_lock); + jent_lock = NULL; } ssize_t FIPS_jitter_entropy(unsigned char *buf, size_t buflen) { ssize_t ent_bytes = -1; - if (buf != NULL && buflen != 0 && FIPS_entropy_init()) { + /* + * Order is important. We need to call FIPS_entropy_init() before we + * acquire jent_lock, otherwise it can lead to deadlock. Once we have + * jent_lock, we need to ensure that FIPS_entropy_cleanup() was not called + * in the meantime. Then it's safe to read entropy. + */ + if (buf != NULL + && buflen != 0 + && FIPS_entropy_init() + && CRYPTO_THREAD_write_lock(jent_lock) != 0 + && stop == 0) { /* Get entropy */ ent_bytes = jent_read_entropy_safe(&ec, (char *)buf, buflen); + CRYPTO_THREAD_unlock(jent_lock); } return ent_bytes; }