diff options
author | Carlos Martín Nieto <cmn@dwim.me> | 2014-06-11 20:52:15 +0200 |
---|---|---|
committer | Carlos Martín Nieto <cmn@dwim.me> | 2014-06-11 20:54:42 +0200 |
commit | 1d3364ac9d2bcd2d194f0afa0d301456d0d4e276 (patch) | |
tree | 74981c82bc5350a2303f6a68a9d162d6001dfec8 | |
parent | 716e20b47eb82ebd94588fe6c950e661b6fe4f15 (diff) | |
download | libgit2-1d3364ac9d2bcd2d194f0afa0d301456d0d4e276.tar.gz |
netops: init OpenSSL once under lock
The OpenSSL init functions are not reentrant, which means that running
multiple fetches in parallel can cause us to crash.
Use a mutex to init OpenSSL, and since we're adding this extra checks,
init it only once.
-rw-r--r-- | src/global.c | 3 | ||||
-rw-r--r-- | src/global.h | 2 | ||||
-rw-r--r-- | src/netops.c | 34 |
3 files changed, 37 insertions, 2 deletions
diff --git a/src/global.c b/src/global.c index 7da31853e..fe410587e 100644 --- a/src/global.c +++ b/src/global.c @@ -16,6 +16,9 @@ git_mutex git__mwindow_mutex; #define MAX_SHUTDOWN_CB 8 +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; diff --git a/src/global.h b/src/global.h index 778250376..245f811e4 100644 --- a/src/global.h +++ b/src/global.h @@ -18,6 +18,8 @@ typedef struct { 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 a0193a022..7bce159ad 100644 --- a/src/netops.c +++ b/src/netops.c @@ -33,6 +33,7 @@ #include "posix.h" #include "buffer.h" #include "http_parser.h" +#include "global.h" #ifdef GIT_WIN32 static void net_set_error(const char *str) @@ -386,12 +387,41 @@ cert_fail_name: return -1; } -static int ssl_setup(gitno_socket *socket, const char *host, int flags) +/** + * The OpenSSL init functions are not reentrant so we need to init + * them under lock. + */ +static int init_ssl(void) { - int ret; + 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_library_init(); SSL_load_error_strings(); + + git_atomic_set(&git__ssl_init, 1); + 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) + return -1; + socket->ssl.ctx = SSL_CTX_new(SSLv23_method()); if (socket->ssl.ctx == NULL) return ssl_set_error(&socket->ssl, 0); |