Skip to content

Commit

Permalink
ossl.c: make legacy locking callbacks reentrant
Browse files Browse the repository at this point in the history
Although it's not documented explicitly that the locking callbacks must
provide reentrant mutexes, it seems to be required.

Specifically, the session_remove_cb callback function of an SSL_CTX is
called in a critical section for CRYPTO_LOCK_SSL_CTX, which is shared
across the library. This leads, if the callback function calls another
OpenSSL function that will attempt to lock CRYPTO_LOCK_SSL_CTX, to
deadlock. SSL_CTX_free() is one example of such a function.

	http://ci.rvm.jp/results/trunk@P895/64001
  • Loading branch information
rhenium committed Sep 24, 2017
1 parent 7dd6c28 commit b2b2fb8
Showing 1 changed file with 13 additions and 1 deletion.
14 changes: 13 additions & 1 deletion ext/openssl/ossl.c
Original file line number Diff line number Diff line change
Expand Up @@ -486,21 +486,33 @@ print_mem_leaks(VALUE self)
*/
struct CRYPTO_dynlock_value {
rb_nativethread_lock_t lock;
rb_nativethread_id_t owner;
size_t count;
};

static void
ossl_lock_init(struct CRYPTO_dynlock_value *l)
{
rb_nativethread_lock_initialize(&l->lock);
l->count = 0;
}

static void
ossl_lock_unlock(int mode, struct CRYPTO_dynlock_value *l)
{
if (mode & CRYPTO_LOCK) {
/* TODO: rb_nativethread_id_t is not necessarily compared with ==. */
rb_nativethread_id_t tid = rb_nativethread_self();
if (l->count && l->owner == tid) {
l->count++;
return;
}
rb_nativethread_lock_lock(&l->lock);
l->owner = tid;
l->count = 1;
} else {
rb_nativethread_lock_unlock(&l->lock);
if (!--l->count)
rb_nativethread_lock_unlock(&l->lock);
}
}

Expand Down

0 comments on commit b2b2fb8

Please sign in to comment.