Introduce a no-pinshared option
authorMatt Caswell <matt@openssl.org>
Fri, 16 Nov 2018 14:05:14 +0000 (14:05 +0000)
committerMatt Caswell <matt@openssl.org>
Fri, 4 Jan 2019 20:23:16 +0000 (20:23 +0000)
This option prevents OpenSSL from pinning itself in memory.

Fixes #7598

[extended tests]

Reviewed-by: Tim Hudson <tjh@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/7983)

Configurations/10-main.conf
Configure
INSTALL
crypto/init.c
test/shlibloadtest.c

index ac8828e7e36567567bce808dbc7c2fcd1de7c40e..37e20011cdc2cc762895f2eb5363083455b55774 100644 (file)
@@ -651,7 +651,7 @@ my %targets = (
         dso_scheme       => "dlfcn",
         shared_target    => "linux-shared",
         shared_cflag     => "-fPIC",
-        shared_ldflag    => "-Wl,-znodelete",
+        shared_ldflag    => sub { $disabled{pinshared} ? () : "-Wl,-znodelete" },
         shared_extension => ".so.\$(SHLIB_VERSION_NUMBER)",
         enable           => [ "afalgeng" ],
     },
index b6c9465875684a9c9d78b2cb753e57492af1c26a..7b9501aea57f521cf7677a375a357c4a0716aba5 100755 (executable)
--- a/Configure
+++ b/Configure
@@ -374,6 +374,7 @@ my @disablables = (
     "msan",
     "multiblock",
     "nextprotoneg",
+    "pinshared",
     "ocb",
     "ocsp",
     "pic",
diff --git a/INSTALL b/INSTALL
index 86412c718161e5c7d9a504097b5cec3bd5fc462f..3570dea422966c1f1466acc54956f97ce599f43e 100644 (file)
--- a/INSTALL
+++ b/INSTALL
   no-pic
                    Don't build with support for Position Independent Code.
 
+  no-pinshared     By default OpenSSL will attempt to stay in memory until the
+                   process exits. This is so that libcrypto and libssl can be
+                   properly cleaned up automatically via an "atexit()" handler.
+                   The handler is registered by libcrypto and cleans up both
+                   libraries. On some platforms the atexit() handler will run on
+                   unload of libcrypto (if it has been dynamically loaded)
+                   rather than at process exit. This option can be used to stop
+                   OpenSSL from attempting to stay in memory until the process
+                   exits. This could lead to crashes if either libcrypto or
+                   libssl have already been unloaded at the point
+                   that the atexit handler is invoked, e.g. on a platform which
+                   calls atexit() on unload of the library, and libssl is
+                   unloaded before libcrypto then a crash is likely to happen.
+                   Applications can suppress running of the atexit() handler at
+                   run time by using the OPENSSL_INIT_NO_ATEXIT option to
+                   OPENSSL_init_crypto(). See the man page for it for further
+                   details.
+
   no-posix-io
                    Don't use POSIX IO capabilities.
 
index 1bafb17a9270167477633388533541c7fc1f2411..1c50f2994ec7d49b37acc0fd4477a88d56ca4f82 100644 (file)
@@ -147,7 +147,9 @@ DEFINE_RUN_ONCE_STATIC(ossl_init_load_crypto_nodelete)
 #ifdef OPENSSL_INIT_DEBUG
     fprintf(stderr, "OPENSSL_INIT: ossl_init_load_crypto_nodelete()\n");
 #endif
-#if !defined(OPENSSL_NO_DSO) && !defined(OPENSSL_USE_NODELETE)
+#if !defined(OPENSSL_NO_DSO) \
+    && !defined(OPENSSL_USE_NODELETE) \
+    && !defined(OPENSSL_NO_PINSHARED)
 # ifdef DSO_WIN32
     {
         HMODULE handle = NULL;
@@ -735,7 +737,9 @@ int OPENSSL_atexit(void (*handler)(void))
 {
     OPENSSL_INIT_STOP *newhand;
 
-#if !defined(OPENSSL_NO_DSO) && !defined(OPENSSL_USE_NODELETE)
+#if !defined(OPENSSL_NO_DSO) \
+    && !defined(OPENSSL_USE_NODELETE)\
+    && !defined(OPENSSL_NO_PINSHARED)
     {
         union {
             void *sym;
index aebaee92c4899e4b76646eaaa9876ba1e4b52a1b..d88cf887b6cc3787f9bbf54be3ad7b273a1b1b9c 100644 (file)
@@ -102,6 +102,8 @@ static int shlib_close(SHLIB lib)
 
 #if defined(DSO_DLFCN) || defined(DSO_WIN32)
 
+static int atexit_handler_done = 0;
+
 static void atexit_handler(void)
 {
     FILE *atexit_file = fopen(path_atexit, "w");
@@ -111,6 +113,7 @@ static void atexit_handler(void)
 
     fprintf(atexit_file, "atexit() run\n");
     fclose(atexit_file);
+    atexit_handler_done++;
 }
 
 static int test_lib(void)
@@ -250,33 +253,34 @@ static int test_lib(void)
 # endif /* DSO_DLFCN */
     }
 
-    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");
-            goto end;
-        }
-        if (test_type != CRYPTO_FIRST)
-            break;
-        /* Fall through */
+    if (!shlib_close(cryptolib)) {
+        fprintf(stderr, "Failed to close libcrypto\n");
+        goto end;
+    }
 
-    case SSL_FIRST:
-        if (test_type == CRYPTO_FIRST && !shlib_close(ssllib)) {
+    if (test_type == CRYPTO_FIRST || test_type == SSL_FIRST) {
+        if (!shlib_close(ssllib)) {
             fprintf(stderr, "Failed to close libssl\n");
             goto end;
         }
-        if (test_type != SSL_FIRST)
-            break;
+    }
 
-        if (!shlib_close(cryptolib)) {
-            fprintf(stderr, "Failed to close libcrypto\n");
-            goto end;
-        }
-        break;
+# if defined(OPENSSL_NO_PINSHARED) \
+    && defined(__GLIBC__) \
+    && defined(__GLIBC_PREREQ) \
+    && defined(OPENSSL_SYS_LINUX)
+#  if __GLIBC_PREREQ(2, 3)
+    /*
+     * If we didn't pin the so then we are hopefully on a platform that supports
+     * running atexit() on so unload. If not we might crash. We know this is
+     * true on linux since glibc 2.2.3
+     */
+    if (test_type != NO_ATEXIT && atexit_handler_done != 1) {
+        fprintf(stderr, "atexit() handler did not run\n");
+        goto end;
     }
+#  endif
+# endif
 
     result = 1;
 end: