diff options
author | Thiago Macieira <thiago.macieira@intel.com> | 2017-06-06 17:53:42 -0700 |
---|---|---|
committer | Thiago Macieira <thiago.macieira@intel.com> | 2017-06-12 06:14:56 +0000 |
commit | 629f3c0277632b9e799b30f4dccbbe41ec211eef (patch) | |
tree | 553510a7676b6f3a60cd3662fd6320d6c819689e /src/corelib/global/qrandom.cpp | |
parent | ec63fcb314c7f83d9504297c69483f944d5ee29b (diff) |
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>
Diffstat (limited to 'src/corelib/global/qrandom.cpp')
-rw-r--r-- | src/corelib/global/qrandom.cpp | 32 |
1 files changed, 31 insertions, 1 deletions
diff --git a/src/corelib/global/qrandom.cpp b/src/corelib/global/qrandom.cpp index 5c2548184b..eb9eaa68de 100644 --- a/src/corelib/global/qrandom.cpp +++ b/src/corelib/global/qrandom.cpp @@ -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); |