From 88d57bf83fe32b2c8ceb1264562fdd028de504bf Mon Sep 17 00:00:00 2001 From: Matt Caswell Date: Thu, 15 Nov 2018 17:41:06 +0000 Subject: [PATCH] Test atexit handlers Test that atexit handlers get called properly at process exit, unless we have explicitly asked for them not to be. Reviewed-by: Tim Hudson (Merged from https://github.com/openssl/openssl/pull/7647) --- test/recipes/90-test_shlibload.t | 45 ++++++++++++++++++++----- test/shlibloadtest.c | 58 ++++++++++++++++++++++++++++---- 2 files changed, 87 insertions(+), 16 deletions(-) diff --git a/test/recipes/90-test_shlibload.t b/test/recipes/90-test_shlibload.t index bb7fab079c..ea8aeeb7d5 100644 --- a/test/recipes/90-test_shlibload.t +++ b/test/recipes/90-test_shlibload.t @@ -8,6 +8,7 @@ use OpenSSL::Test qw/:DEFAULT bldtop_dir bldtop_file/; use OpenSSL::Test::Utils; +use File::Temp qw(tempfile); #Load configdata.pm @@ -20,7 +21,7 @@ use configdata; plan skip_all => "Test only supported in a shared build" if disabled("shared"); plan skip_all => "Test is disabled on AIX" if config('target') =~ m|^aix|; -plan tests => 4; +plan tests => 10; # When libssl and libcrypto are compiled on Linux with "-rpath", but not # "--enable-new-dtags", the RPATH takes precedence over LD_LIBRARY_PATH, @@ -30,14 +31,31 @@ plan tests => 4; my $libcrypto = bldtop_file(shlib('libcrypto')); my $libssl = bldtop_file(shlib('libssl')); -ok(run(test(["shlibloadtest", "-crypto_first", $libcrypto, $libssl])), - "running shlibloadtest -crypto_first"); -ok(run(test(["shlibloadtest", "-ssl_first", $libcrypto, $libssl])), - "running shlibloadtest -ssl_first"); -ok(run(test(["shlibloadtest", "-just_crypto", $libcrypto, $libssl])), - "running shlibloadtest -just_crypto"); -ok(run(test(["shlibloadtest", "-dso_ref", $libcrypto, $libssl])), - "running shlibloadtest -dso_ref"); +(my $fh, my $filename) = tempfile(); +ok(run(test(["shlibloadtest", "-crypto_first", $libcrypto, $libssl, $filename])), + "running shlibloadtest -crypto_first $filename"); +ok(check_atexit($fh)); +unlink $filename; +($fh, $filename) = tempfile(); +ok(run(test(["shlibloadtest", "-ssl_first", $libcrypto, $libssl, $filename])), + "running shlibloadtest -ssl_first $filename"); +ok(check_atexit($fh)); +unlink $filename; +($fh, $filename) = tempfile(); +ok(run(test(["shlibloadtest", "-just_crypto", $libcrypto, $libssl, $filename])), + "running shlibloadtest -just_crypto $filename"); +ok(check_atexit($fh)); +unlink $filename; +($fh, $filename) = tempfile(); +ok(run(test(["shlibloadtest", "-dso_ref", $libcrypto, $libssl, $filename])), + "running shlibloadtest -dso_ref $filename"); +ok(check_atexit($fh)); +unlink $filename; +($fh, $filename) = tempfile(); +ok(run(test(["shlibloadtest", "-no_atexit", $libcrypto, $libssl, $filename])), + "running shlibloadtest -no_atexit $filename"); +ok(!check_atexit($fh)); +unlink $filename; sub shlib { my $lib = shift; @@ -49,3 +67,12 @@ sub shlib { $lib =~ s|\.\$\(SHLIB_VERSION_NUMBER\)|.$config{shlib_version}|; return $lib; } + +sub check_atexit { + my $fh = shift; + my $data = <$fh>; + + return 1 if (defined $data && $data =~ m/atexit\(\) run/); + + return 0; +} diff --git a/test/shlibloadtest.c b/test/shlibloadtest.c index 9655456740..b1a817258f 100644 --- a/test/shlibloadtest.c +++ b/test/shlibloadtest.c @@ -20,6 +20,8 @@ typedef void DSO; typedef const SSL_METHOD * (*TLS_method_t)(void); typedef SSL_CTX * (*SSL_CTX_new_t)(const SSL_METHOD *meth); typedef void (*SSL_CTX_free_t)(SSL_CTX *); +typedef int (*OPENSSL_init_crypto_t)(uint64_t, void *); +typedef int (*OPENSSL_atexit_t)(void (*handler)(void)); typedef unsigned long (*ERR_get_error_t)(void); typedef unsigned long (*OPENSSL_version_major_t)(void); typedef unsigned long (*OPENSSL_version_minor_t)(void); @@ -31,12 +33,14 @@ typedef enum test_types_en { CRYPTO_FIRST, SSL_FIRST, JUST_CRYPTO, - DSO_REFTEST + DSO_REFTEST, + NO_ATEXIT } TEST_TYPE; static TEST_TYPE test_type; static const char *path_crypto; static const char *path_ssl; +static const char *path_atexit; #ifdef DSO_DLFCN @@ -100,6 +104,17 @@ static int shlib_close(SHLIB lib) #if defined(DSO_DLFCN) || defined(DSO_WIN32) +static void atexit_handler(void) +{ + FILE *atexit_file = fopen(path_atexit, "w"); + + if (atexit_file == NULL) + return; + + fprintf(atexit_file, "atexit() run\n"); + fclose(atexit_file); +} + static int test_lib(void) { SHLIB ssllib = SHLIB_INIT; @@ -108,7 +123,7 @@ static int test_lib(void) union { void (*func)(void); SHLIB_SYM sym; - } symbols[4]; + } symbols[5]; TLS_method_t myTLS_method; SSL_CTX_new_t mySSL_CTX_new; SSL_CTX_free_t mySSL_CTX_free; @@ -116,11 +131,13 @@ static int test_lib(void) OPENSSL_version_major_t myOPENSSL_version_major; OPENSSL_version_minor_t myOPENSSL_version_minor; OPENSSL_version_patch_t myOPENSSL_version_patch; + OPENSSL_atexit_t myOPENSSL_atexit; int result = 0; switch (test_type) { case JUST_CRYPTO: case DSO_REFTEST: + case NO_ATEXIT: case CRYPTO_FIRST: if (!shlib_load(path_crypto, &cryptolib)) { fprintf(stderr, "Failed to load libcrypto\n"); @@ -144,7 +161,23 @@ static int test_lib(void) break; } - if (test_type != JUST_CRYPTO && test_type != DSO_REFTEST) { + if (test_type == NO_ATEXIT) { + OPENSSL_init_crypto_t myOPENSSL_init_crypto; + + if (!shlib_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) { if (!shlib_sym(ssllib, "TLS_method", &symbols[0].sym) || !shlib_sym(ssllib, "SSL_CTX_new", &symbols[1].sym) || !shlib_sym(ssllib, "SSL_CTX_free", &symbols[2].sym)) { @@ -165,7 +198,8 @@ static int test_lib(void) if (!shlib_sym(cryptolib, "ERR_get_error", &symbols[0].sym) || !shlib_sym(cryptolib, "OPENSSL_version_major", &symbols[1].sym) || !shlib_sym(cryptolib, "OPENSSL_version_minor", &symbols[2].sym) - || !shlib_sym(cryptolib, "OPENSSL_version_patch", &symbols[3].sym)) { + || !shlib_sym(cryptolib, "OPENSSL_version_patch", &symbols[3].sym) + || !shlib_sym(cryptolib, "OPENSSL_atexit", &symbols[4].sym)) { fprintf(stderr, "Failed to load libcrypto symbols\n"); goto end; } @@ -186,6 +220,12 @@ static int test_lib(void) goto end; } + myOPENSSL_atexit = (OPENSSL_atexit_t)symbols[4].func; + if (!myOPENSSL_atexit(atexit_handler)) { + fprintf(stderr, "Failed to register atexit handler\n"); + goto end; + } + if (test_type == DSO_REFTEST) { # ifdef DSO_DLFCN DSO_dsobyaddr_t myDSO_dsobyaddr; @@ -224,6 +264,7 @@ static int test_lib(void) switch (test_type) { case JUST_CRYPTO: case DSO_REFTEST: + case NO_ATEXIT: case CRYPTO_FIRST: if (!shlib_close(cryptolib)) { fprintf(stderr, "Failed to close libcrypto\n"); @@ -264,8 +305,8 @@ int main(int argc, char *argv[]) { const char *p; - if (argc != 4) { - fprintf(stderr, "Incorrect number of arguments"); + if (argc != 5) { + fprintf(stderr, "Incorrect number of arguments\n"); return 1; } @@ -279,12 +320,15 @@ 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"); + fprintf(stderr, "Unrecognised argument\n"); return 1; } path_crypto = argv[2]; path_ssl = argv[3]; + path_atexit = argv[4]; if (path_crypto == NULL || path_ssl == NULL) { fprintf(stderr, "Invalid libcrypto/libssl path\n"); return 1; -- 2.25.1