QRandomGenerator: improve the fallback seeding in emergencies
If we've never read any samples from hardware RNG or from /dev/urandom, then there are no stored samples for us to seed the Mersenne Twister. In that case, attempt to obtain an emergency sample that consists of some random bits from the variable addresses (ASLR should help) and from the clock (using nanosecond quality, instead of seconds). There's still the possibility that we'll get poor entropy: very close to boot, if the kernel entropy pool is empty, ASLR could be poor and the monotonic clock value could be consistent from boot to boot. There's nothing we can do about that. Change-Id: Ia3e896da908f42939148fffd14c5b0c7b608371b Reviewed-by: Lars Knoll <lars.knoll@qt.io>bb10
parent
ec63fcb314
commit
629f3c0277
|
|
@ -48,6 +48,8 @@
|
|||
|
||||
#if QT_HAS_INCLUDE(<random>)
|
||||
# include <random>
|
||||
# include "qdeadlinetimer.h"
|
||||
# include "qhashfunctions.h"
|
||||
#endif
|
||||
|
||||
#ifdef Q_OS_UNIX
|
||||
|
|
@ -217,12 +219,40 @@ static void fallback_update_seed(unsigned value)
|
|||
seed.fetchAndXorRelaxed(value);
|
||||
}
|
||||
|
||||
static void emergency_seed(quint32 &v) Q_DECL_NOTHROW
|
||||
{
|
||||
// we don't have any seed at all, so let's use the some bits from the
|
||||
// seed variable's address (hoping to get entropy from the system ASLR)
|
||||
// and the current monotonic time in nanoseconds
|
||||
// (wall-clock time can be predicted)
|
||||
|
||||
v = quint32(quintptr(&seed)) >> 12; // PAGE_SHIFT
|
||||
if (sizeof(quintptr) == sizeof(quint32)) {
|
||||
// mask off highest 4 bits, since they're likely to be constant
|
||||
v &= ~0xf00000000U;
|
||||
}
|
||||
|
||||
#ifndef QT_BUILD_QMAKE
|
||||
// see QtPrivate::QHashCombine for the algorithm
|
||||
quint32 nsecs = quint32(QDeadlineTimer::current(Qt::PreciseTimer).deadline());
|
||||
v = QtPrivate::QHashCombine()(v, nsecs);
|
||||
#endif
|
||||
}
|
||||
|
||||
Q_NEVER_INLINE
|
||||
#ifdef Q_CC_GNU
|
||||
__attribute__((cold)) // this function is pretty big, so optimize for size
|
||||
#endif
|
||||
static void fallback_fill(quint32 *ptr, qssize_t left) Q_DECL_NOTHROW
|
||||
{
|
||||
Q_ASSERT(left);
|
||||
|
||||
quint32 v = seed.load();
|
||||
if (Q_UNLIKELY(v == 0))
|
||||
emergency_seed(v);
|
||||
|
||||
// this is highly inefficient, we should save the generator across calls...
|
||||
std::mt19937 generator(seed.load());
|
||||
std::mt19937 generator(v);
|
||||
std::generate(ptr, ptr + left, generator);
|
||||
|
||||
fallback_update_seed(*ptr);
|
||||
|
|
|
|||
Loading…
Reference in New Issue