X-Git-Url: https://git.openssl.org/gitweb/?a=blobdiff_plain;f=crypto%2Finit.c;h=5e6be10fcaf809224f4ecc9d5111e89108548e89;hb=23fed8ba0ec895e1b2a089cae380697f15170afc;hp=37b7a7c72eabb5d3b58b07c6044712179814baa4;hpb=cdb10bae3f773401e039c55965eb177a6f3fc160;p=openssl.git diff --git a/crypto/init.c b/crypto/init.c index 37b7a7c72e..5e6be10fca 100644 --- a/crypto/init.c +++ b/crypto/init.c @@ -1,7 +1,7 @@ /* * Copyright 2016-2018 The OpenSSL Project Authors. All Rights Reserved. * - * Licensed under the OpenSSL license (the "License"). You may not use + * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy * in the file LICENSE in the source distribution or at * https://www.openssl.org/source/license.html @@ -30,11 +30,28 @@ static int stopped = 0; -static void ossl_init_thread_stop(struct thread_local_inits_st *locals); +/* + * Since per-thread-specific-data destructors are not universally + * available, i.e. not on Windows, only below CRYPTO_THREAD_LOCAL key + * is assumed to have destructor associated. And then an effort is made + * to call this single destructor on non-pthread platform[s]. + * + * Initial value is "impossible". It is used as guard value to shortcut + * destructor for threads terminating before libcrypto is initialized or + * after it's de-initialized. Access to the key doesn't have to be + * serialized for the said threads, because they didn't use libcrypto + * and it doesn't matter if they pick "impossible" or derefernce real + * key value and pull NULL past initialization in the first thread that + * intends to use libcrypto. + */ +static union { + long sane; + CRYPTO_THREAD_LOCAL value; +} destructor_key = { -1 }; -static CRYPTO_THREAD_LOCAL threadstopkey; +static void ossl_init_thread_stop(struct thread_local_inits_st *locals); -static void ossl_init_thread_stop_wrap(void *local) +static void ossl_init_thread_destructor(void *local) { ossl_init_thread_stop((struct thread_local_inits_st *)local); } @@ -42,17 +59,17 @@ static void ossl_init_thread_stop_wrap(void *local) static struct thread_local_inits_st *ossl_init_get_thread_local(int alloc) { struct thread_local_inits_st *local = - CRYPTO_THREAD_get_local(&threadstopkey); + CRYPTO_THREAD_get_local(&destructor_key.value); - if (local == NULL && alloc) { - local = OPENSSL_zalloc(sizeof(*local)); - if (local != NULL && !CRYPTO_THREAD_set_local(&threadstopkey, local)) { + if (alloc) { + if (local == NULL + && (local = OPENSSL_zalloc(sizeof(*local))) != NULL + && !CRYPTO_THREAD_set_local(&destructor_key.value, local)) { OPENSSL_free(local); return NULL; } - } - if (!alloc) { - CRYPTO_THREAD_set_local(&threadstopkey, NULL); + } else { + CRYPTO_THREAD_set_local(&destructor_key.value, NULL); } return local; @@ -71,33 +88,82 @@ static CRYPTO_ONCE base = CRYPTO_ONCE_STATIC_INIT; static int base_inited = 0; DEFINE_RUN_ONCE_STATIC(ossl_init_base) { + CRYPTO_THREAD_LOCAL key; + #ifdef OPENSSL_INIT_DEBUG fprintf(stderr, "OPENSSL_INIT: ossl_init_base: Setting up stop handlers\n"); #endif #ifndef OPENSSL_NO_CRYPTO_MDEBUG ossl_malloc_setup_failures(); #endif - /* - * We use a dummy thread local key here. We use the destructor to detect - * when the thread is going to stop (where that feature is available) - */ - CRYPTO_THREAD_init_local(&threadstopkey, ossl_init_thread_stop_wrap); -#ifndef OPENSSL_SYS_UEFI - atexit(OPENSSL_cleanup); -#endif - if ((init_lock = CRYPTO_THREAD_lock_new()) == NULL) + if (!CRYPTO_THREAD_init_local(&key, ossl_init_thread_destructor)) return 0; + if ((init_lock = CRYPTO_THREAD_lock_new()) == NULL) + goto err; OPENSSL_cpuid_setup(); - /* - * BIG FAT WARNING! - * Everything needed to be initialized in this function before threads - * come along MUST happen before base_inited is set to 1, or we will - * see race conditions. - */ + destructor_key.value = key; base_inited = 1; + return 1; + +err: +#ifdef OPENSSL_INIT_DEBUG + fprintf(stderr, "OPENSSL_INIT: ossl_init_base not ok!\n"); +#endif + CRYPTO_THREAD_lock_free(init_lock); + init_lock = NULL; + + CRYPTO_THREAD_cleanup_local(&key); + return 0; +} + +static CRYPTO_ONCE register_atexit = CRYPTO_ONCE_STATIC_INIT; +#if !defined(OPENSSL_SYS_UEFI) && defined(_WIN32) +static int win32atexit(void) +{ + OPENSSL_cleanup(); + return 0; +} +#endif -#if !defined(OPENSSL_NO_DSO) && !defined(OPENSSL_USE_NODELETE) +DEFINE_RUN_ONCE_STATIC(ossl_init_register_atexit) +{ +#ifdef OPENSSL_INIT_DEBUG + fprintf(stderr, "OPENSSL_INIT: ossl_init_register_atexit()\n"); +#endif +#ifndef OPENSSL_SYS_UEFI +# ifdef _WIN32 + /* We use _onexit() in preference because it gets called on DLL unload */ + if (_onexit(win32atexit) == NULL) + return 0; +# else + if (atexit(OPENSSL_cleanup) != 0) + return 0; +# endif +#endif + + return 1; +} + +DEFINE_RUN_ONCE_STATIC_ALT(ossl_init_no_register_atexit, + ossl_init_register_atexit) +{ +#ifdef OPENSSL_INIT_DEBUG + fprintf(stderr, "OPENSSL_INIT: ossl_init_no_register_atexit ok!\n"); +#endif + /* Do nothing in this case */ + return 1; +} + +static CRYPTO_ONCE load_crypto_nodelete = CRYPTO_ONCE_STATIC_INIT; +DEFINE_RUN_ONCE_STATIC(ossl_init_load_crypto_nodelete) +{ +#ifdef OPENSSL_INIT_DEBUG + fprintf(stderr, "OPENSSL_INIT: ossl_init_load_crypto_nodelete()\n"); +#endif +#if !defined(OPENSSL_NO_DSO) \ + && !defined(OPENSSL_USE_NODELETE) \ + && !defined(OPENSSL_NO_PINSHARED) # ifdef DSO_WIN32 { HMODULE handle = NULL; @@ -108,6 +174,10 @@ DEFINE_RUN_ONCE_STATIC(ossl_init_base) | GET_MODULE_HANDLE_EX_FLAG_PIN, (void *)&base_inited, &handle); +# ifdef OPENSSL_INIT_DEBUG + fprintf(stderr, "OPENSSL_INIT: obtained DSO reference? %s\n", + (ret == TRUE ? "No!" : "Yes.")); +# endif return (ret == TRUE) ? 1 : 0; } # else @@ -116,9 +186,12 @@ DEFINE_RUN_ONCE_STATIC(ossl_init_base) * to remain loaded until the atexit() handler is run at process exit. */ { - DSO *dso = NULL; + DSO *dso; + void *err; + + if (!err_shelve_state(&err)) + return 0; - ERR_set_mark(); dso = DSO_dsobyaddr(&base_inited, DSO_FLAG_NO_UNLOAD_ON_FREE); # ifdef OPENSSL_INIT_DEBUG fprintf(stderr, "OPENSSL_INIT: obtained DSO reference? %s\n", @@ -130,7 +203,7 @@ DEFINE_RUN_ONCE_STATIC(ossl_init_base) */ # endif DSO_free(dso); - ERR_pop_to_mark(); + err_unshelve_state(err); } # endif #endif @@ -140,12 +213,6 @@ DEFINE_RUN_ONCE_STATIC(ossl_init_base) static CRYPTO_ONCE load_crypto_strings = CRYPTO_ONCE_STATIC_INIT; static int load_crypto_strings_inited = 0; -DEFINE_RUN_ONCE_STATIC(ossl_init_no_load_crypto_strings) -{ - /* Do nothing in this case */ - return 1; -} - DEFINE_RUN_ONCE_STATIC(ossl_init_load_crypto_strings) { int ret = 1; @@ -164,6 +231,13 @@ DEFINE_RUN_ONCE_STATIC(ossl_init_load_crypto_strings) return ret; } +DEFINE_RUN_ONCE_STATIC_ALT(ossl_init_no_load_crypto_strings, + ossl_init_load_crypto_strings) +{ + /* Do nothing in this case */ + return 1; +} + static CRYPTO_ONCE add_all_ciphers = CRYPTO_ONCE_STATIC_INIT; DEFINE_RUN_ONCE_STATIC(ossl_init_add_all_ciphers) { @@ -181,6 +255,13 @@ DEFINE_RUN_ONCE_STATIC(ossl_init_add_all_ciphers) return 1; } +DEFINE_RUN_ONCE_STATIC_ALT(ossl_init_no_add_all_ciphers, + ossl_init_add_all_ciphers) +{ + /* Do nothing */ + return 1; +} + static CRYPTO_ONCE add_all_digests = CRYPTO_ONCE_STATIC_INIT; DEFINE_RUN_ONCE_STATIC(ossl_init_add_all_digests) { @@ -198,7 +279,31 @@ DEFINE_RUN_ONCE_STATIC(ossl_init_add_all_digests) return 1; } -DEFINE_RUN_ONCE_STATIC(ossl_init_no_add_algs) +DEFINE_RUN_ONCE_STATIC_ALT(ossl_init_no_add_all_digests, + ossl_init_add_all_digests) +{ + /* Do nothing */ + return 1; +} + +static CRYPTO_ONCE add_all_macs = CRYPTO_ONCE_STATIC_INIT; +DEFINE_RUN_ONCE_STATIC(ossl_init_add_all_macs) +{ + /* + * OPENSSL_NO_AUTOALGINIT is provided here to prevent at compile time + * pulling in all the macs during static linking + */ +#ifndef OPENSSL_NO_AUTOALGINIT +# ifdef OPENSSL_INIT_DEBUG + fprintf(stderr, "OPENSSL_INIT: ossl_init_add_all_macs: " + "openssl_add_all_macs_int()\n"); +# endif + openssl_add_all_macs_int(); +#endif + return 1; +} + +DEFINE_RUN_ONCE_STATIC_ALT(ossl_init_no_add_all_macs, ossl_init_add_all_macs) { /* Do nothing */ return 1; @@ -218,7 +323,7 @@ DEFINE_RUN_ONCE_STATIC(ossl_init_config) config_inited = 1; return 1; } -DEFINE_RUN_ONCE_STATIC(ossl_init_no_config) +DEFINE_RUN_ONCE_STATIC_ALT(ossl_init_no_config, ossl_init_config) { #ifdef OPENSSL_INIT_DEBUG fprintf(stderr, @@ -349,9 +454,9 @@ static void ossl_init_thread_stop(struct thread_local_inits_st *locals) if (locals->async) { #ifdef OPENSSL_INIT_DEBUG fprintf(stderr, "OPENSSL_INIT: ossl_init_thread_stop: " - "ASYNC_cleanup_thread()\n"); + "async_delete_thread_state()\n"); #endif - ASYNC_cleanup_thread(); + async_delete_thread_state(); } if (locals->err_state) { @@ -375,8 +480,8 @@ static void ossl_init_thread_stop(struct thread_local_inits_st *locals) void OPENSSL_thread_stop(void) { - ossl_init_thread_stop( - (struct thread_local_inits_st *)ossl_init_get_thread_local(0)); + if (destructor_key.sane != -1) + ossl_init_thread_stop(ossl_init_get_thread_local(0)); } int ossl_init_thread_start(uint64_t opts) @@ -421,6 +526,7 @@ int ossl_init_thread_start(uint64_t opts) void OPENSSL_cleanup(void) { OPENSSL_INIT_STOP *currhandler, *lasthandler; + CRYPTO_THREAD_LOCAL key; /* If we've not been inited then no need to deinit */ if (!base_inited) @@ -480,7 +586,9 @@ void OPENSSL_cleanup(void) err_free_strings_int(); } - CRYPTO_THREAD_cleanup_local(&threadstopkey); + key = destructor_key.value; + destructor_key.sane = -1; + CRYPTO_THREAD_cleanup_local(&key); #ifdef OPENSSL_INIT_DEBUG fprintf(stderr, "OPENSSL_INIT: OPENSSL_cleanup: " @@ -540,27 +648,32 @@ void OPENSSL_cleanup(void) */ int OPENSSL_init_crypto(uint64_t opts, const OPENSSL_INIT_SETTINGS *settings) { - static int stoperrset = 0; - if (stopped) { - if (!stoperrset) { - /* - * We only ever set this once to avoid getting into an infinite - * loop where the error system keeps trying to init and fails so - * sets an error etc - */ - stoperrset = 1; + if (!(opts & OPENSSL_INIT_BASE_ONLY)) CRYPTOerr(CRYPTO_F_OPENSSL_INIT_CRYPTO, ERR_R_INIT_FAIL); - } return 0; } - if (!base_inited && !RUN_ONCE(&base, ossl_init_base)) + if (!RUN_ONCE(&base, ossl_init_base)) + return 0; + + if ((opts & OPENSSL_INIT_NO_ATEXIT) != 0) { + if (!RUN_ONCE_ALT(®ister_atexit, ossl_init_no_register_atexit, + ossl_init_register_atexit)) + return 0; + } else if (!RUN_ONCE(®ister_atexit, ossl_init_register_atexit)) { + return 0; + } + + if (!(opts & OPENSSL_INIT_BASE_ONLY) + && !RUN_ONCE(&load_crypto_nodelete, + ossl_init_load_crypto_nodelete)) return 0; if ((opts & OPENSSL_INIT_NO_LOAD_CRYPTO_STRINGS) - && !RUN_ONCE(&load_crypto_strings, - ossl_init_no_load_crypto_strings)) + && !RUN_ONCE_ALT(&load_crypto_strings, + ossl_init_no_load_crypto_strings, + ossl_init_load_crypto_strings)) return 0; if ((opts & OPENSSL_INIT_LOAD_CRYPTO_STRINGS) @@ -568,7 +681,8 @@ int OPENSSL_init_crypto(uint64_t opts, const OPENSSL_INIT_SETTINGS *settings) return 0; if ((opts & OPENSSL_INIT_NO_ADD_ALL_CIPHERS) - && !RUN_ONCE(&add_all_ciphers, ossl_init_no_add_algs)) + && !RUN_ONCE_ALT(&add_all_ciphers, ossl_init_no_add_all_ciphers, + ossl_init_add_all_ciphers)) return 0; if ((opts & OPENSSL_INIT_ADD_ALL_CIPHERS) @@ -576,19 +690,29 @@ int OPENSSL_init_crypto(uint64_t opts, const OPENSSL_INIT_SETTINGS *settings) return 0; if ((opts & OPENSSL_INIT_NO_ADD_ALL_DIGESTS) - && !RUN_ONCE(&add_all_digests, ossl_init_no_add_algs)) + && !RUN_ONCE_ALT(&add_all_digests, ossl_init_no_add_all_digests, + ossl_init_add_all_digests)) return 0; if ((opts & OPENSSL_INIT_ADD_ALL_DIGESTS) && !RUN_ONCE(&add_all_digests, ossl_init_add_all_digests)) return 0; + if ((opts & OPENSSL_INIT_NO_ADD_ALL_MACS) + && !RUN_ONCE_ALT(&add_all_macs, ossl_init_no_add_all_macs, + ossl_init_add_all_macs)) + return 0; + + if ((opts & OPENSSL_INIT_ADD_ALL_MACS) + && !RUN_ONCE(&add_all_macs, ossl_init_add_all_macs)) + return 0; + if ((opts & OPENSSL_INIT_ATFORK) && !openssl_init_fork_handlers()) return 0; if ((opts & OPENSSL_INIT_NO_LOAD_CONFIG) - && !RUN_ONCE(&config, ossl_init_no_config)) + && !RUN_ONCE_ALT(&config, ossl_init_no_config, ossl_init_config)) return 0; if (opts & OPENSSL_INIT_LOAD_CONFIG) { @@ -659,7 +783,9 @@ int OPENSSL_atexit(void (*handler)(void)) { OPENSSL_INIT_STOP *newhand; -#if !defined(OPENSSL_NO_DSO) && !defined(OPENSSL_USE_NODELETE) +#if !defined(OPENSSL_NO_DSO) \ + && !defined(OPENSSL_USE_NODELETE)\ + && !defined(OPENSSL_NO_PINSHARED) { union { void *sym;