Custome built dladdr() for AIX.
[openssl.git] / test / shlibloadtest.c
index 20030d9..919bf7c 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
@@ -12,6 +12,9 @@
 #include <stdlib.h>
 #include <openssl/opensslv.h>
 
+/* The test is only currently implemented for DSO_DLFCN and DSO_WIN32 */
+#if defined(DSO_DLFCN) || defined(DSO_WIN32)
+
 #define SSL_CTX_NEW "SSL_CTX_new"
 #define SSL_CTX_FREE "SSL_CTX_free"
 #define TLS_METHOD "TLS_method"
@@ -35,31 +38,27 @@ static SSL_CTX_free_t SSL_CTX_free;
 static ERR_get_error_t ERR_get_error;
 static OpenSSL_version_num_t OpenSSL_version_num;
 
-
 #ifdef DSO_DLFCN
 
+# define DSO_DSOBYADDR "DSO_dsobyaddr"
+# define DSO_FREE "DSO_free"
+
+typedef void DSO;
+typedef DSO * (*DSO_dsobyaddr_t)(void (*addr)(), int flags);
+typedef int (*DSO_free_t)(DSO *dso);
+
+static DSO_dsobyaddr_t DSO_dsobyaddr;
+static DSO_free_t DSO_free;
+
 # include <dlfcn.h>
 
 typedef void * SHLIB;
 typedef void * SHLIB_SYM;
 # define SHLIB_INIT NULL
 
-# define SHARED_LIBRARY_SUFFIX ".so"
-
-static int shlib_load(char *filename, SHLIB *lib)
+static int shlib_load(const char *filename, SHLIB *lib)
 {
-    char *tmpfile;
-    size_t filenamelen = strlen(filename);
-
-    /* Total length = base filename len + suffix len + 1 for NULL terminator */
-    tmpfile = malloc(filenamelen + sizeof(SHARED_LIBRARY_SUFFIX) + 1);
-    if (tmpfile == NULL)
-        return 0;
-    strcpy(tmpfile, filename);
-    strcpy(tmpfile + filenamelen, SHARED_LIBRARY_SUFFIX);
-
-    *lib = dlopen(tmpfile, RTLD_GLOBAL | RTLD_LAZY);
-    free(tmpfile);
+    *lib = dlopen(filename, RTLD_GLOBAL | RTLD_LAZY);
 
     if (*lib == NULL)
         return 0;
@@ -90,7 +89,7 @@ typedef HINSTANCE SHLIB;
 typedef void * SHLIB_SYM;
 # define SHLIB_INIT 0
 
-static int shlib_load(char *filename, SHLIB *lib)
+static int shlib_load(const char *filename, SHLIB *lib)
 {
     *lib = LoadLibraryA(filename);
     if (*lib == NULL)
@@ -116,17 +115,16 @@ static int shlib_close(SHLIB lib)
 
 #endif
 
-/* The test is only currently implemented for DSO_DLFCN and DSO_WIN32 */
-#if defined(DSO_DLFCN) || defined(DSO_WIN32)
-
 # define CRYPTO_FIRST_OPT    "-crypto_first"
 # define SSL_FIRST_OPT       "-ssl_first"
 # define JUST_CRYPTO_OPT     "-just_crypto"
+# define DSO_REFTEST_OPT     "-dso_ref"
 
 enum test_types_en {
     CRYPTO_FIRST,
     SSL_FIRST,
-    JUST_CRYPTO
+    JUST_CRYPTO,
+    DSO_REFTEST
 };
 
 int main(int argc, char **argv)
@@ -137,7 +135,7 @@ int main(int argc, char **argv)
         void (*func) (void);
         SHLIB_SYM sym;
     } tls_method_sym, ssl_ctx_new_sym, ssl_ctx_free_sym, err_get_error_sym,
-    openssl_version_num_sym;
+    openssl_version_num_sym, dso_dsobyaddr_sym, dso_free_sym;
     enum test_types_en test_type;
     int i;
 
@@ -152,6 +150,8 @@ int main(int argc, char **argv)
             test_type = SSL_FIRST;
     } else if (strcmp(argv[1], JUST_CRYPTO_OPT) == 0) {
             test_type = JUST_CRYPTO;
+    } else if (strcmp(argv[1], DSO_REFTEST_OPT) == 0) {
+            test_type = DSO_REFTEST;
     } else {
         printf("Unrecognised argument\n");
         return 1;
@@ -159,7 +159,8 @@ int main(int argc, char **argv)
 
     for (i = 0; i < 2; i++) {
         if ((i == 0 && (test_type == CRYPTO_FIRST
-                       || test_type == JUST_CRYPTO))
+                       || test_type == JUST_CRYPTO
+                       || test_type == DSO_REFTEST))
                || (i == 1 && test_type == SSL_FIRST)) {
             if (!shlib_load(argv[2], &cryptolib)) {
                 printf("Unable to load libcrypto\n");
@@ -175,7 +176,7 @@ int main(int argc, char **argv)
         }
     }
 
-    if (test_type != JUST_CRYPTO) {
+    if (test_type != JUST_CRYPTO && test_type != DSO_REFTEST) {
         if (!shlib_sym(ssllib, TLS_METHOD, &tls_method_sym.sym)
                 || !shlib_sym(ssllib, SSL_CTX_NEW, &ssl_ctx_new_sym.sym)
                 || !shlib_sym(ssllib, SSL_CTX_FREE, &ssl_ctx_free_sym.sym)) {
@@ -210,11 +211,57 @@ int main(int argc, char **argv)
         return 1;
     }
 
-    if (OpenSSL_version_num() != OPENSSL_VERSION_NUMBER) {
+    /*
+     * 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
+    if ((OpenSSL_version_num() & COMPATIBILITY_MASK)
+        != (OPENSSL_VERSION_NUMBER & COMPATIBILITY_MASK)) {
         printf("Unexpected library version loaded\n");
         return 1;
     }
 
+    if ((OpenSSL_version_num() & ~COMPATIBILITY_MASK)
+        < (OPENSSL_VERSION_NUMBER & ~COMPATIBILITY_MASK)) {
+        printf("Unexpected library version loaded\n");
+        return 1;
+    }
+
+    if (test_type == DSO_REFTEST) {
+# ifdef DSO_DLFCN
+        /*
+         * 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 (!shlib_sym(cryptolib, DSO_DSOBYADDR, &dso_dsobyaddr_sym.sym)
+            || !shlib_sym(cryptolib, DSO_FREE, &dso_free_sym.sym)) {
+            printf("Unable to load crypto dso symbols\n");
+            return 1;
+        }
+
+        DSO_dsobyaddr = (DSO_dsobyaddr_t)dso_dsobyaddr_sym.func;
+        DSO_free = (DSO_free_t)dso_free_sym.func;
+
+        {
+            DSO *hndl;
+            /* use known symbol from crypto module */
+            if ((hndl = DSO_dsobyaddr((void (*)())ERR_get_error, 0)) != NULL) {
+                DSO_free(hndl);
+            } else {
+                printf("Unable to obtain DSO reference from crypto symbol\n");
+                return 1;
+            }
+        }
+# endif /* DSO_DLFCN */
+    }
+
     for (i = 0; i < 2; i++) {
         if ((i == 0 && test_type == CRYPTO_FIRST)
                 || (i == 1 && test_type == SSL_FIRST)) {
@@ -224,7 +271,8 @@ int main(int argc, char **argv)
             }
         }
         if ((i == 0 && (test_type == SSL_FIRST
-                       || test_type == JUST_CRYPTO))
+                       || test_type == JUST_CRYPTO
+                       || test_type == DSO_REFTEST))
                 || (i == 1 && test_type == CRYPTO_FIRST)) {
             if (!shlib_close(cryptolib)) {
                 printf("Unable to close libcrypto\n");