diff options
| -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); |
