socket: call init_openssl_mt() in init() and add cleanup

init_openssl_mt() wasn't explicitly invoked and was run implicitly before
dlopen() returned as it was tagged as __attribute__ ((constructor)). This
function used to call GF_CALLOC() which wasn't available or initialized
when socket.so is dlopen()ed by an external program. The program used to
crash with SIGSEGV as follows:

0x00007ffff5efe1ad in __gf_calloc (nmemb=41, size=40, type=158, typestr=0x7ffff63eb3d6 "gf_sock_mt_lock_array")
at mem-pool.c:109
0x00007ffff63e6acf in init_openssl_mt () at socket.c:4016
0x00007ffff7de90da in call_init.part () from /lib64/ld-linux-x86-64.so.2
0x00007ffff7de91eb in _dl_init () from /lib64/ld-linux-x86-64.so.2
0x00007ffff7dedde1 in dl_open_worker () from /lib64/ld-linux-x86-64.so.2
0x00007ffff7de8f84 in _dl_catch_error () from /lib64/ld-linux-x86-64.so.2
0x00007ffff7ded339 in _dl_open () from /lib64/ld-linux-x86-64.so.2

This change moves call to init_openssl_mt() from being a constructor function
to the init() function and introduces fini_openssl_mt() which cleans up
resources (called in destructor).

BUG: 1193929
Change-Id: Iab690897ec34e24c33f6b43f8d8d9f8fd75ac607
Signed-off-by: Prashanth Pai <ppai@redhat.com>
Reviewed-on: https://review.gluster.org/17753
Smoke: Gluster Build System <jenkins@build.gluster.org>
CentOS-regression: Gluster Build System <jenkins@build.gluster.org>
Reviewed-by: Amar Tumballi <amarts@redhat.com>
Reviewed-by: Jeff Darcy <jeff@pl.atyp.us>
This commit is contained in:
Prashanth Pai 2017-07-12 12:59:35 +05:30 committed by Jeff Darcy
parent 4c410a46ef
commit 58a15ae04e

View File

@ -3962,15 +3962,7 @@ out:
}
/*
* Unlike the stuff in init, this only needs to be called once GLOBALLY no
* matter how many translators/sockets we end up with. Conveniently,
* __attribute__(constructor) provides exactly those semantics in a pretty
* portable fashion.
*/
static pthread_mutex_t *lock_array = NULL;
static gf_boolean_t constructor_ok = _gf_false;
static void
locking_func (int mode, int type, const char *file, int line)
@ -4007,29 +3999,61 @@ legacy_threadid_func (void)
}
#endif
static void __attribute__((constructor))
static void
init_openssl_mt (void)
{
int num_locks = CRYPTO_num_locks();
int i;
if (lock_array) {
/* this only needs to be initialized once GLOBALLY no
matter how many translators/sockets we end up with. */
return;
}
SSL_library_init();
SSL_load_error_strings();
lock_array = GF_CALLOC (num_locks, sizeof(pthread_mutex_t),
gf_sock_mt_lock_array);
if (lock_array) {
for (i = 0; i < num_locks; ++i) {
pthread_mutex_init (&lock_array[i], NULL);
}
CRYPTO_set_locking_callback (locking_func);
#if HAVE_CRYPTO_THREADID
CRYPTO_THREADID_set_callback (threadid_func);
#else /* older openssl */
CRYPTO_set_id_callback (legacy_threadid_func);
#endif
constructor_ok = _gf_true;
CRYPTO_set_locking_callback (locking_func);
}
SSL_library_init();
SSL_load_error_strings();
}
static void __attribute__((destructor))
fini_openssl_mt (void)
{
int i;
if (!lock_array) {
return;
}
CRYPTO_set_locking_callback(NULL);
#if HAVE_CRYPTO_THREADID
CRYPTO_THREADID_set_callback (NULL);
#else /* older openssl */
CRYPTO_set_id_callback (NULL);
#endif
for (i = 0; i < CRYPTO_num_locks(); ++i) {
pthread_mutex_destroy (&lock_array[i]);
}
GF_FREE (lock_array);
lock_array = NULL;
ERR_free_strings();
}
static void
@ -4319,18 +4343,6 @@ socket_init (rpc_transport_t *this)
if (priv->ssl_enabled || priv->mgmt_ssl) {
BIO *bio = NULL;
/*
* The right time to check this is after all of our relevant
* fields have been set, but before we start issuing OpenSSL
* calls for the current translator. In other words, now.
*/
if (!constructor_ok) {
gf_log (this->name, GF_LOG_ERROR,
"can't initialize TLS socket (%s)",
"static constructor failed");
goto err;
}
#if HAVE_TLSV1_2_METHOD
priv->ssl_meth = (SSL_METHOD *)TLSv1_2_method();
#else
@ -4548,6 +4560,8 @@ init (rpc_transport_t *this)
{
int ret = -1;
init_openssl_mt();
ret = socket_init (this);
if (ret == -1) {