summaryrefslogtreecommitdiffstats
path: root/src/corelib/global/qrandom.cpp
diff options
context:
space:
mode:
authorThiago Macieira <thiago.macieira@intel.com>2017-06-06 17:53:42 -0700
committerThiago Macieira <thiago.macieira@intel.com>2017-06-12 06:14:56 +0000
commit629f3c0277632b9e799b30f4dccbbe41ec211eef (patch)
tree553510a7676b6f3a60cd3662fd6320d6c819689e /src/corelib/global/qrandom.cpp
parentec63fcb314c7f83d9504297c69483f944d5ee29b (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.cpp32
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);