From 081e76bac26e1ed6adafb402d15b30c622866d61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Thu, 12 Jun 2014 16:20:52 +0200 Subject: [PATCH] ssl: init everything all the time Bring together all of the OpenSSL initialization to git_threads_init() so it's together and doesn't need locks. Moving it here also gives us libssh2 thread safety (when built against openssl). --- src/global.c | 53 +++++++++++++++++++++++++++++---- src/global.h | 2 -- src/netops.c | 83 ++-------------------------------------------------- 3 files changed, 51 insertions(+), 87 deletions(-) diff --git a/src/global.c b/src/global.c index 41428ec42..b144b050a 100644 --- a/src/global.c +++ b/src/global.c @@ -19,11 +19,9 @@ git_mutex git__mwindow_mutex; #ifdef GIT_SSL # include SSL_CTX *git__ssl_ctx; +static git_mutex *openssl_locks; #endif -git_mutex git__ssl_mutex; -git_atomic git__ssl_init; - static git_global_shutdown_fn git__shutdown_callbacks[MAX_SHUTDOWN_CB]; static git_atomic git__n_shutdown_callbacks; static git_atomic git__n_inits; @@ -47,12 +45,59 @@ static void git__shutdown(void) } +#if defined(GIT_THREADS) && defined(GIT_SSL) +void openssl_locking_function(int mode, int n, const char *file, int line) +{ + int lock; + + GIT_UNUSED(file); + GIT_UNUSED(line); + + lock = mode & CRYPTO_LOCK; + + if (lock) { + git_mutex_lock(&openssl_locks[n]); + } else { + git_mutex_unlock(&openssl_locks[n]); + } +} +#endif + + static void init_ssl(void) { #ifdef GIT_SSL SSL_load_error_strings(); OpenSSL_add_ssl_algorithms(); git__ssl_ctx = SSL_CTX_new(SSLv23_method()); + SSL_CTX_set_mode(git__ssl_ctx, SSL_MODE_AUTO_RETRY); + SSL_CTX_set_verify(git__ssl_ctx, SSL_VERIFY_NONE, NULL); + if (!SSL_CTX_set_default_verify_paths(git__ssl_ctx)) { + SSL_CTX_free(git__ssl_ctx); + git__ssl_ctx = NULL; + } + +# ifdef GIT_THREADS + { + int num_locks, i; + + num_locks = CRYPTO_num_locks(); + openssl_locks = git__calloc(num_locks, sizeof(git_mutex)); + if (openssl_locks == NULL) { + SSL_CTX_free(git__ssl_ctx); + git__ssl_ctx = NULL; + } + + for (i = 0; i < num_locks; i++) { + if (git_mutex_init(&openssl_locks[i]) != 0) { + SSL_CTX_free(git__ssl_ctx); + git__ssl_ctx = NULL; + } + } + + CRYPTO_set_locking_callback(openssl_locking_function); + } +# endif #endif } @@ -183,8 +228,6 @@ static void init_once(void) { if ((init_error = git_mutex_init(&git__mwindow_mutex)) != 0) return; - if ((init_error = git_mutex_init(&git__ssl_mutex)) != 0) - return; pthread_key_create(&_tls_key, &cb__free_status); diff --git a/src/global.h b/src/global.h index 8904e2de5..745df3e4a 100644 --- a/src/global.h +++ b/src/global.h @@ -23,8 +23,6 @@ extern SSL_CTX *git__ssl_ctx; git_global_st *git__global_state(void); extern git_mutex git__mwindow_mutex; -extern git_mutex git__ssl_mutex; -extern git_atomic git__ssl_init; #define GIT_GLOBAL (git__global_state()) diff --git a/src/netops.c b/src/netops.c index 54804d418..965e4775d 100644 --- a/src/netops.c +++ b/src/netops.c @@ -35,11 +35,6 @@ #include "http_parser.h" #include "global.h" -#if defined(GIT_SSL) && defined(GIT_THREADS) -/* OpenSSL wants us to keep an array of locks */ -static git_mutex *openssl_locks; -#endif - #ifdef GIT_WIN32 static void net_set_error(const char *str) { @@ -391,86 +386,14 @@ cert_fail_name: return -1; } -#ifdef GIT_THREADS -void openssl_locking_function(int mode, int n, const char *file, int line) -{ - int lock; - - GIT_UNUSED(file); - GIT_UNUSED(line); - - lock = mode & CRYPTO_LOCK; - - if (lock) { - git_mutex_lock(&openssl_locks[n]); - } else { - git_mutex_unlock(&openssl_locks[n]); - } -} -#endif - -/** - * The OpenSSL init functions are not reentrant so we need to init - * them under lock. - */ -static int init_ssl(void) -{ - if (git__ssl_init.val) - return 0; - - if (git_mutex_lock(&git__ssl_mutex) < 0) { - giterr_set(GITERR_OS, "failed to acquire ssl init lock"); - return -1; - } - - /* if we had to wait for the lock, someone else did it, we can return */ - if (git__ssl_init.val) - return 0; - - SSL_CTX_set_mode(git__ssl_ctx, SSL_MODE_AUTO_RETRY); - SSL_CTX_set_verify(git__ssl_ctx, SSL_VERIFY_NONE, NULL); - if (!SSL_CTX_set_default_verify_paths(git__ssl_ctx)) { - unsigned long err = ERR_get_error(); - giterr_set(GITERR_SSL, "failed to set verify paths: %s\n", ERR_error_string(err, NULL)); - return -1; - } - -#ifdef GIT_THREADS - { - int num_locks, i; - - num_locks = CRYPTO_num_locks(); - openssl_locks = git__calloc(num_locks, sizeof(git_mutex)); - if (openssl_locks == NULL) { - git_mutex_unlock(&git__ssl_mutex); - return -1; - } - GITERR_CHECK_ALLOC(openssl_locks); - - for (i = 0; i < num_locks; i++) { - if (git_mutex_init(&openssl_locks[i]) != 0) { - git_mutex_unlock(&git__ssl_mutex); - giterr_set(GITERR_SSL, "failed to init lock %d", i); - return -1; - } - } - } - - CRYPTO_set_locking_callback(openssl_locking_function); -#endif - - git_atomic_inc(&git__ssl_init); - git_mutex_unlock(&git__ssl_mutex); - - return 0; -} - static int ssl_setup(gitno_socket *socket, const char *host, int flags) { int ret; - if (init_ssl() < 0) + if (git__ssl_ctx == NULL) { + giterr_set(GITERR_NET, "OpenSSL initialization failed"); return -1; + } socket->ssl.ssl = SSL_new(git__ssl_ctx); if (socket->ssl.ssl == NULL)