X-Git-Url: https://git.openssl.org/gitweb/?p=openssl.git;a=blobdiff_plain;f=crypto%2Finit.c;h=6b6bd71967534d8c67e6124f4ed4091651650fd9;hp=fb7e3ace8790063d2c8542af9736b39f5c70f824;hb=41999e7d358c3657a254b34b85fd9e948180529b;hpb=eb2b9892065cf5b69400b98ca82e4e99a525eb29 diff --git a/crypto/init.c b/crypto/init.c index fb7e3ace87..6b6bd71967 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,26 +88,21 @@ 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) - */ - if (!CRYPTO_THREAD_init_local(&threadstopkey, ossl_init_thread_stop_wrap)) + if (!CRYPTO_THREAD_init_local(&key, ossl_init_thread_destructor)) return 0; if ((init_lock = CRYPTO_THREAD_lock_new()) == NULL) goto err; -#ifndef OPENSSL_SYS_UEFI - if (atexit(OPENSSL_cleanup) != 0) - goto err; -#endif OPENSSL_cpuid_setup(); + destructor_key.value = key; base_inited = 1; return 1; @@ -101,17 +113,43 @@ err: CRYPTO_THREAD_lock_free(init_lock); init_lock = NULL; - CRYPTO_THREAD_cleanup_local(&threadstopkey); + CRYPTO_THREAD_cleanup_local(&key); return 0; } +static CRYPTO_ONCE register_atexit = CRYPTO_ONCE_STATIC_INIT; +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 + if (atexit(OPENSSL_cleanup) != 0) + return 0; +#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) +#if !defined(OPENSSL_NO_DSO) \ + && !defined(OPENSSL_USE_NODELETE) \ + && !defined(OPENSSL_NO_PINSHARED) # ifdef DSO_WIN32 { HMODULE handle = NULL; @@ -161,12 +199,6 @@ DEFINE_RUN_ONCE_STATIC(ossl_init_load_crypto_nodelete) 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; @@ -185,6 +217,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) { @@ -202,6 +241,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) { @@ -219,7 +265,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; @@ -239,7 +309,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, @@ -370,9 +440,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) { @@ -396,8 +466,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) @@ -442,6 +512,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) @@ -501,7 +572,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: " @@ -570,14 +643,23 @@ int OPENSSL_init_crypto(uint64_t opts, const OPENSSL_INIT_SETTINGS *settings) 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) @@ -585,7 +667,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) @@ -593,19 +676,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) { @@ -676,7 +769,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;