aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKazuki Yamaguchi <k@rhe.jp>2017-09-20 23:40:25 +0900
committerKazuki Yamaguchi <k@rhe.jp>2017-09-24 12:00:29 +0900
commitb2b2fb868745f4069df959cbb0972be033347f28 (patch)
tree9ed21281183fc1f70f66a0141328b34975620554
parent7dd6c28a335b5a590be89c7e782e53e4112f4bb5 (diff)
downloadruby-openssl-b2b2fb868745f4069df959cbb0972be033347f28.tar.gz
ossl.c: make legacy locking callbacks reentrantky/fix-legacy-locking-callback-relock
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
-rw-r--r--ext/openssl/ossl.c14
1 files changed, 13 insertions, 1 deletions
diff --git a/ext/openssl/ossl.c b/ext/openssl/ossl.c
index 7d3ed6c4..88bb8f21 100644
--- a/ext/openssl/ossl.c
+++ b/ext/openssl/ossl.c
@@ -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);
}
}