Skip to content

Commit 16e40a8

Browse files
committed
Integrate util/system's CInit into RNGState
This guarantees that OpenSSL is initialized properly whenever randomness is used, even when that randomness is invoked from global constructors. Note that this patch uses Mutex directly, rather than CCriticalSection. This is because the lock-detection code is not necessarily initialized during global constructors.
1 parent 2ccc3d3 commit 16e40a8

File tree

2 files changed

+43
-51
lines changed

2 files changed

+43
-51
lines changed

src/random.cpp

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747

4848
#include <openssl/err.h>
4949
#include <openssl/rand.h>
50+
#include <openssl/conf.h>
5051

5152
[[noreturn]] static void RandFailure()
5253
{
@@ -294,15 +295,46 @@ void GetRandBytes(unsigned char* buf, int num)
294295
}
295296
}
296297

298+
void LockingCallbackOpenSSL(int mode, int i, const char* file, int line);
299+
297300
namespace {
301+
298302
struct RNGState {
299303
Mutex m_mutex;
300304
unsigned char m_state[32] GUARDED_BY(m_mutex) = {0};
301305
uint64_t m_counter GUARDED_BY(m_mutex) = 0;
306+
std::unique_ptr<Mutex[]> m_mutex_openssl;
302307

303308
RNGState()
304309
{
305310
InitHardwareRand();
311+
312+
// Init OpenSSL library multithreading support
313+
m_mutex_openssl.reset(new Mutex[CRYPTO_num_locks()]);
314+
CRYPTO_set_locking_callback(LockingCallbackOpenSSL);
315+
316+
// OpenSSL can optionally load a config file which lists optional loadable modules and engines.
317+
// We don't use them so we don't require the config. However some of our libs may call functions
318+
// which attempt to load the config file, possibly resulting in an exit() or crash if it is missing
319+
// or corrupt. Explicitly tell OpenSSL not to try to load the file. The result for our libs will be
320+
// that the config appears to have been loaded and there are no modules/engines available.
321+
OPENSSL_no_config();
322+
323+
#ifdef WIN32
324+
// Seed OpenSSL PRNG with current contents of the screen
325+
RAND_screen();
326+
#endif
327+
328+
// Seed OpenSSL PRNG with performance counter
329+
RandAddSeed();
330+
}
331+
332+
~RNGState()
333+
{
334+
// Securely erase the memory used by the OpenSSL PRNG
335+
RAND_cleanup();
336+
// Shutdown OpenSSL library multithreading support
337+
CRYPTO_set_locking_callback(nullptr);
306338
}
307339

308340
/** Extract up to 32 bytes of entropy from the RNG state, mixing in new entropy from hasher. */
@@ -343,6 +375,17 @@ RNGState& GetRNGState()
343375
}
344376
}
345377

378+
void LockingCallbackOpenSSL(int mode, int i, const char* file, int line) NO_THREAD_SAFETY_ANALYSIS
379+
{
380+
RNGState& rng = GetRNGState();
381+
382+
if (mode & CRYPTO_LOCK) {
383+
rng.m_mutex_openssl[i].lock();
384+
} else {
385+
rng.m_mutex_openssl[i].unlock();
386+
}
387+
}
388+
346389
static void AddDataToRng(void* data, size_t len, RNGState& rng);
347390

348391
void RandAddSeedSleep()

src/util/system.cpp

Lines changed: 0 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -73,9 +73,6 @@
7373
#include <malloc.h>
7474
#endif
7575

76-
#include <openssl/crypto.h>
77-
#include <openssl/rand.h>
78-
#include <openssl/conf.h>
7976
#include <thread>
8077

8178
// Application startup time (used for uptime calculation)
@@ -86,54 +83,6 @@ const char * const BITCOIN_PID_FILENAME = "bitcoind.pid";
8683

8784
ArgsManager gArgs;
8885

89-
/** Init OpenSSL library multithreading support */
90-
static std::unique_ptr<CCriticalSection[]> ppmutexOpenSSL;
91-
void locking_callback(int mode, int i, const char* file, int line) NO_THREAD_SAFETY_ANALYSIS
92-
{
93-
if (mode & CRYPTO_LOCK) {
94-
ENTER_CRITICAL_SECTION(ppmutexOpenSSL[i]);
95-
} else {
96-
LEAVE_CRITICAL_SECTION(ppmutexOpenSSL[i]);
97-
}
98-
}
99-
100-
// Singleton for wrapping OpenSSL setup/teardown.
101-
class CInit
102-
{
103-
public:
104-
CInit()
105-
{
106-
// Init OpenSSL library multithreading support
107-
ppmutexOpenSSL.reset(new CCriticalSection[CRYPTO_num_locks()]);
108-
CRYPTO_set_locking_callback(locking_callback);
109-
110-
// OpenSSL can optionally load a config file which lists optional loadable modules and engines.
111-
// We don't use them so we don't require the config. However some of our libs may call functions
112-
// which attempt to load the config file, possibly resulting in an exit() or crash if it is missing
113-
// or corrupt. Explicitly tell OpenSSL not to try to load the file. The result for our libs will be
114-
// that the config appears to have been loaded and there are no modules/engines available.
115-
OPENSSL_no_config();
116-
117-
#ifdef WIN32
118-
// Seed OpenSSL PRNG with current contents of the screen
119-
RAND_screen();
120-
#endif
121-
122-
// Seed OpenSSL PRNG with performance counter
123-
RandAddSeed();
124-
}
125-
~CInit()
126-
{
127-
// Securely erase the memory used by the PRNG
128-
RAND_cleanup();
129-
// Shutdown OpenSSL library multithreading support
130-
CRYPTO_set_locking_callback(nullptr);
131-
// Clear the set of locks now to maintain symmetry with the constructor.
132-
ppmutexOpenSSL.reset();
133-
}
134-
}
135-
instance_of_cinit;
136-
13786
/** A map that contains all the currently held directory locks. After
13887
* successful locking, these will be held here until the global destructor
13988
* cleans them up and thus automatically unlocks them, or ReleaseDirectoryLocks

0 commit comments

Comments
 (0)