X-Git-Url: https://git.openssl.org/gitweb/?p=openssl.git;a=blobdiff_plain;f=crypto%2Finit.c;h=143e01a44a5b27b2157c526138e56c32d09b2cec;hp=ccfd003bb630c1dfc11169394ce1a8753e5eb10f;hb=8af7e94d7b720224547efa7e3364857f7f666dd4;hpb=0b14a5b7ccd1618fe47d74a51c4873144c57ac83 diff --git a/crypto/init.c b/crypto/init.c index ccfd003bb6..143e01a44a 100644 --- a/crypto/init.c +++ b/crypto/init.c @@ -7,6 +7,7 @@ * https://www.openssl.org/source/license.html */ +#include "e_os.h" #include "internal/cryptlib_int.h" #include #include "internal/rand_int.h" @@ -26,6 +27,15 @@ #include "internal/dso.h" #include "internal/store.h" + +typedef struct global_lock_st { + CRYPTO_RWLOCK *lock; + const char *name; + struct global_lock_st *next; +} GLOBAL_LOCK; + +static GLOBAL_LOCK *global_locks; + static int stopped = 0; static void ossl_init_thread_stop(struct thread_local_inits_st *locals); @@ -43,7 +53,7 @@ static struct thread_local_inits_st *ossl_init_get_thread_local(int alloc) CRYPTO_THREAD_get_local(&threadstopkey); if (local == NULL && alloc) { - local = OPENSSL_zalloc(sizeof *local); + local = OPENSSL_zalloc(sizeof(*local)); if (local != NULL && !CRYPTO_THREAD_set_local(&threadstopkey, local)) { OPENSSL_free(local); return NULL; @@ -62,6 +72,9 @@ struct ossl_init_stop_st { OPENSSL_INIT_STOP *next; }; +static CRYPTO_RWLOCK *glock_lock = NULL; +static CRYPTO_ONCE glock_once = CRYPTO_ONCE_STATIC_INIT; + static OPENSSL_INIT_STOP *stop_handlers = NULL; static CRYPTO_RWLOCK *init_lock = NULL; @@ -83,6 +96,7 @@ DEFINE_RUN_ONCE_STATIC(ossl_init_base) #ifndef OPENSSL_SYS_UEFI atexit(OPENSSL_cleanup); #endif + /* Do not change this to glock's! */ if ((init_lock = CRYPTO_THREAD_lock_new()) == NULL) return 0; OPENSSL_cpuid_setup(); @@ -420,6 +434,7 @@ void OPENSSL_cleanup(void) stop_handlers = NULL; CRYPTO_THREAD_lock_free(init_lock); + init_lock = NULL; /* * We assume we are single-threaded for this function, i.e. no race @@ -488,7 +503,7 @@ void OPENSSL_cleanup(void) * obj_cleanup_int() must be called last */ rand_cleanup_int(); - rand_cleanup_drbg_int(); + rand_drbg_cleanup_int(); conf_modules_free_int(); #ifndef OPENSSL_NO_ENGINE engine_cleanup_int(); @@ -500,6 +515,16 @@ void OPENSSL_cleanup(void) obj_cleanup_int(); err_cleanup(); + /* Free list of global locks. */ + while (global_locks != NULL) { + GLOBAL_LOCK *next = global_locks->next; + + free(global_locks); + global_locks = next; + } + CRYPTO_THREAD_lock_free(glock_lock); + glock_lock = NULL; + base_inited = 0; } @@ -683,7 +708,55 @@ int OPENSSL_atexit(void (*handler)(void)) return 1; } -#ifdef OPENSSL_SYS_UNIX +#ifndef OPENSSL_SYS_UNIX +CRYPTO_RWLOCK *CRYPTO_THREAD_glock_new(const char *name) +{ + return CRYPTO_THREAD_lock_new(); +} + +#else +DEFINE_RUN_ONCE_STATIC(glock_init) +{ + glock_lock = CRYPTO_THREAD_lock_new(); + return glock_lock != NULL; +} + +/* + * Create a new global lock, return NULL on error. + */ +CRYPTO_RWLOCK *CRYPTO_THREAD_glock_new(const char *name) +{ + GLOBAL_LOCK *newlock; + + if (glock_lock == NULL && !RUN_ONCE(&glock_once, glock_init)) + return NULL; + if ((newlock = malloc(sizeof(*newlock))) == NULL) + return NULL; + if ((newlock->lock = CRYPTO_THREAD_lock_new()) == NULL) { + free(newlock); + return NULL; + } + newlock->name = name; + CRYPTO_THREAD_write_lock(glock_lock); + newlock->next = global_locks; + global_locks = newlock; + CRYPTO_THREAD_unlock(glock_lock); + return newlock->lock; +} + +/* + * Unlock all global locks. + */ +static void unlock_all(void) +{ + GLOBAL_LOCK *lp; + + CRYPTO_THREAD_write_lock(glock_lock); + for (lp = global_locks; lp != NULL; lp = lp->next) + CRYPTO_THREAD_unlock(lp->lock); + CRYPTO_THREAD_unlock(glock_lock); +} + /* * The following three functions are for OpenSSL developers. This is * where we set/reset state across fork (called via pthread_atfork when @@ -697,14 +770,22 @@ int OPENSSL_atexit(void (*handler)(void)) void OPENSSL_fork_prepare(void) { + GLOBAL_LOCK *lp; + + CRYPTO_THREAD_write_lock(glock_lock); + for (lp = global_locks; lp != NULL; lp = lp->next) + CRYPTO_THREAD_write_lock(lp->lock); + CRYPTO_THREAD_unlock(glock_lock); } void OPENSSL_fork_parent(void) { + unlock_all(); } void OPENSSL_fork_child(void) { + unlock_all(); rand_fork(); } #endif