openssl: lazily load libraries when dynamically loading Defer dlopen until it's needed when dynamically loading OpenSSL libraries.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
diff --git a/src/streams/openssl.c b/src/streams/openssl.c
index 212c002..89c9678 100644
--- a/src/streams/openssl.c
+++ b/src/streams/openssl.c
@@ -102,7 +102,7 @@ static void git_openssl_free(void *mem)
# endif /* !GIT_OPENSSL_LEGACY && !GIT_OPENSSL_DYNAMIC */
#endif /* VALGRIND */
-int git_openssl_stream_global_init(void)
+static int openssl_init(void)
{
long ssl_opts = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3;
const char *ciphers = git_libgit2__ssl_ciphers();
@@ -115,11 +115,6 @@ int git_openssl_stream_global_init(void)
ssl_opts |= SSL_OP_NO_COMPRESSION;
#endif
-#ifdef GIT_OPENSSL_DYNAMIC
- if (git_openssl_stream_dynamic_init() < 0)
- return -1;
-#endif
-
#ifdef VALGRIND
/*
* Swap in our own allocator functions that initialize
@@ -171,6 +166,49 @@ error:
return -1;
}
+/*
+ * When we use dynamic loading, we defer OpenSSL initialization until
+ * it's first used. `openssl_ensure_initialized` will do the work
+ * under a mutex.
+ */
+git_mutex openssl_mutex;
+bool openssl_initialized;
+
+int git_openssl_stream_global_init(void)
+{
+#ifndef GIT_OPENSSL_DYNAMIC
+ return openssl_init();
+#else
+ if (git_mutex_init(&openssl_mutex) != 0)
+ return -1;
+
+ return 0;
+#endif
+}
+
+static int openssl_ensure_initialized(void)
+{
+#ifdef GIT_OPENSSL_DYNAMIC
+ int error = 0;
+
+ if (git_mutex_lock(&openssl_mutex) != 0)
+ return -1;
+
+ if (!openssl_initialized) {
+ if ((error = git_openssl_stream_dynamic_init()) == 0)
+ error = openssl_init();
+
+ openssl_initialized = true;
+ }
+
+ error |= git_mutex_unlock(&openssl_mutex);
+ return error;
+
+#else
+ return 0;
+#endif
+}
+
#if !defined(GIT_OPENSSL_LEGACY) && !defined(GIT_OPENSSL_DYNAMIC)
int git_openssl_set_locking(void)
{
@@ -644,6 +682,9 @@ static int openssl_stream_wrap(
int git_openssl_stream_wrap(git_stream **out, git_stream *in, const char *host)
{
+ if (openssl_ensure_initialized() < 0)
+ return -1;
+
return openssl_stream_wrap(out, in, host, 0);
}
@@ -656,6 +697,9 @@ int git_openssl_stream_new(git_stream **out, const char *host, const char *port)
GIT_ASSERT_ARG(host);
GIT_ASSERT_ARG(port);
+ if (openssl_ensure_initialized() < 0)
+ return -1;
+
if ((error = git_socket_stream_new(&stream, host, port)) < 0)
return error;
@@ -669,6 +713,9 @@ int git_openssl_stream_new(git_stream **out, const char *host, const char *port)
int git_openssl__set_cert_location(const char *file, const char *path)
{
+ if (openssl_ensure_initialized() < 0)
+ return -1;
+
if (SSL_CTX_load_verify_locations(git__ssl_ctx, file, path) == 0) {
char errmsg[256];