Fix clients crashing in TLS code on exit.

If client code initiates an FDB operation to a TLS cluster, and then
immediately exits the main thread, then OpenSSL's atexit handler would
potentially run while the network thread is attempting to do TLS
operations, and thus crash.

This commit removes the OpenSSL atexit hander, and instead relies on a
client intentionally ending the network thread to do TLS cleanup.  If
the client code exits without stopping the network thread, then we'll
never free OpenSSL data structures, which is the safer thing to do.
This commit is contained in:
Alex Miller 2020-04-18 15:48:02 -07:00
parent b5d7780293
commit 94b4f78ea9
3 changed files with 44 additions and 0 deletions

View File

@ -994,6 +994,7 @@ void setupNetwork(uint64_t transportId, bool useMetrics) {
if (!networkOptions.logClientInfo.present()) if (!networkOptions.logClientInfo.present())
networkOptions.logClientInfo = true; networkOptions.logClientInfo = true;
TLS::DisableOpenSSLAtExitHandler();
g_network = newNet2(tlsConfig, false, useMetrics || networkOptions.traceDirectory.present()); g_network = newNet2(tlsConfig, false, useMetrics || networkOptions.traceDirectory.present());
FlowTransport::createInstance(true, transportId); FlowTransport::createInstance(true, transportId);
Net2FileSystem::newFileSystem(); Net2FileSystem::newFileSystem();
@ -1019,6 +1020,7 @@ void stopNetwork() {
g_network->stop(); g_network->stop();
closeTraceFile(); closeTraceFile();
TLS::DestroyOpenSSLGlobalState();
} }
Reference<ProxyInfo> DatabaseContext::getMasterProxies(bool useProvisionalProxies) { Reference<ProxyInfo> DatabaseContext::getMasterProxies(bool useProvisionalProxies) {

View File

@ -25,6 +25,32 @@
// To force typeinfo to only be emitted once. // To force typeinfo to only be emitted once.
TLSPolicy::~TLSPolicy() {} TLSPolicy::~TLSPolicy() {}
namespace TLS {
void DisableOpenSSLAtExitHandler() {
#ifdef TLS_DISABLED
return;
#else
static bool once = false;
if (!once) {
once = true;
int success = OPENSSL_init_crypto(OPENSSL_INIT_NO_ATEXIT, nullptr);
if (!success) {
throw tls_error();
}
}
#endif
}
void DestroyOpenSSLGlobalState() {
#ifdef TLS_DISABLED
return;
#else
OPENSSL_cleanup();
#endif
}
} // namespace TLS
#ifdef TLS_DISABLED #ifdef TLS_DISABLED
void LoadedTLSConfig::print(FILE *fp) { void LoadedTLSConfig::print(FILE *fp) {

View File

@ -36,6 +36,22 @@
#include "flow/Knobs.h" #include "flow/Knobs.h"
#include "flow/flow.h" #include "flow/flow.h"
namespace TLS {
// Force OpenSSL to not register an atexit handler to clean up global state before process exit.
// If you call this, you must also call DestroyOpenSSLGlobalState() before the program exits.
// Calls OPENSSL_init_crypto with OPENSSL_INIT_NO_ATEXIT.
// Must be called before any other OpenSSL function.
void DisableOpenSSLAtExitHandler();
// Frees all global state maintained by OpenSSL.
// Calls OPENSSL_cleanup.
// Must be called before program exit if using DisableOpenSSLAtExitHandler.
// No OpenSSL code may be run after calling this function.
void DestroyOpenSSLGlobalState();
} // namespace TLS
#ifndef TLS_DISABLED #ifndef TLS_DISABLED
#include <openssl/x509.h> #include <openssl/x509.h>