diff options
author | William Ahern <william@25thandClement.com> | 2014-01-31 14:41:53 -0800 |
---|---|---|
committer | William Ahern <william@25thandClement.com> | 2014-01-31 14:41:53 -0800 |
commit | 331bc576f5bf394bcc006a8cb7766062dabdfe9c (patch) | |
tree | 519cfa9cce121d1c4182ca249c07a57e40d7c97a | |
parent | 864c08cc3e75442443d3492cf3084b704ef5af70 (diff) | |
download | luaossl-331bc576f5bf394bcc006a8cb7766062dabdfe9c.tar.gz luaossl-331bc576f5bf394bcc006a8cb7766062dabdfe9c.tar.bz2 luaossl-331bc576f5bf394bcc006a8cb7766062dabdfe9c.zip |
add multithread reentrancy protection
-rw-r--r-- | debian/changelog | 8 | ||||
-rw-r--r-- | src/GNUmakefile | 2 | ||||
-rw-r--r-- | src/openssl.c | 159 |
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 @@ | |||
1 | liblua-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 | |||
1 | liblua-openssl (20131209-1) unstable; urgency=low | 9 | liblua-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) | |||
29 | CPPFLAGS_$(d) += -DOPENSSL_NO_EC | 29 | CPPFLAGS_$(d) += -DOPENSSL_NO_EC |
30 | endif | 30 | endif |
31 | 31 | ||
32 | LDFLAGS_$(d) += -lssl -lcrypto | 32 | LDFLAGS_$(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 | |||
3925 | static struct { | ||
3926 | pthread_mutex_t *lock; | ||
3927 | int nlock; | ||
3928 | |||
3929 | void *dlref; | ||
3930 | } mt_state; | ||
3931 | |||
3932 | |||
3933 | static 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 | |||
3951 | static 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 | |||
3974 | static 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 | |||
4023 | leave: | ||
4024 | pthread_mutex_unlock(&mutex); | ||
4025 | |||
4026 | return error; | ||
4027 | } /* mt_init() */ | ||
4028 | |||
4029 | |||
3909 | static void initall(lua_State *L) { | 4030 | static 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); |