mirror of
https://github.com/openssl/openssl.git
synced 2026-05-07 20:12:39 +00:00
Introduce OPENSSL_ATEXIT_CLEANUP env. variable.
libcrypto does not arm OPENSSL_cleanup() function as atexit(3) handler by default. If application/user wants libcrypto to install OPENSSL_cleanup() as atexit handler, then OPENSSL_ATEXIT_CLEANUP env. variable must be set. If platform's libc does not provide atexit(3), then OPENSSL_ATEXIT_CLEANUP has no effect. The OPENSSL_atexit() is wrapper of atexit(3) provided by libc now. Reviewed-by: Neil Horman <nhorman@openssl.org> Reviewed-by: Matt Caswell <matt@openssl.org> (Merged from https://github.com/openssl/openssl/pull/29385)
This commit is contained in:
committed by
Neil Horman
parent
380ff14485
commit
31659fe326
@@ -36,11 +36,19 @@ OpenSSL 4.0
|
||||
|
||||
*Norbert Pocs*
|
||||
|
||||
* libcrypto no longer arms OPENSSL_cleanup() as atexit(3) handler by default.
|
||||
Memory leak detectors now report there is allocated and reachable memory
|
||||
at application exit. To avoid such leak detection the application must
|
||||
call OPENSSL_cleanup() before main() exits.
|
||||
|
||||
*Alexandr Nedvedicky*
|
||||
|
||||
* The crypto-mdebug-backtrace configuration option has been entirely removed.
|
||||
The option has been a no-op since 1.0.2.
|
||||
|
||||
*Neil Horman*
|
||||
|
||||
|
||||
* Removed extra leading '00:' when printing key data such as an RSA modulus
|
||||
in hexadecimal format where the first (most significant) byte is >= 0x80.
|
||||
This had been added artificially to resemble ASN.1 DER encoding internals.
|
||||
|
||||
@@ -967,6 +967,7 @@ cleanup:
|
||||
EVP_MAC_CTX_free(ctx);
|
||||
OPENSSL_free(read_buffer);
|
||||
free_config_and_unload(conf);
|
||||
OPENSSL_cleanup();
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -372,6 +372,7 @@ end:
|
||||
#ifndef OPENSSL_NO_SECURE_MEMORY
|
||||
CRYPTO_secure_malloc_done();
|
||||
#endif
|
||||
OPENSSL_cleanup();
|
||||
EXIT(ret);
|
||||
}
|
||||
|
||||
|
||||
+6
-132
@@ -35,13 +35,6 @@
|
||||
static int stopped = 0;
|
||||
static uint64_t optsdone = 0;
|
||||
|
||||
typedef struct ossl_init_stop_st OPENSSL_INIT_STOP;
|
||||
struct ossl_init_stop_st {
|
||||
void (*handler)(void);
|
||||
OPENSSL_INIT_STOP *next;
|
||||
};
|
||||
|
||||
static OPENSSL_INIT_STOP *stop_handlers = NULL;
|
||||
/* Guards access to the optsdone variable on platforms without atomics */
|
||||
static CRYPTO_RWLOCK *optsdone_lock = NULL;
|
||||
/* Guards simultaneous INIT_LOAD_CONFIG calls with non-NULL settings */
|
||||
@@ -84,45 +77,6 @@ err:
|
||||
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
|
||||
|
||||
DEFINE_RUN_ONCE_STATIC(ossl_init_register_atexit)
|
||||
{
|
||||
#ifndef OPENSSL_NO_ATEXIT
|
||||
#ifdef OPENSSL_INIT_DEBUG
|
||||
fprintf(stderr, "OPENSSL_INIT: ossl_init_register_atexit()\n");
|
||||
#endif
|
||||
#ifndef OPENSSL_SYS_UEFI
|
||||
#if defined(_WIN32) && !defined(__BORLANDC__)
|
||||
/* 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
|
||||
#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)
|
||||
@@ -150,7 +104,7 @@ DEFINE_RUN_ONCE_STATIC(ossl_init_load_crypto_nodelete)
|
||||
#elif !defined(DSO_NONE)
|
||||
/*
|
||||
* Deliberately leak a reference to ourselves. This will force the library
|
||||
* to remain loaded until the atexit() handler is run at process exit.
|
||||
* to remain loaded until the OPENSSL_cleanup() is called.
|
||||
*/
|
||||
{
|
||||
DSO *dso;
|
||||
@@ -308,8 +262,6 @@ DEFINE_RUN_ONCE_STATIC(ossl_init_async)
|
||||
|
||||
void OPENSSL_cleanup(void)
|
||||
{
|
||||
OPENSSL_INIT_STOP *currhandler, *lasthandler;
|
||||
|
||||
/*
|
||||
* At some point we should consider looking at this function with a view to
|
||||
* moving most/all of this into onfree handlers in OSSL_LIB_CTX.
|
||||
@@ -319,7 +271,7 @@ void OPENSSL_cleanup(void)
|
||||
if (!base_inited)
|
||||
return;
|
||||
|
||||
/* Might be explicitly called and also by atexit */
|
||||
/* Might be explicitly called a*/
|
||||
if (stopped)
|
||||
return;
|
||||
stopped = 1;
|
||||
@@ -330,15 +282,6 @@ void OPENSSL_cleanup(void)
|
||||
*/
|
||||
OPENSSL_thread_stop();
|
||||
|
||||
currhandler = stop_handlers;
|
||||
while (currhandler != NULL) {
|
||||
currhandler->handler();
|
||||
lasthandler = currhandler;
|
||||
currhandler = currhandler->next;
|
||||
OPENSSL_free(lasthandler);
|
||||
}
|
||||
stop_handlers = NULL;
|
||||
|
||||
CRYPTO_THREAD_lock_free(optsdone_lock);
|
||||
optsdone_lock = NULL;
|
||||
CRYPTO_THREAD_lock_free(init_lock);
|
||||
@@ -486,20 +429,6 @@ int OPENSSL_init_crypto(uint64_t opts, const OPENSSL_INIT_SETTINGS *settings)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Now we don't always set up exit handlers, the INIT_BASE_ONLY calls
|
||||
* should not have the side-effect of setting up exit handlers, and
|
||||
* therefore, this code block is below the INIT_BASE_ONLY-conditioned early
|
||||
* return above.
|
||||
*/
|
||||
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 (!RUN_ONCE(&load_crypto_nodelete, ossl_init_load_crypto_nodelete))
|
||||
return 0;
|
||||
|
||||
@@ -586,64 +515,9 @@ int OPENSSL_init_crypto(uint64_t opts, const OPENSSL_INIT_SETTINGS *settings)
|
||||
|
||||
int OPENSSL_atexit(void (*handler)(void))
|
||||
{
|
||||
OPENSSL_INIT_STOP *newhand;
|
||||
|
||||
#if !defined(OPENSSL_USE_NODELETE) \
|
||||
&& !defined(OPENSSL_NO_PINSHARED)
|
||||
{
|
||||
#if defined(DSO_WIN32) && !defined(_WIN32_WCE)
|
||||
HMODULE handle = NULL;
|
||||
BOOL ret;
|
||||
union {
|
||||
void *sym;
|
||||
void (*func)(void);
|
||||
} handlersym;
|
||||
|
||||
handlersym.func = handler;
|
||||
|
||||
/*
|
||||
* 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,
|
||||
handlersym.sym, &handle);
|
||||
|
||||
if (!ret)
|
||||
return 0;
|
||||
#elif !defined(DSO_NONE)
|
||||
/*
|
||||
* Deliberately leak a reference to the handler. This will force the
|
||||
* library/code containing the handler to remain loaded until we run the
|
||||
* atexit handler. If -znodelete has been used then this is
|
||||
* unnecessary.
|
||||
*/
|
||||
DSO *dso = NULL;
|
||||
union {
|
||||
void *sym;
|
||||
void (*func)(void);
|
||||
} handlersym;
|
||||
|
||||
handlersym.func = handler;
|
||||
|
||||
ERR_set_mark();
|
||||
dso = DSO_dsobyaddr(handlersym.sym, DSO_FLAG_NO_UNLOAD_ON_FREE);
|
||||
/* See same code above in ossl_init_base() for an explanation. */
|
||||
OSSL_TRACE1(INIT,
|
||||
"atexit: obtained DSO reference? %s\n",
|
||||
(dso == NULL ? "No!" : "Yes."));
|
||||
DSO_free(dso);
|
||||
ERR_pop_to_mark();
|
||||
#if defined(__TANDEM)
|
||||
return 0;
|
||||
#else
|
||||
return atexit(handler) == 0;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
if ((newhand = OPENSSL_malloc(sizeof(*newhand))) == NULL)
|
||||
return 0;
|
||||
|
||||
newhand->handler = handler;
|
||||
newhand->next = stop_handlers;
|
||||
stop_handlers = newhand;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -326,7 +326,12 @@ 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)
|
||||
|
||||
@@ -124,13 +124,6 @@ sub-library (see L<ASYNC_start_job(3)>). 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
|
||||
|
||||
By default OpenSSL will attempt to clean itself up when the process exits via an
|
||||
"atexit" handler. Using this option suppresses that behaviour. This means that
|
||||
the application will have to clean up OpenSSL explicitly using
|
||||
OPENSSL_cleanup().
|
||||
|
||||
=back
|
||||
|
||||
Multiple options may be combined together in a single call to
|
||||
@@ -158,11 +151,7 @@ OpenSSL error strings will not be available, only an error code. This code can
|
||||
be put through the openssl errstr command line application to produce a human
|
||||
readable error (see L<openssl-errstr(1)>).
|
||||
|
||||
The OPENSSL_atexit() function enables the registration of a
|
||||
function to be called during OPENSSL_cleanup(). Stop handlers are
|
||||
called after deinitialisation of resources local to a thread, but before other
|
||||
process wide resources are freed. In the event that multiple stop handlers are
|
||||
registered, no guarantees are made about the order of execution.
|
||||
The OPENSSL_atexit() is a wrapper on atexit(3) provided by platform's libc.
|
||||
|
||||
The OPENSSL_thread_stop_ex() function deallocates resources associated
|
||||
with the current thread for the given OSSL_LIB_CTX B<ctx>. The B<ctx> parameter
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <openssl/crypto.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/provider.h>
|
||||
#include "testutil.h"
|
||||
@@ -68,6 +69,11 @@ static int test_is_fips_enabled(void)
|
||||
return 1;
|
||||
}
|
||||
|
||||
void cleanup_tests(void)
|
||||
{
|
||||
OPENSSL_cleanup();
|
||||
}
|
||||
|
||||
int setup_tests(void)
|
||||
{
|
||||
size_t argc;
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
#include <string.h>
|
||||
#include <openssl/core_dispatch.h>
|
||||
#include <openssl/crypto.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/rsa.h>
|
||||
@@ -1767,4 +1768,6 @@ void cleanup_tests(void)
|
||||
OSSL_PROVIDER_unload(keyprov);
|
||||
OSSL_LIB_CTX_free(testctx);
|
||||
OSSL_LIB_CTX_free(keyctx);
|
||||
|
||||
OPENSSL_cleanup();
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <openssl/crypto.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/rand.h>
|
||||
#include <openssl/bio.h>
|
||||
@@ -275,6 +276,11 @@ err:
|
||||
return res;
|
||||
}
|
||||
|
||||
void cleanup_tests(void)
|
||||
{
|
||||
OPENSSL_cleanup();
|
||||
}
|
||||
|
||||
int setup_tests(void)
|
||||
{
|
||||
if (!test_skip_common_options()) {
|
||||
|
||||
@@ -25,7 +25,7 @@ plan skip_all => "Test only supported in a dso build" if disabled("dso");
|
||||
plan skip_all => "Test is disabled in an address sanitizer build" unless disabled("asan");
|
||||
plan skip_all => "Test is disabled in no-atexit build" if disabled("atexit");
|
||||
|
||||
plan tests => 10;
|
||||
plan tests => 8;
|
||||
|
||||
my $libcrypto = platform->sharedlib('libcrypto');
|
||||
my $libssl = platform->sharedlib('libssl');
|
||||
@@ -55,12 +55,6 @@ ok(run(test(["shlibloadtest", "-dso_ref", $libcrypto, $libssl, $atexit_outfile])
|
||||
"running shlibloadtest -dso_ref $atexit_outfile");
|
||||
ok(check_atexit($atexit_outfile));
|
||||
|
||||
$atexit_outfile = 'atexit-noatexit.txt';
|
||||
1 while unlink $atexit_outfile;
|
||||
ok(run(test(["shlibloadtest", "-no_atexit", $libcrypto, $libssl, $atexit_outfile])),
|
||||
"running shlibloadtest -no_atexit $atexit_outfile");
|
||||
ok(!check_atexit($atexit_outfile));
|
||||
|
||||
sub check_atexit {
|
||||
my $filename = shift;
|
||||
|
||||
|
||||
+2
-21
@@ -34,7 +34,6 @@ typedef enum test_types_en {
|
||||
SSL_FIRST,
|
||||
JUST_CRYPTO,
|
||||
DSO_REFTEST,
|
||||
NO_ATEXIT
|
||||
} TEST_TYPE;
|
||||
|
||||
static TEST_TYPE test_type;
|
||||
@@ -80,7 +79,6 @@ static int test_lib(void)
|
||||
switch (test_type) {
|
||||
case JUST_CRYPTO:
|
||||
case DSO_REFTEST:
|
||||
case NO_ATEXIT:
|
||||
case CRYPTO_FIRST:
|
||||
if (!sd_load(path_crypto, &cryptolib, SD_SHLIB)) {
|
||||
fprintf(stderr, "Failed to load libcrypto\n");
|
||||
@@ -104,23 +102,8 @@ static int test_lib(void)
|
||||
break;
|
||||
}
|
||||
|
||||
if (test_type == NO_ATEXIT) {
|
||||
OPENSSL_init_crypto_t myOPENSSL_init_crypto;
|
||||
|
||||
if (!sd_sym(cryptolib, "OPENSSL_init_crypto", &symbols[0].sym)) {
|
||||
fprintf(stderr, "Failed to load OPENSSL_init_crypto symbol\n");
|
||||
goto end;
|
||||
}
|
||||
myOPENSSL_init_crypto = (OPENSSL_init_crypto_t)symbols[0].func;
|
||||
if (!myOPENSSL_init_crypto(OPENSSL_INIT_NO_ATEXIT, NULL)) {
|
||||
fprintf(stderr, "Failed to initialise libcrypto\n");
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
if (test_type != JUST_CRYPTO
|
||||
&& test_type != DSO_REFTEST
|
||||
&& test_type != NO_ATEXIT) {
|
||||
&& test_type != DSO_REFTEST) {
|
||||
if (!sd_sym(ssllib, "TLS_method", &symbols[0].sym)
|
||||
|| !sd_sym(ssllib, "SSL_CTX_new", &symbols[1].sym)
|
||||
|| !sd_sym(ssllib, "SSL_CTX_free", &symbols[2].sym)) {
|
||||
@@ -228,7 +211,7 @@ static int test_lib(void)
|
||||
* running atexit() on so unload. If not we might crash. We know this is
|
||||
* true on linux since glibc 2.2.3
|
||||
*/
|
||||
if (test_type != NO_ATEXIT && atexit_handler_done != 1) {
|
||||
if (atexit_handler_done != 1) {
|
||||
fprintf(stderr, "atexit() handler did not run\n");
|
||||
goto end;
|
||||
}
|
||||
@@ -269,8 +252,6 @@ int main(int argc, char *argv[])
|
||||
test_type = JUST_CRYPTO;
|
||||
} else if (strcmp(p, "-dso_ref") == 0) {
|
||||
test_type = DSO_REFTEST;
|
||||
} else if (strcmp(p, "-no_atexit") == 0) {
|
||||
test_type = NO_ATEXIT;
|
||||
} else {
|
||||
fprintf(stderr, "Unrecognised argument\n");
|
||||
return 1;
|
||||
|
||||
Reference in New Issue
Block a user