diff --git a/NEWS.md b/NEWS.md index e95e94ed2c..f966d8cfda 100644 --- a/NEWS.md +++ b/NEWS.md @@ -29,7 +29,7 @@ OpenSSL 4.0 * The script tool `c_rehash` was removed. Use `openssl rehash` instead. - * OPENSSL_cleanup() no longer invoked as atexit(3) handler by default. + * libcrypto no longer cleans up globally allocated data via atexit() * ENGINE support was removed. The `no-engine` build option and the `OPENSSL_NO_ENGINE` macro is always present. diff --git a/apps/fipsinstall.c b/apps/fipsinstall.c index 10114cb1d8..ea54a00cff 100644 --- a/apps/fipsinstall.c +++ b/apps/fipsinstall.c @@ -967,7 +967,6 @@ cleanup: EVP_MAC_CTX_free(ctx); OPENSSL_free(read_buffer); free_config_and_unload(conf); - OPENSSL_cleanup(); return ret; } diff --git a/crypto/init.c b/crypto/init.c index 2aeffb96e5..dd866d7e08 100644 --- a/crypto/init.c +++ b/crypto/init.c @@ -29,9 +29,14 @@ #include /* for OSSL_CMP_log_close() */ #include #include /* for OPENSSL_INIT_(NO_)?LOAD_SSL_STRINGS */ +#include "crypto/bn.h" #include "crypto/ctype.h" #include "sslerr.h" +#ifdef S390X_MOD_EXP +#include "s390x_arch.h" +#endif + static int stopped = 0; static uint64_t optsdone = 0; @@ -77,58 +82,6 @@ err: return 0; } -static CRYPTO_ONCE load_crypto_nodelete = CRYPTO_ONCE_STATIC_INIT; -DEFINE_RUN_ONCE_STATIC(ossl_init_load_crypto_nodelete) -{ - OSSL_TRACE(INIT, "ossl_init_load_crypto_nodelete()\n"); - -#if !defined(OPENSSL_USE_NODELETE) \ - && !defined(OPENSSL_NO_PINSHARED) -#if defined(DSO_WIN32) && !defined(_WIN32_WCE) - { - HMODULE handle = NULL; - BOOL ret; - - /* We don't use the DSO route for WIN32 because there is a better way */ - ret = GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS - | GET_MODULE_HANDLE_EX_FLAG_PIN, - (void *)&base_inited, &handle); - - OSSL_TRACE1(INIT, - "ossl_init_load_crypto_nodelete: " - "obtained DSO reference? %s\n", - (ret == TRUE ? "No!" : "Yes.")); - return (ret == TRUE) ? 1 : 0; - } -#elif !defined(DSO_NONE) - /* - * Deliberately leak a reference to ourselves. This will force the library - * to remain loaded until the OPENSSL_cleanup() is called. - */ - { - DSO *dso; - void *err; - - if (!err_shelve_state(&err)) - return 0; - - dso = DSO_dsobyaddr(&base_inited, DSO_FLAG_NO_UNLOAD_ON_FREE); - /* - * In case of No!, it is uncertain our exit()-handlers can still be - * called. After dlclose() the whole library might have been unloaded - * already. - */ - OSSL_TRACE1(INIT, "obtained DSO reference? %s\n", - (dso == NULL ? "No!" : "Yes.")); - DSO_free(dso); - err_unshelve_state(err); - } -#endif -#endif - - return 1; -} - static CRYPTO_ONCE load_crypto_strings = CRYPTO_ONCE_STATIC_INIT; DEFINE_RUN_ONCE_STATIC(ossl_init_load_crypto_strings) @@ -270,7 +223,7 @@ void OPENSSL_cleanup(void) if (!base_inited) return; - /* Might be explicitly called a*/ + /* Might be explicitly called */ if (stopped) return; stopped = 1; @@ -357,6 +310,10 @@ void OPENSSL_cleanup(void) OSSL_TRACE(INIT, "OPENSSL_cleanup: ossl_trace_cleanup()\n"); ossl_trace_cleanup(); +#ifdef S390X_MOD_EXP + OPENSSL_s390x_cleanup(); +#endif + base_inited = 0; } @@ -402,10 +359,7 @@ int OPENSSL_init_crypto(uint64_t opts, const OPENSSL_INIT_SETTINGS *settings) * * When the caller specifies OPENSSL_INIT_BASE_ONLY, that should be the * *only* option specified. With that option we return immediately after - * doing the requested limited initialization. Note that - * err_shelve_state() called by us via ossl_init_load_crypto_nodelete() - * re-enters OPENSSL_init_crypto() with OPENSSL_INIT_BASE_ONLY, but with - * base already initialized this is a harmless NOOP. + * doing the requested limited initialization. * * If we remain the only caller of err_shelve_state() the recursion should * perhaps be removed, but if in doubt, it can be left in place. @@ -428,9 +382,6 @@ int OPENSSL_init_crypto(uint64_t opts, const OPENSSL_INIT_SETTINGS *settings) return 1; } - if (!RUN_ONCE(&load_crypto_nodelete, ossl_init_load_crypto_nodelete)) - return 0; - if ((opts & OPENSSL_INIT_NO_LOAD_CRYPTO_STRINGS) && !RUN_ONCE_ALT(&load_crypto_strings, ossl_init_no_load_crypto_strings, diff --git a/crypto/initthread.c b/crypto/initthread.c index d408ea9ca1..1e1b9e69db 100644 --- a/crypto/initthread.c +++ b/crypto/initthread.c @@ -326,12 +326,7 @@ err: void ossl_thread_event_ctx_free(OSSL_LIB_CTX *ctx) { - THREAD_EVENT_HANDLER **hands; - - hands = (THREAD_EVENT_HANDLER **)CRYPTO_THREAD_get_local_ex(CRYPTO_THREAD_LOCAL_TEVENT_KEY, ctx); CRYPTO_THREAD_set_local_ex(CRYPTO_THREAD_LOCAL_TEVENT_KEY, ctx, NULL); - - OPENSSL_free(hands); } static void ossl_arg_thread_stop(void *arg) diff --git a/crypto/s390x_arch.h b/crypto/s390x_arch.h index c3a805b359..f5ff696dcd 100644 --- a/crypto/s390x_arch.h +++ b/crypto/s390x_arch.h @@ -31,6 +31,7 @@ void s390x_kma(const unsigned char *aad, size_t alen, const unsigned char *in, int s390x_pcc(unsigned int fc, void *param); int s390x_kdsa(unsigned int fc, void *param, const unsigned char *in, size_t len); +void OPENSSL_s390x_cleanup(void); void s390x_flip_endian32(unsigned char dst[32], const unsigned char src[32]); void s390x_flip_endian64(unsigned char dst[64], const unsigned char src[64]); diff --git a/crypto/s390xcap.c b/crypto/s390xcap.c index e1e75173af..77b3b0307a 100644 --- a/crypto/s390xcap.c +++ b/crypto/s390xcap.c @@ -221,7 +221,6 @@ void OPENSSL_cpuid_setup(void) OPENSSL_s390xcex = -1; } else { OPENSSL_s390xcex = open("/dev/z90crypt", O_RDWR | O_CLOEXEC); - OPENSSL_atexit(OPENSSL_s390x_cleanup); } OPENSSL_s390xcex_nodev = 0; #endif diff --git a/doc/man3/OPENSSL_init_crypto.pod b/doc/man3/OPENSSL_init_crypto.pod index 0740c219d2..6d9628054d 100644 --- a/doc/man3/OPENSSL_init_crypto.pod +++ b/doc/man3/OPENSSL_init_crypto.pod @@ -124,6 +124,10 @@ sub-library (see L). This is a default option. With this option the library will register its fork handlers. See OPENSSL_fork_prepare(3) for details. +=item OPENSSL_INIT_NO_ATEXIT + +The option has no effect in 4.0 and later. + =back Multiple options may be combined together in a single call to diff --git a/doc/man7/ossl-guide-migration.pod b/doc/man7/ossl-guide-migration.pod index 4ce7b6ec8f..64284c9091 100644 --- a/doc/man7/ossl-guide-migration.pod +++ b/doc/man7/ossl-guide-migration.pod @@ -37,6 +37,11 @@ features available in OpenSSL 4.0. Some functions have been removed that were deprecated in previous versions of OpenSSL. See L. +libcrypto no longer arms OPENSSL_cleanup() function as atexit(3) handler. +Memory leak detectors may report there is allocated, but still reachable, +allocated memory at application exit. If clean report is desired, then +application must call OPENSSL_cleanup() explicitly before main() returns. + =head1 OPENSSL 3.6 =head2 Main Changes from OpenSSL 3.5 diff --git a/include/openssl/crypto.h.in b/include/openssl/crypto.h.in index 9341985026..c9dc3706f3 100644 --- a/include/openssl/crypto.h.in +++ b/include/openssl/crypto.h.in @@ -490,8 +490,8 @@ int CRYPTO_memcmp(const void *in_a, const void *in_b, size_t len); /* FREE: 0x00010000L */ #define OPENSSL_INIT_ATFORK 0x00020000L /* OPENSSL_INIT_BASE_ONLY 0x00040000L */ +#define OPENSSL_INIT_NO_ATEXIT 0x00080000L /* OPENSSL_INIT flag range 0x03f00000 reserved for OPENSSL_init_ssl() */ -/* FREE: 0x00080000L */ /* FREE: 0x04000000L */ /* FREE: 0x08000000L */ /* FREE: 0x10000000L */ diff --git a/providers/implementations/rands/seeding/rand_unix.c b/providers/implementations/rands/seeding/rand_unix.c index 47643d3c67..1af996b25f 100644 --- a/providers/implementations/rands/seeding/rand_unix.c +++ b/providers/implementations/rands/seeding/rand_unix.c @@ -422,11 +422,6 @@ static int keep_random_devices_open = 1; && defined(OPENSSL_RAND_SEED_GETRANDOM) static void *shm_addr; -static void cleanup_shm(void) -{ - shmdt(shm_addr); -} - /* * Ensure that the system randomness source has been adequately seeded. * This is done by having the first start of libcrypto, wait until the device @@ -493,8 +488,8 @@ static int wait_random_seeded(void) * If this call fails, it isn't a big problem. */ shm_addr = shmat(shm_id, NULL, SHM_RDONLY); - if (shm_addr != (void *)-1) - OPENSSL_atexit(&cleanup_shm); + if (shm_addr == (void *)-1) + shm_addr = NULL; } } return seeded; @@ -583,6 +578,14 @@ void ossl_rand_pool_cleanup(void) for (i = 0; i < OSSL_NELEM(random_devices); i++) close_random_device(i); + +#if defined(__linux) && defined(DEVRANDOM_WAIT) \ + && defined(OPENSSL_RAND_SEED_GETRANDOM) + if (shm_addr != NULL) { + shmdt(shm_addr); + shm_addr = NULL; + } +#endif } void ossl_rand_pool_keep_random_devices_open(int keep) diff --git a/ssl/rio/rio_notifier.c b/ssl/rio/rio_notifier.c index ea40790d62..0d84880065 100644 --- a/ssl/rio/rio_notifier.c +++ b/ssl/rio/rio_notifier.c @@ -29,7 +29,9 @@ static int set_cloexec(int fd) #if defined(OPENSSL_SYS_WINDOWS) static CRYPTO_ONCE ensure_wsa_startup_once = CRYPTO_ONCE_STATIC_INIT; +static CRYPTO_RWLOCK *wsa_lock; static int wsa_started; +static int wsa_ref; static void ossl_wsa_cleanup(void) { @@ -37,6 +39,9 @@ static void ossl_wsa_cleanup(void) wsa_started = 0; WSACleanup(); } + + CRYPTO_THREAD_lock_free(wsa_lock); + wsa_lock = NULL; } DEFINE_RUN_ONCE_STATIC(do_wsa_startup) @@ -44,16 +49,43 @@ DEFINE_RUN_ONCE_STATIC(do_wsa_startup) WORD versionreq = 0x0202; /* Version 2.2 */ WSADATA wsadata; - if (WSAStartup(versionreq, &wsadata) != 0) + wsa_lock = CRYPTO_THREAD_lock_new(); + if (wsa_lock == NULL) return 0; + + if (WSAStartup(versionreq, &wsadata) != 0) { + CRYPTO_THREAD_lock_free(wsa_lock); + wsa_lock = NULL; + return 0; + } wsa_started = 1; - OPENSSL_atexit(ossl_wsa_cleanup); + return 1; } static ossl_inline int ensure_wsa_startup(void) { - return RUN_ONCE(&ensure_wsa_startup_once, do_wsa_startup); + int rv, unused; + + rv = RUN_ONCE(&ensure_wsa_startup_once, do_wsa_startup); + if (rv != 0) + CRYPTO_atomic_add(&wsa_ref, 1, &unused, wsa_lock); + + return rv; +} + +static void wsa_done(void) +{ + int ref; + + if (wsa_lock != NULL) { + CRYPTO_atomic_add(&wsa_ref, -1, &ref, wsa_lock); + if (ref == 0) { + ossl_wsa_cleanup(); + ensure_wsa_startup_once = CRYPTO_ONCE_STATIC_INIT; + wsa_lock = NULL; + } + } } #endif @@ -154,6 +186,8 @@ int ossl_rio_notifier_init(RIO_NOTIFIER *nfy) if (!ensure_wsa_startup()) { ERR_raise_data(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR, "Cannot start Windows sockets"); + + wsa_done(); return 0; } #endif @@ -340,6 +374,9 @@ void ossl_rio_notifier_cleanup(RIO_NOTIFIER *nfy) BIO_closesocket(nfy->wfd); BIO_closesocket(nfy->rfd); nfy->rfd = nfy->wfd = -1; +#if defined(OPENSSL_SYS_WINDOWS) + wsa_done(); +#endif } int ossl_rio_notifier_signal(RIO_NOTIFIER *nfy) diff --git a/test/defltfips_test.c b/test/defltfips_test.c index b7e85211c4..16d834b020 100644 --- a/test/defltfips_test.c +++ b/test/defltfips_test.c @@ -8,7 +8,6 @@ */ #include -#include #include #include #include "testutil.h" @@ -69,11 +68,6 @@ static int test_is_fips_enabled(void) return 1; } -void cleanup_tests(void) -{ - OPENSSL_cleanup(); -} - int setup_tests(void) { size_t argc; diff --git a/test/endecode_test.c b/test/endecode_test.c index 58fd12473b..6081ef5d0b 100644 --- a/test/endecode_test.c +++ b/test/endecode_test.c @@ -9,7 +9,6 @@ #include #include -#include #include #include #include @@ -1768,6 +1767,4 @@ void cleanup_tests(void) OSSL_PROVIDER_unload(keyprov); OSSL_LIB_CTX_free(testctx); OSSL_LIB_CTX_free(keyctx); - - OPENSSL_cleanup(); } diff --git a/test/rand_test.c b/test/rand_test.c index 0ac097cb34..0fbd89542f 100644 --- a/test/rand_test.c +++ b/test/rand_test.c @@ -7,7 +7,6 @@ * https://www.openssl.org/source/license.html */ -#include #include #include #include @@ -276,11 +275,6 @@ err: return res; } -void cleanup_tests(void) -{ - OPENSSL_cleanup(); -} - int setup_tests(void) { if (!test_skip_common_options()) { diff --git a/test/testutil/main.c b/test/testutil/main.c index 468d18a825..2d7c88c383 100644 --- a/test/testutil/main.c +++ b/test/testutil/main.c @@ -7,6 +7,7 @@ * https://www.openssl.org/source/license.html */ +#include #include "../testutil.h" #include "output.h" #include "tu_local.h" @@ -39,5 +40,6 @@ int main(int argc, char *argv[]) end: ret = pulldown_test_framework(ret); test_close_streams(); + OPENSSL_cleanup(); return ret; }