diff options
author | Spencer Jackson <spencer.jackson@mongodb.com> | 2017-03-31 11:47:59 -0400 |
---|---|---|
committer | Spencer Jackson <spencer.jackson@mongodb.com> | 2017-04-10 13:45:40 -0400 |
commit | 169f0f1178347f367d56b8ef8ec608b11ca71307 (patch) | |
tree | 09812505836e1a6cf0686497bf131fe361195bda /src/mongo/util | |
parent | 54f2f3b1bcbf950d440daf839962630869a1a082 (diff) | |
download | mongo-169f0f1178347f367d56b8ef8ec608b11ca71307.tar.gz |
SERVER-28530 Prevent SSLThreadInfo destruction construction cycle
Diffstat (limited to 'src/mongo/util')
-rw-r--r-- | src/mongo/util/net/ssl_manager.cpp | 84 |
1 files changed, 34 insertions, 50 deletions
diff --git a/src/mongo/util/net/ssl_manager.cpp b/src/mongo/util/net/ssl_manager.cpp index 4b80ad3cfab..96feccc4a7d 100644 --- a/src/mongo/util/net/ssl_manager.cpp +++ b/src/mongo/util/net/ssl_manager.cpp @@ -34,7 +34,7 @@ #include <boost/algorithm/string.hpp> #include <boost/date_time/posix_time/posix_time.hpp> #include <boost/thread/recursive_mutex.hpp> -#include <boost/thread/tss.hpp> +#include <boost/thread/thread.hpp> #include <iostream> #include <sstream> #include <string> @@ -48,6 +48,7 @@ #include "mongo/stdx/memory.h" #include "mongo/transport/session.h" #include "mongo/util/concurrency/mutex.h" +#include "mongo/util/concurrency/threadlocal.h" #include "mongo/util/debug_util.h" #include "mongo/util/exit.h" #include "mongo/util/log.h" @@ -150,31 +151,32 @@ const STACK_OF(X509_EXTENSION) * X509_get0_extensions(const X509* peerCert) { * Multithreaded Support for SSL. * * In order to allow OpenSSL to work in a multithreaded environment, you - * must provide some callbacks for it to use for locking. The following code - * sets up a vector of mutexes and uses thread-local storage to assign an id - * to each thread. + * may need to provide some callbacks for it to use for locking. The following code + * sets up a vector of mutexes and provides a thread unique ID number. * The so-called SSLThreadInfo class encapsulates most of the logic required for * OpenSSL multithreaded support. + * + * OpenSSL before version 1.1.0 requires applications provide a callback which emits a thread + * identifier. This ID is used to store thread specific ERR information. When a thread is + * terminated, it must call ERR_remove_state or ERR_remove_thread_state. These functions may + * themselves invoke the application provided callback. */ - -unsigned long _ssl_id_callback(); -void _ssl_locking_callback(int mode, int type, const char* file, int line); - class SSLThreadInfo { public: - SSLThreadInfo() { - _id = _next.fetchAndAdd(1); - } - - ~SSLThreadInfo() { - ERR_remove_state(0); - } + static unsigned long getID() { + enforceCleanupOnShutdown(); - unsigned long id() const { - return _id; +#ifdef _WIN32 + return GetCurrentThreadId(); +#else + static_assert(sizeof(void*) == sizeof(unsigned long), + "OpenSSL needs the address of a thread-unique object to be castable to" + "unsigned long"); + return reinterpret_cast<unsigned long>(&errno); +#endif } - void lock_callback(int mode, int type, const char* file, int line) { + static void lockingCallback(int mode, int type, const char* file, int line) { if (mode & CRYPTO_LOCK) { _mutex[type]->lock(); } else { @@ -183,38 +185,32 @@ public: } static void init() { + CRYPTO_set_id_callback(&SSLThreadInfo::getID); + CRYPTO_set_locking_callback(&SSLThreadInfo::lockingCallback); + while ((int)_mutex.size() < CRYPTO_num_locks()) { _mutex.emplace_back(stdx::make_unique<stdx::recursive_mutex>()); } } - static SSLThreadInfo* get() { - SSLThreadInfo* me = _thread.get(); - if (!me) { - me = new SSLThreadInfo(); - _thread.reset(me); +private: + SSLThreadInfo() = delete; + + // When called, ensures that this thread will, on termination, call ERR_remove_state. + static void enforceCleanupOnShutdown() { + static MONGO_TRIVIALLY_CONSTRUCTIBLE_THREAD_LOCAL bool firstCall = true; + if (firstCall) { + boost::this_thread::at_thread_exit([] { ERR_remove_state(0); }); + firstCall = false; } - return me; } -private: - unsigned _id; - - static AtomicUInt32 _next; // Note: see SERVER-8734 for why we are using a recursive mutex here. // Once the deadlock fix in OpenSSL is incorporated into most distros of // Linux, this can be changed back to a nonrecursive mutex. static std::vector<std::unique_ptr<stdx::recursive_mutex>> _mutex; - static boost::thread_specific_ptr<SSLThreadInfo> _thread; }; - -unsigned long _ssl_id_callback() { - return SSLThreadInfo::get()->id(); -} - -void _ssl_locking_callback(int mode, int type, const char* file, int line) { - SSLThreadInfo::get()->lock_callback(mode, type, file, line); -} +std::vector<std::unique_ptr<stdx::recursive_mutex>> SSLThreadInfo::_mutex; // We only want to free SSL_CTX objects if they have been populated. OpenSSL seems to perform this // check before freeing them, but because it does not document this, we should protect ourselves. @@ -224,10 +220,6 @@ void _free_ssl_context(SSL_CTX* ctx) { } } -AtomicUInt32 SSLThreadInfo::_next; -std::vector<std::unique_ptr<stdx::recursive_mutex>> SSLThreadInfo::_mutex; -boost::thread_specific_ptr<SSLThreadInfo> SSLThreadInfo::_thread; - //////////////////////////////////////////////////////////////// SimpleMutex sslManagerMtx; @@ -407,12 +399,8 @@ MONGO_INITIALIZER(SetupOpenSSL)(InitializerContext*) { // so that encryption/decryption is backwards compatible OpenSSL_add_all_algorithms(); - // Setup OpenSSL multithreading callbacks - CRYPTO_set_id_callback(_ssl_id_callback); - CRYPTO_set_locking_callback(_ssl_locking_callback); - + // Setup OpenSSL multithreading callbacks and mutexes SSLThreadInfo::init(); - SSLThreadInfo::get(); return Status::OK(); } @@ -458,10 +446,6 @@ std::string getCertificateSubjectName(X509* cert) { SSLConnection::SSLConnection(SSL_CTX* context, Socket* sock, const char* initialBytes, int len) : socket(sock) { - // This just ensures that SSL multithreading support is set up for this thread, - // if it's not already. - SSLThreadInfo::get(); - ssl = SSL_new(context); std::string sslErr = |