aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKoichi Sasada <ko1@atdot.net>2020-12-18 18:19:33 +0900
committerKazuki Yamaguchi <k@rhe.jp>2021-10-16 16:59:23 +0900
commit74d6a346a3490d0752dc0d78de11b27e5beb6786 (patch)
treef765e7e627f22b8ddcd72affcffd133a5c6aaf7f
parentd60ded5afc7414bf9934e3bdbd523e3091a4d05e (diff)
downloadruby-openssl-74d6a346a3490d0752dc0d78de11b27e5beb6786.tar.gz
openssl is ractor-safe
[ This is a backport to the 2.2 branch. ] ossl_bn_ctx is C's global variable and it should be ractor-local to make it ractor-safe. ruby/ruby@b5588edc0a538de840c79e0bbc9d271ba0c5a711 (cherry picked from commit 9e7cf9e930cb986a04e312cb576814254dff13be and commit f2db943e8f19d4fa7bf871b9914dd9b92a5fbe6f)
-rw-r--r--ext/openssl/ossl.c11
-rw-r--r--ext/openssl/ossl_bn.c70
-rw-r--r--ext/openssl/ossl_bn.h3
3 files changed, 72 insertions, 12 deletions
diff --git a/ext/openssl/ossl.c b/ext/openssl/ossl.c
index 2f54b861..ce02efd9 100644
--- a/ext/openssl/ossl.c
+++ b/ext/openssl/ossl.c
@@ -497,8 +497,11 @@ print_mem_leaks(VALUE self)
int ret;
#endif
- BN_CTX_free(ossl_bn_ctx);
- ossl_bn_ctx = NULL;
+#ifndef HAVE_RB_EXT_RACTOR_SAFE
+ // for Ruby 2.x
+ void ossl_bn_ctx_free(void); // ossl_bn.c
+ ossl_bn_ctx_free();
+#endif
#if OPENSSL_VERSION_NUMBER >= 0x10100000
ret = CRYPTO_mem_leaks_fp(stderr);
@@ -1126,6 +1129,10 @@ ossl_crypto_fixed_length_secure_compare(VALUE dummy, VALUE str1, VALUE str2)
void
Init_openssl(void)
{
+#if HAVE_RB_EXT_RACTOR_SAFE
+ rb_ext_ractor_safe(true);
+#endif
+
#undef rb_intern
/*
* Init timezone info
diff --git a/ext/openssl/ossl_bn.c b/ext/openssl/ossl_bn.c
index f3f2e792..bec37299 100644
--- a/ext/openssl/ossl_bn.c
+++ b/ext/openssl/ossl_bn.c
@@ -10,6 +10,10 @@
/* modified by Michal Rokos <m.rokos@sh.cvut.cz> */
#include "ossl.h"
+#if HAVE_RB_EXT_RACTOR_SAFE
+#include <ruby/ractor.h>
+#endif
+
#define NewBN(klass) \
TypedData_Wrap_Struct((klass), &ossl_bn_type, 0)
#define SetBN(obj, bn) do { \
@@ -150,12 +154,58 @@ ossl_bn_value_ptr(volatile VALUE *ptr)
/*
* Private
*/
-/*
- * BN_CTX - is used in more difficult math. ops
- * (Why just 1? Because Ruby itself isn't thread safe,
- * we don't need to care about threads)
- */
-BN_CTX *ossl_bn_ctx;
+
+#if HAVE_RB_EXT_RACTOR_SAFE
+void
+ossl_bn_ctx_free(void *ptr)
+{
+ BN_CTX *ctx = (BN_CTX *)ptr;
+ BN_CTX_free(ctx);
+}
+
+struct rb_ractor_local_storage_type ossl_bn_ctx_key_type = {
+ NULL, // mark
+ ossl_bn_ctx_free,
+};
+
+rb_ractor_local_key_t ossl_bn_ctx_key;
+
+BN_CTX *
+ossl_bn_ctx_get(void)
+{
+ // stored in ractor local storage
+
+ BN_CTX *ctx = rb_ractor_local_storage_ptr(ossl_bn_ctx_key);
+ if (!ctx) {
+ if (!(ctx = BN_CTX_new())) {
+ ossl_raise(rb_eRuntimeError, "Cannot init BN_CTX");
+ }
+ rb_ractor_local_storage_ptr_set(ossl_bn_ctx_key, ctx);
+ }
+ return ctx;
+}
+#else
+// for ruby 2.x
+static BN_CTX *gv_ossl_bn_ctx;
+
+BN_CTX *
+ossl_bn_ctx_get(void)
+{
+ if (gv_ossl_bn_ctx == NULL) {
+ if (!(gv_ossl_bn_ctx = BN_CTX_new())) {
+ ossl_raise(rb_eRuntimeError, "Cannot init BN_CTX");
+ }
+ }
+ return gv_ossl_bn_ctx;
+}
+
+void
+ossl_bn_ctx_free(void)
+{
+ BN_CTX_free(gv_ossl_bn_ctx);
+ gv_ossl_bn_ctx = NULL;
+}
+#endif
static VALUE
ossl_bn_alloc(VALUE klass)
@@ -1102,9 +1152,11 @@ Init_ossl_bn(void)
eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
#endif
- if (!(ossl_bn_ctx = BN_CTX_new())) {
- ossl_raise(rb_eRuntimeError, "Cannot init BN_CTX");
- }
+#ifdef HAVE_RB_EXT_RACTOR_SAFE
+ ossl_bn_ctx_key = rb_ractor_local_storage_ptr_newkey(&ossl_bn_ctx_key_type);
+#else
+ ossl_bn_ctx_get();
+#endif
eBNError = rb_define_class_under(mOSSL, "BNError", eOSSLError);
diff --git a/ext/openssl/ossl_bn.h b/ext/openssl/ossl_bn.h
index a19ba194..1cc041fc 100644
--- a/ext/openssl/ossl_bn.h
+++ b/ext/openssl/ossl_bn.h
@@ -13,7 +13,8 @@
extern VALUE cBN;
extern VALUE eBNError;
-extern BN_CTX *ossl_bn_ctx;
+BN_CTX *ossl_bn_ctx_get(void);
+#define ossl_bn_ctx ossl_bn_ctx_get()
#define GetBNPtr(obj) ossl_bn_value_ptr(&(obj))