summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWilliam Ahern <william@25thandClement.com>2014-01-31 14:41:53 -0800
committerWilliam Ahern <william@25thandClement.com>2014-01-31 14:41:53 -0800
commit331bc576f5bf394bcc006a8cb7766062dabdfe9c (patch)
tree519cfa9cce121d1c4182ca249c07a57e40d7c97a
parent864c08cc3e75442443d3492cf3084b704ef5af70 (diff)
downloadluaossl-331bc576f5bf394bcc006a8cb7766062dabdfe9c.tar.gz
luaossl-331bc576f5bf394bcc006a8cb7766062dabdfe9c.tar.bz2
luaossl-331bc576f5bf394bcc006a8cb7766062dabdfe9c.zip
add multithread reentrancy protection
-rw-r--r--debian/changelog8
-rw-r--r--src/GNUmakefile2
-rw-r--r--src/openssl.c159
3 files changed, 165 insertions, 4 deletions
diff --git a/debian/changelog b/debian/changelog
index 4d5e440..8ace2cc 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,11 @@
1liblua-openssl (20141231-0) unstable; urgency=low
2
3 * Add multi-threaded re-entrancy protection, including explicitly
4 synchronizing OpenSSL initialization because OpenSSL doesn't appear to
5 use its own locking callbacks from initialization routines.
6
7 -- William Ahern <william@25thandClement.com> Fri, 31 Jan 2014 14:27:30 -0800
8
1liblua-openssl (20131209-1) unstable; urgency=low 9liblua-openssl (20131209-1) unstable; urgency=low
2 10
3 * Initial release after splitting from cqueues project. 11 * Initial release after splitting from cqueues project.
diff --git a/src/GNUmakefile b/src/GNUmakefile
index fcf79a6..a0c2f00 100644
--- a/src/GNUmakefile
+++ b/src/GNUmakefile
@@ -29,7 +29,7 @@ ifeq ($(CC_$(d)), sunpro)
29CPPFLAGS_$(d) += -DOPENSSL_NO_EC 29CPPFLAGS_$(d) += -DOPENSSL_NO_EC
30endif 30endif
31 31
32LDFLAGS_$(d) += -lssl -lcrypto 32LDFLAGS_$(d) += -lssl -lcrypto -lpthread -ldl
33 33
34# 34#
35# C O M P I L A T I O N R U L E S 35# C O M P I L A T I O N R U L E S
diff --git a/src/openssl.c b/src/openssl.c
index c8af43d..64bbba4 100644
--- a/src/openssl.c
+++ b/src/openssl.c
@@ -1,7 +1,7 @@
1/* ========================================================================== 1/* ==========================================================================
2 * openssl.c - Lua OpenSSL 2 * openssl.c - Lua OpenSSL
3 * -------------------------------------------------------------------------- 3 * --------------------------------------------------------------------------
4 * Copyright (c) 2012 William Ahern 4 * Copyright (c) 2012-2014 William Ahern
5 * 5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a 6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the 7 * copy of this software and associated documentation files (the
@@ -39,6 +39,10 @@
39#include <netinet/in.h> /* struct in_addr struct in6_addr */ 39#include <netinet/in.h> /* struct in_addr struct in6_addr */
40#include <arpa/inet.h> /* inet_pton(3) */ 40#include <arpa/inet.h> /* inet_pton(3) */
41 41
42#include <pthread.h> /* pthread_mutex_init(3) pthread_mutex_lock(3) pthread_mutex_unlock(3) */
43
44#include <dlfcn.h> /* dladdr(3) dlopen(3) */
45
42#include <openssl/err.h> 46#include <openssl/err.h>
43#include <openssl/bn.h> 47#include <openssl/bn.h>
44#include <openssl/asn1.h> 48#include <openssl/asn1.h>
@@ -74,6 +78,13 @@
74#define CIPHER_CLASS "EVP_CIPHER_CTX" /* not a pointer */ 78#define CIPHER_CLASS "EVP_CIPHER_CTX" /* not a pointer */
75 79
76 80
81#if __GNUC__
82#define NOTUSED __attribute__((unused))
83#else
84#define NOTUSED
85#endif
86
87
77#define countof(a) (sizeof (a) / sizeof *(a)) 88#define countof(a) (sizeof (a) / sizeof *(a))
78#define endof(a) (&(a)[countof(a)]) 89#define endof(a) (&(a)[countof(a)])
79 90
@@ -3906,9 +3917,151 @@ int luaopen__openssl_rand(lua_State *L) {
3906} /* luaopen__openssl_rand() */ 3917} /* luaopen__openssl_rand() */
3907 3918
3908 3919
3920/*
3921 * Multithread Reentrancy Protection
3922 *
3923 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3924
3925static struct {
3926 pthread_mutex_t *lock;
3927 int nlock;
3928
3929 void *dlref;
3930} mt_state;
3931
3932
3933static void mt_lock(int mode, int type, const char *file NOTUSED, int line NOTUSED) {
3934 if (mode & CRYPTO_LOCK)
3935 pthread_mutex_lock(&mt_state.lock[type]);
3936 else
3937 pthread_mutex_unlock(&mt_state.lock[type]);
3938} /* mt_lock() */
3939
3940
3941/*
3942 * Sources include Google and especially the Wine Project. See get_unix_tid
3943 * at http://source.winehq.org/git/wine.git/?a=blob;f=dlls/ntdll/server.c.
3944 */
3945#if __FreeBSD__
3946#include <sys/thr.h> /* thr_self(2) */
3947#elif __NetBSD__
3948#include <lwp.h> /* _lwp_self(2) */
3949#endif
3950
3951static unsigned long mt_gettid(void) {
3952#if __APPLE__
3953 return pthread_mach_thread_np(pthread_self());
3954#elif __DragonFly__
3955 return lwp_gettid();
3956#elif __FreeBSD__
3957 long id;
3958
3959 thr_self(&id);
3960
3961 return id;
3962#elif __NetBSD__
3963 return _lwp_self();
3964#else
3965 /*
3966 * pthread_t is an integer on Solaris and Linux, and a unique pointer
3967 * on OpenBSD.
3968 */
3969 return (unsigned long)pthread_self();
3970#endif
3971} /* mt_gettid() */
3972
3973
3974static int mt_init(void) {
3975 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
3976 int bound = 0, error = 0;
3977
3978 pthread_mutex_lock(&mutex);
3979
3980 if (!CRYPTO_get_locking_callback()) {
3981 if (!mt_state.lock) {
3982 int i;
3983
3984 mt_state.nlock = CRYPTO_num_locks();
3985
3986 if (!(mt_state.lock = malloc(mt_state.nlock * sizeof *mt_state.lock))) {
3987 error = errno;
3988 goto leave;
3989 }
3990
3991 for (i = 0; i < mt_state.nlock; i++) {
3992 pthread_mutex_init(&mt_state.lock[i], NULL);
3993 }
3994 }
3995
3996 CRYPTO_set_locking_callback(&mt_lock);
3997 bound = 1;
3998 }
3999
4000 if (!CRYPTO_get_id_callback()) {
4001 CRYPTO_set_id_callback(&mt_gettid);
4002 bound = 1;
4003 }
4004
4005 /*
4006 * Prevent loader from unlinking us if we've registered a callback
4007 * with OpenSSL by taking another reference to ourselves.
4008 */
4009 if (bound && !mt_state.dlref) {
4010 Dl_info info;
4011
4012 if (!dladdr(&luaopen__openssl_rand, &info)) {
4013 error = -1;
4014 goto leave;
4015 }
4016
4017 if (!(mt_state.dlref = dlopen(info.dli_fname, RTLD_NOW|RTLD_LOCAL))) {
4018 error = -1;
4019 goto leave;
4020 }
4021 }
4022
4023leave:
4024 pthread_mutex_unlock(&mutex);
4025
4026 return error;
4027} /* mt_init() */
4028
4029
3909static void initall(lua_State *L) { 4030static void initall(lua_State *L) {
3910 ERR_load_crypto_strings(); 4031 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
3911 OpenSSL_add_all_algorithms(); 4032 static int initssl;
4033 int error;
4034
4035 if ((error = mt_init())) {
4036 if (error == -1) {
4037 luaL_error(L, "openssl.init: %s", dlerror());
4038 } else {
4039 char why[256];
4040
4041 if (0 != strerror_r(error, why, sizeof why) || *why == '\0')
4042 luaL_error(L, "openssl.init: Unknown error: %d", error);
4043
4044 luaL_error(L, "openssl.init: %s", why);
4045 }
4046 }
4047
4048 pthread_mutex_lock(&mutex);
4049
4050 if (!initssl) {
4051 initssl = 1;
4052
4053 SSL_load_error_strings();
4054 SSL_library_init();
4055 OpenSSL_add_all_algorithms();
4056
4057 /*
4058 * TODO: Figure out a way to detect whether OpenSSL has
4059 * already been configured.
4060 */
4061 OPENSSL_config(NULL);
4062 }
4063
4064 pthread_mutex_unlock(&mutex);
3912 4065
3913 addclass(L, BIGNUM_CLASS, bn_methods, bn_metatable); 4066 addclass(L, BIGNUM_CLASS, bn_methods, bn_metatable);
3914 addclass(L, PUBKEY_CLASS, pk_methods, pk_metatable); 4067 addclass(L, PUBKEY_CLASS, pk_methods, pk_metatable);