X-Git-Url: https://git.openssl.org/gitweb/?p=openssl.git;a=blobdiff_plain;f=crypto%2Fex_data.c;h=ca1c204f38e116c2f81e0a957d52d92deb383109;hp=fcdc83f9d130375822ba5a6e837aa679072cd54b;hb=fa79c543d28c3543b3fcaa8adf5fe3d43cdba1c8;hpb=4a1f3f274108e25b97bd9870170fe2970892e155 diff --git a/crypto/ex_data.c b/crypto/ex_data.c index fcdc83f9d1..ca1c204f38 100644 --- a/crypto/ex_data.c +++ b/crypto/ex_data.c @@ -108,7 +108,8 @@ * */ -#include "internal/cryptlib.h" +#include "internal/cryptlib_int.h" +#include "internal/threads.h" #include /* @@ -116,8 +117,8 @@ * exdata has a stack of callbacks for each instance. */ struct ex_callback_st { - long argl; /* Arbitary long */ - void *argp; /* Arbitary void * */ + long argl; /* Arbitrary long */ + void *argp; /* Arbitrary void * */ CRYPTO_EX_new *new_func; CRYPTO_EX_free *free_func; CRYPTO_EX_dup *dup_func; @@ -133,6 +134,14 @@ typedef struct ex_callbacks_st { static EX_CALLBACKS ex_data[CRYPTO_EX_INDEX__COUNT]; +static CRYPTO_RWLOCK *ex_data_lock = NULL; +static CRYPTO_ONCE ex_data_init = CRYPTO_ONCE_STATIC_INIT; + +static void do_ex_data_init(void) +{ + ex_data_lock = CRYPTO_THREAD_lock_new(); +} + /* * Return the EX_CALLBACKS from the |ex_data| array that corresponds to * a given class. On success, *holds the lock.* @@ -142,23 +151,27 @@ static EX_CALLBACKS *get_and_lock(int class_index) EX_CALLBACKS *ip; if (class_index < 0 || class_index >= CRYPTO_EX_INDEX__COUNT) { - CRYPTOerr(CRYPTO_F_GET_AND_LOCK, ERR_R_MALLOC_FAILURE); + CRYPTOerr(CRYPTO_F_GET_AND_LOCK, ERR_R_PASSED_INVALID_ARGUMENT); return NULL; } - ip = &ex_data[class_index]; - CRYPTO_w_lock(CRYPTO_LOCK_EX_DATA); - if (ip->meth == NULL) { - ip->meth = sk_EX_CALLBACK_new_null(); - /* We push an initial value on the stack because the SSL - * "app_data" routines use ex_data index zero. See RT 3710. */ - if (ip->meth == NULL - || !sk_EX_CALLBACK_push(ip->meth, NULL)) { - CRYPTOerr(CRYPTO_F_GET_AND_LOCK, ERR_R_MALLOC_FAILURE); - CRYPTO_w_unlock(CRYPTO_LOCK_EX_DATA); - return NULL; - } + CRYPTO_THREAD_run_once(&ex_data_init, do_ex_data_init); + + if (ex_data_lock == NULL) { + /* + * This can happen in normal operation when using CRYPTO_mem_leaks(). + * The CRYPTO_mem_leaks() function calls OPENSSL_cleanup() which cleans + * up the locks. Subsequently the BIO that CRYPTO_mem_leaks() uses gets + * freed, which also attempts to free the ex_data. However + * CRYPTO_mem_leaks() ensures that the ex_data is freed early (i.e. + * before OPENSSL_cleanup() is called), so if we get here we can safely + * ignore this operation. We just treat it as an error. + */ + return NULL; } + + ip = &ex_data[class_index]; + CRYPTO_THREAD_write_lock(ex_data_lock); return ip; } @@ -173,7 +186,7 @@ static void cleanup_cb(EX_CALLBACK *funcs) * called under potential race-conditions anyway (it's for program shutdown * after all). */ -void CRYPTO_cleanup_all_ex_data(void) +void crypto_cleanup_all_ex_data_int(void) { int i; @@ -183,6 +196,9 @@ void CRYPTO_cleanup_all_ex_data(void) sk_EX_CALLBACK_pop_free(ip->meth, cleanup_cb); ip->meth = NULL; } + + CRYPTO_THREAD_lock_free(ex_data_lock); + ex_data_lock = NULL; } @@ -225,7 +241,7 @@ int CRYPTO_free_ex_index(int class_index, int idx) a->free_func = dummy_free; toret = 1; err: - CRYPTO_w_unlock(CRYPTO_LOCK_EX_DATA); + CRYPTO_THREAD_unlock(ex_data_lock); return toret; } @@ -242,6 +258,18 @@ int CRYPTO_get_ex_new_index(int class_index, long argl, void *argp, if (ip == NULL) return -1; + + if (ip->meth == NULL) { + ip->meth = sk_EX_CALLBACK_new_null(); + /* We push an initial value on the stack because the SSL + * "app_data" routines use ex_data index zero. See RT 3710. */ + if (ip->meth == NULL + || !sk_EX_CALLBACK_push(ip->meth, NULL)) { + CRYPTOerr(CRYPTO_F_CRYPTO_GET_EX_NEW_INDEX, ERR_R_MALLOC_FAILURE); + goto err; + } + } + a = (EX_CALLBACK *)OPENSSL_malloc(sizeof(*a)); if (a == NULL) { CRYPTOerr(CRYPTO_F_CRYPTO_GET_EX_NEW_INDEX, ERR_R_MALLOC_FAILURE); @@ -262,7 +290,7 @@ int CRYPTO_get_ex_new_index(int class_index, long argl, void *argp, (void)sk_EX_CALLBACK_set(ip->meth, toret, a); err: - CRYPTO_w_unlock(CRYPTO_LOCK_EX_DATA); + CRYPTO_THREAD_unlock(ex_data_lock); return toret; } @@ -296,7 +324,7 @@ int CRYPTO_new_ex_data(int class_index, void *obj, CRYPTO_EX_DATA *ad) for (i = 0; i < mx; i++) storage[i] = sk_EX_CALLBACK_value(ip->meth, i); } - CRYPTO_w_unlock(CRYPTO_LOCK_EX_DATA); + CRYPTO_THREAD_unlock(ex_data_lock); if (mx > 0 && storage == NULL) { CRYPTOerr(CRYPTO_F_CRYPTO_NEW_EX_DATA, ERR_R_MALLOC_FAILURE); @@ -346,7 +374,7 @@ int CRYPTO_dup_ex_data(int class_index, CRYPTO_EX_DATA *to, for (i = 0; i < mx; i++) storage[i] = sk_EX_CALLBACK_value(ip->meth, i); } - CRYPTO_w_unlock(CRYPTO_LOCK_EX_DATA); + CRYPTO_THREAD_unlock(ex_data_lock); if (mx > 0 && storage == NULL) { CRYPTOerr(CRYPTO_F_CRYPTO_DUP_EX_DATA, ERR_R_MALLOC_FAILURE); @@ -391,7 +419,7 @@ void CRYPTO_free_ex_data(int class_index, void *obj, CRYPTO_EX_DATA *ad) for (i = 0; i < mx; i++) storage[i] = sk_EX_CALLBACK_value(ip->meth, i); } - CRYPTO_w_unlock(CRYPTO_LOCK_EX_DATA); + CRYPTO_THREAD_unlock(ex_data_lock); if (mx > 0 && storage == NULL) { CRYPTOerr(CRYPTO_F_CRYPTO_FREE_EX_DATA, ERR_R_MALLOC_FAILURE);