[openssl-commits] [openssl] master update

Matt Caswell matt at openssl.org
Wed Nov 2 23:40:17 UTC 2016


The branch master has been updated
       via  2b59d1beaad43d9cf8eb916a437db63bc8ce1d3a (commit)
       via  b6d5ba1a9f004d637acac18ae3519fe063b6b5e1 (commit)
       via  b987d748e46d4ec19a45e5ec9e890a9003a361d6 (commit)
       via  5836780f436e03be231ff245f04f2f9f2f0ede91 (commit)
       via  b39eda7ee69a9277c722f8789736e00dc680cda6 (commit)
       via  cb6ea61c161e88aa0268c77f308469a67b2ec063 (commit)
      from  ce95f3b724f71f42dd57af4a0a8e2f571deaf94d (commit)


- Log -----------------------------------------------------------------
commit 2b59d1beaad43d9cf8eb916a437db63bc8ce1d3a
Author: Matt Caswell <matt at openssl.org>
Date:   Fri Oct 28 11:03:22 2016 +0100

    Implement GET_MODULE_HANDLE_EX_FLAG_PIN for windows
    
    Rather than leaking a reference, just call GetModuleHandleEx and pin the
    module on Windows.
    
    Reviewed-by: Tim Hudson <tjh at openssl.org>

commit b6d5ba1a9f004d637acac18ae3519fe063b6b5e1
Author: Matt Caswell <matt at openssl.org>
Date:   Tue Oct 18 15:11:57 2016 +0100

    Link using -znodelete
    
    Instead of deliberately leaking a reference to ourselves, use nodelete
    which does this more neatly. Only for Linux at the moment.
    
    Reviewed-by: Tim Hudson <tjh at openssl.org>

commit b987d748e46d4ec19a45e5ec9e890a9003a361d6
Author: Matt Caswell <matt at openssl.org>
Date:   Tue Oct 18 14:16:35 2016 +0100

    Add a test to dynamically load and unload the libraries
    
    This should demonstrate that the atexit() handling is working properly (or
    at least not crashing) on process exit.
    
    Reviewed-by: Tim Hudson <tjh at openssl.org>

commit 5836780f436e03be231ff245f04f2f9f2f0ede91
Author: Matt Caswell <matt at openssl.org>
Date:   Tue Oct 18 14:13:25 2016 +0100

    Ensure that libcrypto and libssl do not unload until the process exits
    
    Because we use atexit() to cleanup after ourselves, this will cause a
    problem if we have been dynamically loaded and then unloaded again: the
    atexit() handler may no longer be there.
    
    Most modern atexit() implementations can handle this, however there are
    still difficulties if libssl gets unloaded before libcrypto, because of
    the atexit() callback that libcrypto makes to libssl.
    
    The most robust solution seems to be to ensure that libcrypto and libssl
    never unload. This is done by simply deliberately leaking a dlopen()
    reference to them.
    
    Reviewed-by: Tim Hudson <tjh at openssl.org>

commit b39eda7ee69a9277c722f8789736e00dc680cda6
Author: Matt Caswell <matt at openssl.org>
Date:   Sat Oct 15 16:01:40 2016 +0100

    Add a DSO_dsobyaddr() function
    
    This works the same way as DSO_pathbyaddr() but instead returns a ptr to
    the DSO that contains the provided symbol.
    
    Reviewed-by: Tim Hudson <tjh at openssl.org>

commit cb6ea61c161e88aa0268c77f308469a67b2ec063
Author: Matt Caswell <matt at openssl.org>
Date:   Sat Oct 15 15:23:03 2016 +0100

    Partial revert of 3d8b2ec42 to add back DSO_pathbyaddr
    
    Commit 3d8b2ec42 removed various unused functions. However now we need to
    use one of them! This commit resurrects DSO_pathbyaddr(). We're not going to
    resurrect the Windows version though because what we need to achieve can be
    done a different way on Windows.
    
    Reviewed-by: Tim Hudson <tjh at openssl.org>

-----------------------------------------------------------------------

Summary of changes:
 Configurations/10-main.conf      |  25 ++--
 crypto/dso/dso_dl.c              |  34 ++++++
 crypto/dso/dso_dlfcn.c           |  34 ++++++
 crypto/dso/dso_err.c             |   2 +
 crypto/dso/dso_lib.c             |  35 +++++-
 crypto/dso/dso_locl.h            |   2 +
 crypto/dso/dso_vms.c             |   4 +-
 crypto/dso/dso_win32.c           |   1 +
 crypto/init.c                    |  70 +++++++++++
 include/internal/dso.h           |  24 ++++
 test/build.info                  |   6 +
 test/recipes/90-test_shlibload.t |  37 ++++++
 test/shlibloadtest.c             | 243 +++++++++++++++++++++++++++++++++++++++
 util/libcrypto.num               |   2 +
 14 files changed, 503 insertions(+), 16 deletions(-)
 create mode 100644 test/recipes/90-test_shlibload.t
 create mode 100644 test/shlibloadtest.c

diff --git a/Configurations/10-main.conf b/Configurations/10-main.conf
index 9b4c78f..b77efbf 100644
--- a/Configurations/10-main.conf
+++ b/Configurations/10-main.conf
@@ -632,7 +632,8 @@ sub vms_info {
         thread_scheme    => "pthreads",
         dso_scheme       => "dlfcn",
         shared_target    => "linux-shared",
-        shared_cflag     => "-fPIC",
+        shared_cflag     => "-fPIC -DOPENSSL_USE_NODELETE",
+        shared_ldflag    => "-znodelete",
         shared_extension => ".so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
     },
     "linux-generic64" => {
@@ -648,14 +649,14 @@ sub vms_info {
         inherit_from     => [ "linux-generic64", asm("ppc64_asm") ],
         cflags           => add("-m64 -DB_ENDIAN"),
         perlasm_scheme   => "linux64",
-        shared_ldflag    => "-m64",
+        shared_ldflag    => add("-m64"),
         multilib         => "64",
     },
     "linux-ppc64le" => {
         inherit_from     => [ "linux-generic64", asm("ppc64_asm") ],
         cflags           => add("-m64 -DL_ENDIAN"),
         perlasm_scheme   => "linux64le",
-        shared_ldflag    => "-m64",
+        shared_ldflag    => add("-m64"),
     },
 
     "linux-armv4" => {
@@ -711,7 +712,7 @@ sub vms_info {
         inherit_from     => [ "linux-generic32", asm("mips32_asm") ],
         cflags           => add("-mabi=32 -DBN_DIV3W"),
         perlasm_scheme   => "o32",
-        shared_ldflag    => "-mabi=32",
+        shared_ldflag    => add("-mabi=32"),
     },
     # mips32 and mips64 below refer to contemporary MIPS Architecture
     # specifications, MIPS32 and MIPS64, rather than to kernel bitness.
@@ -720,14 +721,14 @@ sub vms_info {
         cflags           => add("-mabi=n32 -DBN_DIV3W"),
         bn_ops           => "SIXTY_FOUR_BIT RC4_CHAR",
         perlasm_scheme   => "n32",
-        shared_ldflag    => "-mabi=n32",
+        shared_ldflag    => add("-mabi=n32"),
         multilib         => "32",
     },
     "linux64-mips64" => {
         inherit_from     => [ "linux-generic64", asm("mips64_asm") ],
         cflags           => add("-mabi=64 -DBN_DIV3W"),
         perlasm_scheme   => "64",
-        shared_ldflag    => "-mabi=64",
+        shared_ldflag    => add("-mabi=64"),
         multilib         => "64",
     },
 
@@ -754,7 +755,7 @@ sub vms_info {
         cflags           => add("-m64 -DL_ENDIAN"),
         bn_ops           => "SIXTY_FOUR_BIT_LONG",
         perlasm_scheme   => "elf",
-        shared_ldflag    => "-m64",
+        shared_ldflag    => add("-m64"),
         multilib         => "64",
     },
     "linux-x86_64-clang" => {
@@ -781,7 +782,7 @@ sub vms_info {
         inherit_from     => [ "linux-generic64", asm("s390x_asm") ],
         cflags           => add("-m64 -DB_ENDIAN"),
         perlasm_scheme   => "64",
-        shared_ldflag    => "-m64",
+        shared_ldflag    => add("-m64"),
         multilib         => "64",
     },
     "linux32-s390x" => {
@@ -805,7 +806,7 @@ sub vms_info {
         cflags           => add("-m31 -Wa,-mzarch -DB_ENDIAN"),
         bn_asm_src       => sub { my $r=join(" ", at _); $r=~s|asm/s390x\.S|bn_asm.c|; $r; },
         perlasm_scheme   => "31",
-        shared_ldflag    => "-m31",
+        shared_ldflag    => add("-m31"),
         multilib         => "/highgprs",
     },
 
@@ -821,14 +822,14 @@ sub vms_info {
         # but -Wa,-Av8plus should do the trick no matter what.
         inherit_from     => [ "linux-generic32", asm("sparcv9_asm") ],
         cflags           => add("-m32 -mcpu=ultrasparc -Wa,-Av8plus -DB_ENDIAN -DBN_DIV2W"),
-        shared_ldflag    => "-m32",
+        shared_ldflag    => add("-m32"),
     },
     "linux64-sparcv9" => {
         # GCC 3.1 is a requirement
         inherit_from     => [ "linux-generic64", asm("sparcv9_asm") ],
         cflags           => add("-m64 -mcpu=ultrasparc -DB_ENDIAN"),
         bn_ops           => "BN_LLONG RC4_CHAR",
-        shared_ldflag    => "-m64",
+        shared_ldflag    => add("-m64"),
         multilib         => "64",
     },
 
@@ -857,7 +858,7 @@ sub vms_info {
         dso_scheme       => "dlfcn",
         shared_target    => "linux-shared",
         shared_cflag     => "--pic",
-        shared_ldflag    => "-z --sysv --shared",
+        shared_ldflag    => add("-z --sysv --shared"),
         shared_extension => ".so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
         ranlib           => "true",
     },
diff --git a/crypto/dso/dso_dl.c b/crypto/dso/dso_dl.c
index bc29fb2..d80bf56 100644
--- a/crypto/dso/dso_dl.c
+++ b/crypto/dso/dso_dl.c
@@ -22,6 +22,7 @@ static DSO_FUNC_TYPE dl_bind_func(DSO *dso, const char *symname);
 static char *dl_name_converter(DSO *dso, const char *filename);
 static char *dl_merger(DSO *dso, const char *filespec1,
                        const char *filespec2);
+static int dl_pathbyaddr(void *addr, char *path, int sz);
 static void *dl_globallookup(const char *name);
 
 static DSO_METHOD dso_meth_dl = {
@@ -34,6 +35,7 @@ static DSO_METHOD dso_meth_dl = {
     dl_merger,
     NULL,                       /* init */
     NULL,                       /* finish */
+    dl_pathbyaddr,
     dl_globallookup
 };
 
@@ -235,6 +237,38 @@ static char *dl_name_converter(DSO *dso, const char *filename)
     return (translated);
 }
 
+static int dl_pathbyaddr(void *addr, char *path, int sz)
+{
+    struct shl_descriptor inf;
+    int i, len;
+
+    if (addr == NULL) {
+        union {
+            int (*f) (void *, char *, int);
+            void *p;
+        } t = {
+            dl_pathbyaddr
+        };
+        addr = t.p;
+    }
+
+    for (i = -1; shl_get_r(i, &inf) == 0; i++) {
+        if (((size_t)addr >= inf.tstart && (size_t)addr < inf.tend) ||
+            ((size_t)addr >= inf.dstart && (size_t)addr < inf.dend)) {
+            len = (int)strlen(inf.filename);
+            if (sz <= 0)
+                return len + 1;
+            if (len >= sz)
+                len = sz - 1;
+            memcpy(path, inf.filename, len);
+            path[len++] = 0;
+            return len;
+        }
+    }
+
+    return -1;
+}
+
 static void *dl_globallookup(const char *name)
 {
     void *ret;
diff --git a/crypto/dso/dso_dlfcn.c b/crypto/dso/dso_dlfcn.c
index 624052b..a4b0cdd 100644
--- a/crypto/dso/dso_dlfcn.c
+++ b/crypto/dso/dso_dlfcn.c
@@ -44,6 +44,7 @@ static DSO_FUNC_TYPE dlfcn_bind_func(DSO *dso, const char *symname);
 static char *dlfcn_name_converter(DSO *dso, const char *filename);
 static char *dlfcn_merger(DSO *dso, const char *filespec1,
                           const char *filespec2);
+static int dlfcn_pathbyaddr(void *addr, char *path, int sz);
 static void *dlfcn_globallookup(const char *name);
 
 static DSO_METHOD dso_meth_dlfcn = {
@@ -56,6 +57,7 @@ static DSO_METHOD dso_meth_dlfcn = {
     dlfcn_merger,
     NULL,                       /* init */
     NULL,                       /* finish */
+    dlfcn_pathbyaddr,
     dlfcn_globallookup
 };
 
@@ -306,6 +308,38 @@ static int dladdr(void *address, Dl_info *dl)
 }
 # endif                         /* __sgi */
 
+static int dlfcn_pathbyaddr(void *addr, char *path, int sz)
+{
+# ifdef HAVE_DLINFO
+    Dl_info dli;
+    int len;
+
+    if (addr == NULL) {
+        union {
+            int (*f) (void *, char *, int);
+            void *p;
+        } t = {
+            dlfcn_pathbyaddr
+        };
+        addr = t.p;
+    }
+
+    if (dladdr(addr, &dli)) {
+        len = (int)strlen(dli.dli_fname);
+        if (sz <= 0)
+            return len + 1;
+        if (len >= sz)
+            len = sz - 1;
+        memcpy(path, dli.dli_fname, len);
+        path[len++] = 0;
+        return len;
+    }
+
+    ERR_add_error_data(2, "dlfcn_pathbyaddr(): ", dlerror());
+# endif
+    return -1;
+}
+
 static void *dlfcn_globallookup(const char *name)
 {
     void *ret = NULL, *handle = dlopen(NULL, RTLD_LAZY);
diff --git a/crypto/dso/dso_err.c b/crypto/dso/dso_err.c
index a180580..07588d5 100644
--- a/crypto/dso/dso_err.c
+++ b/crypto/dso/dso_err.c
@@ -38,6 +38,7 @@ static ERR_STRING_DATA DSO_str_functs[] = {
     {ERR_FUNC(DSO_F_DSO_LOAD), "DSO_load"},
     {ERR_FUNC(DSO_F_DSO_MERGE), "DSO_merge"},
     {ERR_FUNC(DSO_F_DSO_NEW_METHOD), "DSO_new_method"},
+    {ERR_FUNC(DSO_F_DSO_PATHBYADDR), "DSO_pathbyaddr"},
     {ERR_FUNC(DSO_F_DSO_SET_FILENAME), "DSO_set_filename"},
     {ERR_FUNC(DSO_F_DSO_UP_REF), "DSO_up_ref"},
     {ERR_FUNC(DSO_F_VMS_BIND_SYM), "vms_bind_sym"},
@@ -50,6 +51,7 @@ static ERR_STRING_DATA DSO_str_functs[] = {
     {ERR_FUNC(DSO_F_WIN32_LOAD), "win32_load"},
     {ERR_FUNC(DSO_F_WIN32_MERGER), "win32_merger"},
     {ERR_FUNC(DSO_F_WIN32_NAME_CONVERTER), "win32_name_converter"},
+    {ERR_FUNC(DSO_F_WIN32_PATHBYADDR), "win32_pathbyaddr"},
     {ERR_FUNC(DSO_F_WIN32_SPLITTER), "win32_splitter"},
     {ERR_FUNC(DSO_F_WIN32_UNLOAD), "win32_unload"},
     {0, NULL}
diff --git a/crypto/dso/dso_lib.c b/crypto/dso/dso_lib.c
index bea8776..52816df 100644
--- a/crypto/dso/dso_lib.c
+++ b/crypto/dso/dso_lib.c
@@ -73,9 +73,11 @@ int DSO_free(DSO *dso)
         return 1;
     REF_ASSERT_ISNT(i < 0);
 
-    if ((dso->meth->dso_unload != NULL) && !dso->meth->dso_unload(dso)) {
-        DSOerr(DSO_F_DSO_FREE, DSO_R_UNLOAD_FAILED);
-        return 0;
+    if ((dso->flags & DSO_FLAG_NO_UNLOAD_ON_FREE) == 0) {
+        if ((dso->meth->dso_unload != NULL) && !dso->meth->dso_unload(dso)) {
+            DSOerr(DSO_F_DSO_FREE, DSO_R_UNLOAD_FAILED);
+            return 0;
+        }
     }
 
     if ((dso->meth->finish != NULL) && !dso->meth->finish(dso)) {
@@ -304,6 +306,33 @@ char *DSO_convert_filename(DSO *dso, const char *filename)
     return (result);
 }
 
+int DSO_pathbyaddr(void *addr, char *path, int sz)
+{
+    DSO_METHOD *meth = default_DSO_meth;
+    if (meth == NULL)
+        meth = DSO_METHOD_openssl();
+    if (meth->pathbyaddr == NULL) {
+        DSOerr(DSO_F_DSO_PATHBYADDR, DSO_R_UNSUPPORTED);
+        return -1;
+    }
+    return (*meth->pathbyaddr) (addr, path, sz);
+}
+
+DSO *DSO_dsobyaddr(void *addr, int flags)
+{
+    DSO *ret = NULL;
+    char *filename = NULL;
+    int len = DSO_pathbyaddr(addr, NULL, 0);
+
+    filename = OPENSSL_malloc(len);
+    if (filename != NULL
+            && DSO_pathbyaddr(addr, filename, len) == len)
+        ret = DSO_load(NULL, filename, NULL, flags);
+
+    OPENSSL_free(filename);
+    return ret;
+}
+
 void *DSO_global_lookup(const char *name)
 {
     DSO_METHOD *meth = default_DSO_meth;
diff --git a/crypto/dso/dso_locl.h b/crypto/dso/dso_locl.h
index 1976787..fbfad05 100644
--- a/crypto/dso/dso_locl.h
+++ b/crypto/dso/dso_locl.h
@@ -99,6 +99,8 @@ struct dso_meth_st {
     /* [De]Initialisation handlers. */
     int (*init) (DSO *dso);
     int (*finish) (DSO *dso);
+    /* Return pathname of the module containing location */
+    int (*pathbyaddr) (void *addr, char *path, int sz);
     /* Perform global symbol lookup, i.e. among *all* modules */
     void *(*globallookup) (const char *symname);
 };
diff --git a/crypto/dso/dso_vms.c b/crypto/dso/dso_vms.c
index 2e0d84c..e3c157b 100644
--- a/crypto/dso/dso_vms.c
+++ b/crypto/dso/dso_vms.c
@@ -50,7 +50,9 @@ static DSO_METHOD dso_meth_vms = {
     vms_name_converter,
     vms_merger,
     NULL,                       /* init */
-    NULL                        /* finish */
+    NULL,                       /* finish */
+    NULL,                       /* pathbyaddr */
+    NULL                        /* globallookup */
 };
 
 /*
diff --git a/crypto/dso/dso_win32.c b/crypto/dso/dso_win32.c
index 4ac6e71..4a4c34a 100644
--- a/crypto/dso/dso_win32.c
+++ b/crypto/dso/dso_win32.c
@@ -77,6 +77,7 @@ static DSO_METHOD dso_meth_win32 = {
     win32_merger,
     NULL,                       /* init */
     NULL,                       /* finish */
+    NULL,                       /* pathbyaddr */
     win32_globallookup
 };
 
diff --git a/crypto/init.c b/crypto/init.c
index 93ec7bb..4363bee 100644
--- a/crypto/init.c
+++ b/crypto/init.c
@@ -23,6 +23,7 @@
 #include <stdlib.h>
 #include <assert.h>
 #include <internal/thread_once.h>
+#include <internal/dso.h>
 
 static int stopped = 0;
 
@@ -79,6 +80,34 @@ DEFINE_RUN_ONCE_STATIC(ossl_init_base)
         return 0;
     OPENSSL_cpuid_setup();
     base_inited = 1;
+
+#ifndef OPENSSL_USE_NODELETE
+# ifdef DSO_WIN32
+    {
+        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);
+
+        return (ret == TRUE) ? 1 : 0;
+    }
+# else
+    /*
+     * Deliberately leak a reference to ourselves. This will force the library
+     * to remain loaded until the atexit() handler is run a process exit.
+     */
+    {
+        DSO *dso = NULL;
+
+        dso = DSO_dsobyaddr(&base_inited, DSO_FLAG_NO_UNLOAD_ON_FREE);
+        DSO_free(dso);
+    }
+# endif
+#endif
+
     return 1;
 }
 
@@ -575,6 +604,47 @@ int OPENSSL_atexit(void (*handler)(void))
 {
     OPENSSL_INIT_STOP *newhand;
 
+#ifndef OPENSSL_USE_NODELETE
+    {
+        union {
+            void *sym;
+            void (*func)(void);
+        } handlersym;
+
+        handlersym.func = handler;
+# ifdef DSO_WIN32
+        {
+            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,
+                                    handlersym.sym, &handle);
+
+            if (!ret)
+                return 0;
+        }
+# else
+        /*
+         * 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
+         * unneccessary.
+         */
+        {
+            DSO *dso = NULL;
+
+            dso = DSO_dsobyaddr(handlersym.sym, DSO_FLAG_NO_UNLOAD_ON_FREE);
+            DSO_free(dso);
+        }
+# endif
+    }
+#endif
+
     newhand = OPENSSL_malloc(sizeof(*newhand));
     if (newhand == NULL)
         return 0;
diff --git a/include/internal/dso.h b/include/internal/dso.h
index 79d98f4..6acd501 100644
--- a/include/internal/dso.h
+++ b/include/internal/dso.h
@@ -43,6 +43,11 @@ extern "C" {
 # define DSO_FLAG_NAME_TRANSLATION_EXT_ONLY      0x02
 
 /*
+ * Don't unload the DSO when we call DSO_free()
+ */
+# define DSO_FLAG_NO_UNLOAD_ON_FREE              0x04
+
+/*
  * This flag loads the library with public symbols. Meaning: The exported
  * symbols of this library are public to all libraries loaded after this
  * library. At the moment only implemented in unix.
@@ -131,6 +136,23 @@ DSO_FUNC_TYPE DSO_bind_func(DSO *dso, const char *symname);
 DSO_METHOD *DSO_METHOD_openssl(void);
 
 /*
+ * This function writes null-terminated pathname of DSO module containing
+ * 'addr' into 'sz' large caller-provided 'path' and returns the number of
+ * characters [including trailing zero] written to it. If 'sz' is 0 or
+ * negative, 'path' is ignored and required amount of charachers [including
+ * trailing zero] to accommodate pathname is returned. If 'addr' is NULL, then
+ * pathname of cryptolib itself is returned. Negative or zero return value
+ * denotes error.
+ */
+int DSO_pathbyaddr(void *addr, char *path, int sz);
+
+/*
+ * Like DSO_pathbyaddr() but instead returns a handle to the DSO for the symbol
+ * or NULL on error.
+ */
+DSO *DSO_dsobyaddr(void *addr, int flags);
+
+/*
  * This function should be used with caution! It looks up symbols in *all*
  * loaded modules and if module gets unloaded by somebody else attempt to
  * dereference the pointer is doomed to have fatal consequences. Primary
@@ -171,6 +193,7 @@ int ERR_load_DSO_strings(void);
 # define DSO_F_DSO_LOAD                                   112
 # define DSO_F_DSO_MERGE                                  132
 # define DSO_F_DSO_NEW_METHOD                             113
+# define DSO_F_DSO_PATHBYADDR                             105
 # define DSO_F_DSO_SET_FILENAME                           129
 # define DSO_F_DSO_UP_REF                                 114
 # define DSO_F_VMS_BIND_SYM                               115
@@ -183,6 +206,7 @@ int ERR_load_DSO_strings(void);
 # define DSO_F_WIN32_LOAD                                 120
 # define DSO_F_WIN32_MERGER                               134
 # define DSO_F_WIN32_NAME_CONVERTER                       125
+# define DSO_F_WIN32_PATHBYADDR                           109
 # define DSO_F_WIN32_SPLITTER                             136
 # define DSO_F_WIN32_UNLOAD                               121
 
diff --git a/test/build.info b/test/build.info
index 5246969..818d073 100644
--- a/test/build.info
+++ b/test/build.info
@@ -282,6 +282,12 @@ IF[{- !$disabled{tests} -}]
     DEPEND[dtls_mtu_test]=../libcrypto ../libssl
   ENDIF
 
+  IF[{- !disabled{shared} -}]
+    PROGRAMS_NO_INST=shlibloadtest
+    SOURCE[shlibloadtest]=shlibloadtest.c
+    INCLUDE[shlibloadtest]=../include
+  ENDIF
+
   IF[{- $disabled{shared} -}]
     PROGRAMS_NO_INST=wpackettest cipher_overhead_test
     SOURCE[wpackettest]=wpackettest.c testutil.c
diff --git a/test/recipes/90-test_shlibload.t b/test/recipes/90-test_shlibload.t
new file mode 100644
index 0000000..dc35613
--- /dev/null
+++ b/test/recipes/90-test_shlibload.t
@@ -0,0 +1,37 @@
+#! /usr/bin/env perl
+# Copyright 2016 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
+# in the file LICENSE in the source distribution or at
+# https://www.openssl.org/source/license.html
+
+
+use OpenSSL::Test qw/:DEFAULT bldtop_dir/;
+use OpenSSL::Test::Utils;
+
+#Load configdata.pm
+
+BEGIN {
+    setup("test_shlibload");
+}
+use lib bldtop_dir('.');
+use configdata;
+
+plan skip_all => "Test only supported in a shared build" if disabled("shared");
+
+plan tests => 3;
+
+ok(run(test(["shlibloadtest", "-crypto_first",
+             $unified_info{sharednames}->{libcrypto},
+             $unified_info{sharednames}->{libssl}])),
+   "running shlibloadtest -crypto_first");
+ok(run(test(["shlibloadtest", "-ssl_first",
+             $unified_info{sharednames}->{libcrypto},
+             $unified_info{sharednames}->{libssl}])),
+   "running shlibloadtest -ssl_first");
+ok(run(test(["shlibloadtest", "-just_crypto",
+             $unified_info{sharednames}->{libcrypto},
+             $unified_info{sharednames}->{libssl}])),
+   "running shlibloadtest -just_crypto");
+
diff --git a/test/shlibloadtest.c b/test/shlibloadtest.c
new file mode 100644
index 0000000..be1e784
--- /dev/null
+++ b/test/shlibloadtest.c
@@ -0,0 +1,243 @@
+/*
+ * Copyright 2016 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
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <openssl/opensslv.h>
+
+#define SSL_CTX_NEW "SSL_CTX_new"
+#define SSL_CTX_FREE "SSL_CTX_free"
+#define TLS_METHOD "TLS_method"
+
+#define ERR_GET_ERROR "ERR_get_error"
+#define OPENSSL_VERSION_NUM_FUNC "OpenSSL_version_num"
+
+typedef struct ssl_ctx_st SSL_CTX;
+typedef struct ssl_method_st SSL_METHOD;
+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);
+
+TLS_method_t TLS_method;
+SSL_CTX_new_t SSL_CTX_new;
+SSL_CTX_free_t SSL_CTX_free;
+
+ERR_get_error_t ERR_get_error;
+OpenSSL_version_num_t OpenSSL_version_num;
+
+
+#ifdef DSO_DLFCN
+
+# include <dlfcn.h>
+
+typedef void * SHLIB;
+typedef void * SHLIB_SYM;
+
+# define SHARED_LIBRARY_SUFFIX ".so"
+
+static int shlib_load(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);
+
+    if (*lib == NULL)
+        return 0;
+
+    return 1;
+}
+
+static int shlib_sym(SHLIB lib, const char *symname, SHLIB_SYM *sym)
+{
+    *sym = dlsym(lib, symname);
+
+    return *sym != NULL;
+}
+
+static int shlib_close(SHLIB lib)
+{
+    if (dlclose(lib) != 0)
+        return 0;
+
+    return 1;
+}
+
+#elif defined(DSO_WIN32)
+
+# include <windows.h>
+
+typedef HINSTANCE SHLIB;
+typedef void * SHLIB_SYM;
+
+static int shlib_load(char *filename, SHLIB *lib)
+{
+    *lib = LoadLibraryA(filename);
+    if (*lib == NULL)
+        return 0;
+
+    return 1;
+}
+
+static int shlib_sym(SHLIB lib, const char *symname, SHLIB_SYM *sym)
+{
+    *sym = (SHLIB_SYM)GetProcAddress(lib, symname);
+
+    return *sym != NULL;
+}
+
+static int shlib_close(SHLIB lib)
+{
+    if (FreeLibrary(lib) == 0)
+        return 0;
+
+    return 1;
+}
+
+#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"
+
+enum test_types_en {
+    CRYPTO_FIRST,
+    SSL_FIRST,
+    JUST_CRYPTO
+};
+
+int main(int argc, char **argv)
+{
+    SHLIB ssllib, cryptolib;
+    SSL_CTX *ctx;
+    union {
+        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;
+    enum test_types_en test_type;
+    int i;
+
+    if (argc != 4) {
+        printf("Unexpected number of arguments\n");
+        return 1;
+    }
+
+    if (strcmp(argv[1], CRYPTO_FIRST_OPT) == 0) {
+        test_type = CRYPTO_FIRST;
+    } else if (strcmp(argv[1], SSL_FIRST_OPT) == 0) {
+            test_type = SSL_FIRST;
+    } else if (strcmp(argv[1], JUST_CRYPTO_OPT) == 0) {
+            test_type = JUST_CRYPTO;
+    } else {
+        printf("Unrecognised argument\n");
+        return 1;
+    }
+
+    for (i = 0; i < 2; i++) {
+        if ((i == 0 && (test_type == CRYPTO_FIRST
+                       || test_type == JUST_CRYPTO))
+               || (i == 1 && test_type == SSL_FIRST)) {
+            if (!shlib_load(argv[2], &cryptolib)) {
+                printf("Unable to load libcrypto\n");
+                return 1;
+            }
+        }
+        if ((i == 0 && test_type == SSL_FIRST)
+                || (i == 1 && test_type == CRYPTO_FIRST)) {
+            if (!shlib_load(argv[3], &ssllib)) {
+                printf("Unable to load libssl\n");
+                return 1;
+            }
+        }
+    }
+
+    if (test_type != JUST_CRYPTO) {
+        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)) {
+            printf("Unable to load ssl symbols\n");
+            return 1;
+        }
+
+        TLS_method = (TLS_method_t)tls_method_sym.func;
+        SSL_CTX_new = (SSL_CTX_new_t)ssl_ctx_new_sym.func;
+        SSL_CTX_free = (SSL_CTX_free_t)ssl_ctx_free_sym.func;
+
+        ctx = SSL_CTX_new(TLS_method());
+        if (ctx == NULL) {
+            printf("Unable to create SSL_CTX\n");
+            return 1;
+        }
+        SSL_CTX_free(ctx);
+    }
+
+    if (!shlib_sym(cryptolib, ERR_GET_ERROR, &err_get_error_sym.sym)
+            || !shlib_sym(cryptolib, OPENSSL_VERSION_NUM_FUNC,
+                          &openssl_version_num_sym.sym)) {
+        printf("Unable to load crypto symbols\n");
+        return 1;
+    }
+
+    ERR_get_error = (ERR_get_error_t)err_get_error_sym.func;
+    OpenSSL_version_num = (OpenSSL_version_num_t)openssl_version_num_sym.func;
+
+    if (ERR_get_error() != 0) {
+        printf("Unexpected error in error queue\n");
+        return 1;
+    }
+
+    if (OpenSSL_version_num() != OPENSSL_VERSION_NUMBER) {
+        printf("Unexpected library version loaded\n");
+        return 1;
+    }
+
+    for (i = 0; i < 2; i++) {
+        if ((i == 0 && test_type == CRYPTO_FIRST)
+                || (i == 1 && test_type == SSL_FIRST)) {
+            if (!shlib_close(ssllib)) {
+                printf("Unable to close libssl\n");
+                return 1;
+            }
+        }
+        if ((i == 0 && (test_type == SSL_FIRST
+                       || test_type == JUST_CRYPTO))
+                || (i == 1 && test_type == CRYPTO_FIRST)) {
+            if (!shlib_close(cryptolib)) {
+                printf("Unable to close libcrypto\n");
+                return 1;
+            }
+        }
+    }
+
+    printf("Success\n");
+    return 0;
+}
+#else
+int main(void)
+{
+    printf("Test not implemented on this platform\n");
+    return 0;
+}
+#endif
diff --git a/util/libcrypto.num b/util/libcrypto.num
index e04580c..0b4190b 100644
--- a/util/libcrypto.num
+++ b/util/libcrypto.num
@@ -4216,3 +4216,5 @@ BIO_meth_get_read_ex                    4166	1_1_1	EXIST::FUNCTION:
 BIO_write_ex                            4167	1_1_1	EXIST::FUNCTION:
 BIO_meth_get_write_ex                   4168	1_1_1	EXIST::FUNCTION:
 BIO_meth_set_write_ex                   4169	1_1_1	EXIST::FUNCTION:
+DSO_pathbyaddr                          4170	1_1_0c	EXIST::FUNCTION:
+DSO_dsobyaddr                           4171	1_1_0c	EXIST::FUNCTION:


More information about the openssl-commits mailing list