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 13:19:39 +0000 (13:19 +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/7647)

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

index 6506203..21d8345 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 da09003..7a2be83 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 049ff21..2fd2235 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 321ac11..6b6bd71 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;
@@ -767,7 +769,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 b1a8172..6934b89 100644 (file)
@@ -104,6 +104,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");
@@ -113,6 +115,7 @@ static void atexit_handler(void)
 
     fprintf(atexit_file, "atexit() run\n");
     fclose(atexit_file);
+    atexit_handler_done++;
 }
 
 static int test_lib(void)
@@ -261,33 +264,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: