[openssl-commits] [openssl] OpenSSL_1_1_0-stable update

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


The branch OpenSSL_1_1_0-stable has been updated
       via  2e6b83f608b7a4b315146895ac911e8c06d40db1 (commit)
       via  848dc9619049f6aaad91b367eed309d987009e5e (commit)
       via  389d4655b143bc6d495ca6c48809aac8f4356e01 (commit)
       via  4af9f7fe79ff82b90c16969b7e5871435056377b (commit)
       via  f722f18e1a3560c13bd018711a30acca73c8d619 (commit)
       via  93558bf5190226494d3b549397fbf94214846d0d (commit)
      from  717f4026d593119cf493b3c1e045462c540f4cb3 (commit)


- Log -----------------------------------------------------------------
commit 2e6b83f608b7a4b315146895ac911e8c06d40db1
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>
    (cherry picked from commit 2b59d1beaad43d9cf8eb916a437db63bc8ce1d3a)

commit 848dc9619049f6aaad91b367eed309d987009e5e
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>
    (cherry picked from commit b6d5ba1a9f004d637acac18ae3519fe063b6b5e1)

commit 389d4655b143bc6d495ca6c48809aac8f4356e01
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>
    (cherry picked from commit b987d748e46d4ec19a45e5ec9e890a9003a361d6)

commit 4af9f7fe79ff82b90c16969b7e5871435056377b
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>
    (cherry picked from commit 5836780f436e03be231ff245f04f2f9f2f0ede91)

commit f722f18e1a3560c13bd018711a30acca73c8d619
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>
    (cherry picked from commit b39eda7ee69a9277c722f8789736e00dc680cda6)

commit 93558bf5190226494d3b549397fbf94214846d0d
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>
    (cherry picked from commit cb6ea61c161e88aa0268c77f308469a67b2ec063)

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

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           |  23 ++++
 test/build.info                  |   6 +
 test/recipes/90-test_shlibload.t |  37 ++++++
 test/shlibloadtest.c             | 243 +++++++++++++++++++++++++++++++++++++++
 util/libcrypto.num               |   2 +
 14 files changed, 502 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 adb40e3..c80d02f 100644
--- a/Configurations/10-main.conf
+++ b/Configurations/10-main.conf
@@ -631,7 +631,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" => {
@@ -647,14 +648,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" => {
@@ -710,7 +711,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.
@@ -719,14 +720,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",
     },
 
@@ -753,7 +754,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" => {
@@ -779,7 +780,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" => {
@@ -803,7 +804,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",
     },
 
@@ -819,14 +820,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",
     },
 
@@ -855,7 +856,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 90d387e..b9a98dd 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 7423ecc..a939cb1 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 970beeb..f5de8a2 100644
--- a/include/internal/dso.h
+++ b/include/internal/dso.h
@@ -43,6 +43,10 @@ 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
+/*
  * The following flag controls the translation of symbol names to upper case.
  * This is currently only being implemented for OpenVMS.
  */
@@ -137,6 +141,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
@@ -177,6 +198,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
@@ -189,6 +211,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 b8fc431..e3a961d 100644
--- a/test/build.info
+++ b/test/build.info
@@ -274,6 +274,12 @@ IF[{- !$disabled{tests} -}]
   SOURCE[bio_enc_test]=bio_enc_test.c
   INCLUDE[bio_enc_test]=../include
   DEPEND[bio_enc_test]=../libcrypto
+
+  IF[{- !disabled{shared} -}]
+    PROGRAMS_NO_INST=shlibloadtest
+    SOURCE[shlibloadtest]=shlibloadtest.c
+    INCLUDE[shlibloadtest]=../include
+  ENDIF
 ENDIF
 
 {-
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 db6732e..a16cc9f 100644
--- a/util/libcrypto.num
+++ b/util/libcrypto.num
@@ -4206,3 +4206,5 @@ ECPARAMETERS_new                        4156	1_1_0	EXIST::FUNCTION:EC
 OCSP_RESPID_set_by_name                 4157	1_1_0a	EXIST::FUNCTION:OCSP
 OCSP_RESPID_set_by_key                  4158	1_1_0a	EXIST::FUNCTION:OCSP
 OCSP_RESPID_match                       4159	1_1_0a	EXIST::FUNCTION:OCSP
+DSO_pathbyaddr                          4170	1_1_0c	EXIST::FUNCTION:
+DSO_dsobyaddr                           4171	1_1_0c	EXIST::FUNCTION:


More information about the openssl-commits mailing list