]> git.proxmox.com Git - mirror_kronosnet.git/commitdiff
[openssl] fix openssl1.0 crash by implementing documented locking callbacks
authorFabio M. Di Nitto <fdinitto@redhat.com>
Tue, 2 Jan 2018 16:23:02 +0000 (17:23 +0100)
committerFabio M. Di Nitto <fdinitto@redhat.com>
Tue, 2 Jan 2018 16:23:02 +0000 (17:23 +0100)
openssl < 1.1.0 do not support natively multithread applications and need
some extra help from the application itself to provide locking callbacks.

https://www.openssl.org/docs/man1.0.2/crypto/threads.html
https://www.openssl.org/blog/blog/2017/02/21/threads/

to test this fix is necessary to use knet_bench or corosync with openssl
and lots of heavy load (perf benchmark) workload. Sooner or later
the application will crash with some random tracebacks.

after this patch, the crash cannot be reproduced anymore.

tested using 9 nodes x2 active/active links all running corosync + cpghum

Signed-off-by: Fabio M. Di Nitto <fdinitto@redhat.com>
libknet/crypto_openssl.c

index 810dd87ce8afa53185dcfa3c9af09ec7815771d8..f584c910c5c0eb5a2a3a67da78bcd53d8d48e52e 100644 (file)
@@ -395,12 +395,96 @@ static int opensslcrypto_authenticate_and_decrypt (
        return 0;
 }
 
+#ifdef BUILDCRYPTOOPENSSL10
+static pthread_mutex_t *openssl_internal_lock;
+static long *openssl_internal_lock_count;
+
+static void openssl_internal_locking_callback(int mode, int type, char *file, int line)
+{
+       if (mode & CRYPTO_LOCK) {
+               pthread_mutex_lock(&(openssl_internal_lock[type]));
+               openssl_internal_lock_count[type]++;
+       } else {
+               pthread_mutex_unlock(&(openssl_internal_lock[type]));
+       }
+}
+
+static unsigned long openssl_internal_thread_id(void)
+{
+       return (unsigned long)pthread_self();
+}
+
+static void openssl_internal_lock_cleanup(void)
+{
+       int i;
+
+       CRYPTO_set_locking_callback(NULL);
+       CRYPTO_set_id_callback(NULL);
+
+       for (i = 0; i < CRYPTO_num_locks(); i++) {
+               pthread_mutex_destroy(&(openssl_internal_lock[i]));
+       }
+
+       if (openssl_internal_lock_count) {
+               free(openssl_internal_lock_count);
+       }
+
+       if (openssl_internal_lock) {
+               free(openssl_internal_lock);
+       }
+
+       return;
+}
+
+static int openssl_internal_lock_setup(void)
+{
+       int savederrno = 0, err = 0;
+       int i;
+
+       openssl_internal_lock = malloc(CRYPTO_num_locks() * sizeof(pthread_mutex_t));
+       if (!openssl_internal_lock) {
+               savederrno = errno;
+               err = -1;
+               goto out;
+       }
+
+       openssl_internal_lock_count = malloc(CRYPTO_num_locks() * sizeof(long));
+       if (!openssl_internal_lock_count) {
+               savederrno = errno;
+               err = -1;
+               goto out;
+       }
+
+       for (i = 0; i < CRYPTO_num_locks(); i++) {
+               openssl_internal_lock_count[i] = 0;
+               savederrno = pthread_mutex_init(&(openssl_internal_lock[i]), NULL);
+               if (savederrno) {
+                       err = -1;
+                       goto out;
+               }
+       }
+
+       CRYPTO_set_id_callback((unsigned long (*)(void))openssl_internal_thread_id);
+       CRYPTO_set_locking_callback((void *)&openssl_internal_locking_callback);
+
+out:
+       if (err) {
+               openssl_internal_lock_cleanup();
+       }
+       errno = savederrno;
+       return err;
+}
+#endif
+
 static void opensslcrypto_fini(
        knet_handle_t knet_h)
 {
        struct opensslcrypto_instance *opensslcrypto_instance = knet_h->crypto_instance->model_instance;
 
        if (opensslcrypto_instance) {
+#ifdef BUILDCRYPTOOPENSSL10
+               openssl_internal_lock_cleanup();
+#endif
                if (opensslcrypto_instance->private_key) {
                        free(opensslcrypto_instance->private_key);
                        opensslcrypto_instance->private_key = NULL;
@@ -441,6 +525,14 @@ static int opensslcrypto_init(
                openssl_is_init = 1;
        }
 
+#ifdef BUILDCRYPTOOPENSSL10
+       if (openssl_internal_lock_setup() < 0) {
+               log_err(knet_h, KNET_SUB_OPENSSLCRYPTO, "Unable to init openssl");
+               errno = EAGAIN;
+               return -1;
+       }
+#endif
+
        knet_h->crypto_instance->model_instance = malloc(sizeof(struct opensslcrypto_instance));
        if (!knet_h->crypto_instance->model_instance) {
                log_err(knet_h, KNET_SUB_OPENSSLCRYPTO, "Unable to allocate memory for openssl model instance");