Skip to content

Commit 2d2e70f

Browse files
committed
openssl: fix thread-safety on non-glibc POSIX systems
While the OpenSSL library provides all means to work safely in a multi-threaded application, we fail to do so correctly. Quoting from crypto_lock(3): OpenSSL can safely be used in multi-threaded applications provided that at least two callback functions are set, locking_function and threadid_func. We do in fact provide the means to set up the locking function via `git_openssl_set_locking()`, where we initialize a set of locks by using the POSIX threads API and set the correct callback function to lock and unlock them. But what we do not do is setting the `threadid_func` callback. This function is being used to correctly locate thread-local data of the OpenSSL library and should thus return per-thread identifiers. Digging deeper into OpenSSL's documentation, the library does provide a fallback in case that locking function is not provided by the user. On Windows and BeOS we should be safe, as it simply "uses the system's default thread identifying API". On other platforms though OpenSSL will fall back to using the address of `errno`, assuming it is thread-local. While this assumption holds true for glibc-based systems, POSIX in fact does not specify whether it is thread-local or not. Quoting from errno(3p): It is unspecified whether errno is a macro or an identifier declared with external linkage. And in fact, with musl there is at least one libc implementation which simply declares `errno` as a simple `int` without being thread-local. On those systems, the fallback threadid function of OpenSSL will not be thread-safe. Fix this by setting up our own callback for this setting. As users of libgit2 may want to set it themselves, we obviously cannot always set that function on initialization. But as we already set up primitives for threading in `git_openssl_set_locking()`, this function becomes the obvious choice where to implement the additional setup.
1 parent a9b6667 commit 2d2e70f

File tree

1 file changed

+9
-0
lines changed

1 file changed

+9
-0
lines changed

src/streams/openssl.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,11 +150,20 @@ int git_openssl_stream_global_init(void)
150150
return 0;
151151
}
152152

153+
#if defined(GIT_THREADS)
154+
static void threadid_cb(CRYPTO_THREADID *threadid)
155+
{
156+
CRYPTO_THREADID_set_numeric(threadid, git_thread_currentid());
157+
}
158+
#endif
159+
153160
int git_openssl_set_locking(void)
154161
{
155162
#if defined(GIT_THREADS) && OPENSSL_VERSION_NUMBER < 0x10100000L
156163
int num_locks, i;
157164

165+
CRYPTO_THREADID_set_callback(threadid_cb);
166+
158167
num_locks = CRYPTO_num_locks();
159168
openssl_locks = git__calloc(num_locks, sizeof(git_mutex));
160169
GITERR_CHECK_ALLOC(openssl_locks);

0 commit comments

Comments
 (0)