Skip to content

Commit b2b2fb8

Browse files
committed
ossl.c: make legacy locking callbacks reentrant
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
1 parent 7dd6c28 commit b2b2fb8

File tree

1 file changed

+13
-1
lines changed

1 file changed

+13
-1
lines changed

ext/openssl/ossl.c

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -486,21 +486,33 @@ print_mem_leaks(VALUE self)
486486
*/
487487
struct CRYPTO_dynlock_value {
488488
rb_nativethread_lock_t lock;
489+
rb_nativethread_id_t owner;
490+
size_t count;
489491
};
490492

491493
static void
492494
ossl_lock_init(struct CRYPTO_dynlock_value *l)
493495
{
494496
rb_nativethread_lock_initialize(&l->lock);
497+
l->count = 0;
495498
}
496499

497500
static void
498501
ossl_lock_unlock(int mode, struct CRYPTO_dynlock_value *l)
499502
{
500503
if (mode & CRYPTO_LOCK) {
504+
/* TODO: rb_nativethread_id_t is not necessarily compared with ==. */
505+
rb_nativethread_id_t tid = rb_nativethread_self();
506+
if (l->count && l->owner == tid) {
507+
l->count++;
508+
return;
509+
}
501510
rb_nativethread_lock_lock(&l->lock);
511+
l->owner = tid;
512+
l->count = 1;
502513
} else {
503-
rb_nativethread_lock_unlock(&l->lock);
514+
if (!--l->count)
515+
rb_nativethread_lock_unlock(&l->lock);
504516
}
505517
}
506518

0 commit comments

Comments
 (0)