Return a fatal error if application data is encountered during shutdown
[openssl.git] / test / shlibloadtest.c
index 8c27bfc111014977f9bf7b53cba8d89eb6b8fe61..aad90e6533e2f532c94d858925a4c290f4b5307a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2016-2018 The OpenSSL Project Authors. All Rights Reserved.
  *
  * Licensed under the OpenSSL license (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
 #include <openssl/opensslv.h>
 #include <openssl/ssl.h>
 #include <openssl/ossl_typ.h>
+#include "internal/dso_conf.h"
 #include "testutil.h"
 
+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 unsigned long (*ERR_get_error_t)(void);
 typedef unsigned long (*OpenSSL_version_num_t)(void);
+typedef DSO * (*DSO_dsobyaddr_t)(void (*addr)(void), int flags);
+typedef int (*DSO_free_t)(DSO *dso);
 
 typedef enum test_types_en {
     CRYPTO_FIRST,
     SSL_FIRST,
-    JUST_CRYPTO
+    JUST_CRYPTO,
+    DSO_REFTEST
 } TEST_TYPE;
 
 static TEST_TYPE test_type;
@@ -52,12 +58,10 @@ static int shlib_sym(SHLIB lib, const char *symname, SHLIB_SYM *sym)
     return *sym != NULL;
 }
 
-# ifdef OPENSSL_USE_NODELETE
 static int shlib_close(SHLIB lib)
 {
     return dlclose(lib) != 0 ? 0 : 1;
 }
-# endif
 #endif
 
 #ifdef DSO_WIN32
@@ -81,12 +85,10 @@ static int shlib_sym(SHLIB lib, const char *symname, SHLIB_SYM *sym)
     return *sym != NULL;
 }
 
-# ifdef OPENSSL_USE_NODELETE
 static int shlib_close(SHLIB lib)
 {
     return FreeLibrary(lib) == 0 ? 0 : 1;
 }
-# endif
 #endif
 
 
@@ -117,14 +119,19 @@ static int test_lib(void)
         if (!TEST_true(shlib_load(path_crypto, &cryptolib))
                 || !TEST_true(shlib_load(path_ssl, &ssllib)))
             goto end;
+        break;
     case SSL_FIRST:
         if (!TEST_true(shlib_load(path_ssl, &ssllib))
                 || !TEST_true(shlib_load(path_crypto, &cryptolib)))
             goto end;
         break;
+    case DSO_REFTEST:
+        if (!TEST_true(shlib_load(path_crypto, &cryptolib)))
+            goto end;
+        break;
     }
 
-    if (test_type != JUST_CRYPTO) {
+    if (test_type != JUST_CRYPTO && test_type != DSO_REFTEST) {
         if (!TEST_true(shlib_sym(ssllib, "TLS_method", &symbols[0].sym))
                 || !TEST_true(shlib_sym(ssllib, "SSL_CTX_new", &symbols[1].sym))
                 || !TEST_true(shlib_sym(ssllib, "SSL_CTX_free", &symbols[2].sym)))
@@ -144,11 +151,53 @@ static int test_lib(void)
     myERR_get_error = (ERR_get_error_t)symbols[0].func;
     if (!TEST_int_eq(myERR_get_error(), 0))
         goto end;
+
+    /*
+     * The bits that COMPATIBILITY_MASK lets through MUST be the same in
+     * the library and in the application.
+     * The bits that are masked away MUST be a larger or equal number in
+     * the library compared to the application.
+     */
+# define COMPATIBILITY_MASK 0xfff00000L
     myOpenSSL_version_num = (OpenSSL_version_num_t)symbols[1].func;
-    if (!TEST_int_eq(myOpenSSL_version_num(), OPENSSL_VERSION_NUMBER))
+    if (!TEST_int_eq(myOpenSSL_version_num() & COMPATIBILITY_MASK,
+                     OPENSSL_VERSION_NUMBER & COMPATIBILITY_MASK))
+        goto end;
+    if (!TEST_int_ge(myOpenSSL_version_num() & ~COMPATIBILITY_MASK,
+                     OPENSSL_VERSION_NUMBER & ~COMPATIBILITY_MASK))
         goto end;
 
-#ifdef OPENSSL_USE_NODELETE
+    if (test_type == DSO_REFTEST) {
+# ifdef DSO_DLFCN
+        DSO_dsobyaddr_t myDSO_dsobyaddr;
+        DSO_free_t myDSO_free;
+
+        /*
+         * This is resembling the code used in ossl_init_base() and
+         * OPENSSL_atexit() to block unloading the library after dlclose().
+         * We are not testing this on Windows, because it is done there in a
+         * completely different way. Especially as a call to DSO_dsobyaddr()
+         * will always return an error, because DSO_pathbyaddr() is not
+         * implemented there.
+         */
+        if (!TEST_true(shlib_sym(cryptolib, "DSO_dsobyaddr", &symbols[0].sym))
+                || !TEST_true(shlib_sym(cryptolib, "DSO_free",
+                                        &symbols[1].sym)))
+            goto end;
+
+        myDSO_dsobyaddr = (DSO_dsobyaddr_t)symbols[0].func;
+        myDSO_free = (DSO_free_t)symbols[1].func;
+
+        {
+            DSO *hndl;
+            /* use known symbol from crypto module */
+            if (!TEST_ptr(hndl = myDSO_dsobyaddr((void (*)(void))ERR_get_error, 0)))
+                goto end;
+            myDSO_free(hndl);
+        }
+# endif /* DSO_DLFCN */
+    }
+
     switch (test_type) {
     case JUST_CRYPTO:
         if (!TEST_true(shlib_close(cryptolib)))
@@ -158,13 +207,17 @@ static int test_lib(void)
         if (!TEST_true(shlib_close(cryptolib))
                 || !TEST_true(shlib_close(ssllib)))
             goto end;
+        break;
     case SSL_FIRST:
         if (!TEST_true(shlib_close(ssllib))
                 || !TEST_true(shlib_close(cryptolib)))
             goto end;
         break;
+    case DSO_REFTEST:
+        if (!TEST_true(shlib_close(cryptolib)))
+            goto end;
+        break;
     }
-#endif
 
     result = 1;
 end:
@@ -173,28 +226,28 @@ end:
 #endif
 
 
-int test_main(int argc, char **argv)
+int setup_tests(void)
 {
-    if (argc != 4) {
-        TEST_error("Unexpected number of arguments");
-        return EXIT_FAILURE;
-    }
+    const char *p = test_get_argument(0);
 
-    if (strcmp(argv[1], "-crypto_first") == 0) {
+    if (strcmp(p, "-crypto_first") == 0) {
         test_type = CRYPTO_FIRST;
-    } else if (strcmp(argv[1], "-ssl_first") == 0) {
+    } else if (strcmp(p, "-ssl_first") == 0) {
         test_type = SSL_FIRST;
-    } else if (strcmp(argv[1], "-just_crypto") == 0) {
+    } else if (strcmp(p, "-just_crypto") == 0) {
+        test_type = JUST_CRYPTO;
+    } else if (strcmp(p, "-dso_ref") == 0) {
         test_type = JUST_CRYPTO;
     } else {
         TEST_error("Unrecognised argument");
-        return EXIT_FAILURE;
+        return 0;
     }
-    path_crypto = argv[2];
-    path_ssl = argv[3];
+    if (!TEST_ptr(path_crypto = test_get_argument(1))
+            || !TEST_ptr(path_ssl = test_get_argument(2)))
+        return 0;
 
 #if defined(DSO_DLFCN) || defined(DSO_WIN32)
     ADD_TEST(test_lib);
 #endif
-    return run_tests(argv[0]);
+    return 1;
 }