summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorThiago Macieira <thiago.macieira@intel.com>2017-06-06 17:58:20 -0700
committerThiago Macieira <thiago.macieira@intel.com>2017-06-12 06:15:01 +0000
commitd57bf5e8aa6c575c4e3b9d80793e9becf1469d82 (patch)
tree597ed892cecf80675aafd45e6047a30a9a6a1bb7 /src
parent629f3c0277632b9e799b30f4dccbbe41ec211eef (diff)
QRandomGenerator: mix the Linux AT_RANDOM random bytes in the fallback
The Linux kernel gives us 16 bytes of random data and sets a pointer to it in the ELF AuxV (the same one that allows us to get HWCAP on ARM systems). So if we end up in the fallback generator, at leat we'll get a good amount of entropy to seed the Mersenne Twister. This could happen if the application is run in a chroot(2) or container without /dev/random or /dev/urandom. That is probably an installation mistake, so we don't optimize this case for performance. With this commit, we have now good, high-quality fallbacks for Windows (rand_s), for BSDs (arc4random) and for Linux. The only missing, supported OS without a good entropy source is QNX. Change-Id: Ia3e896da908f42939148fffd14c5b1084051f1a8 Reviewed-by: Lars Knoll <lars.knoll@qt.io>
Diffstat (limited to 'src')
-rw-r--r--src/corelib/global/qrandom.cpp29
1 files changed, 26 insertions, 3 deletions
diff --git a/src/corelib/global/qrandom.cpp b/src/corelib/global/qrandom.cpp
index eb9eaa68de..0601dbdb30 100644
--- a/src/corelib/global/qrandom.cpp
+++ b/src/corelib/global/qrandom.cpp
@@ -52,6 +52,10 @@
# include "qhashfunctions.h"
#endif
+#if QT_HAS_INCLUDE(<sys/auxv.h>)
+# include <sys/auxv.h>
+#endif
+
#ifdef Q_OS_UNIX
# include <fcntl.h>
# include <private/qcore_unix_p.h>
@@ -247,12 +251,31 @@ static void fallback_fill(quint32 *ptr, qssize_t left) Q_DECL_NOTHROW
{
Q_ASSERT(left);
+ // ELF's auxv AT_RANDOM has 16 random bytes
+ using RandomBytes = quint32[16 / sizeof(quint32)];
+ RandomBytes scratch = {};
+ RandomBytes *auxvSeed = nullptr;
+
+#if QT_HAS_INCLUDE(<sys/auxv.h>) && defined(AT_RANDOM)
+ // works on Linux -- all modern libc have getauxval
+ // other ELF-based systems don't seem to have AT_RANDOM
+ auxvSeed = reinterpret_cast<RandomBytes *>(getauxval(AT_RANDOM));
+ if (auxvSeed)
+ memcpy(scratch, auxvSeed, sizeof(RandomBytes));
+#endif
+
quint32 v = seed.load();
- if (Q_UNLIKELY(v == 0))
- emergency_seed(v);
+ if (Q_LIKELY(v)) {
+ // mix the stored seed value
+ // (using the fact that qHash(unsigned) is idempotent)
+ scratch[0] = QtPrivate::QHashCombine()(scratch[0], v);
+ } else if (Q_UNLIKELY(auxvSeed == nullptr)) {
+ emergency_seed(scratch[0]);
+ }
// this is highly inefficient, we should save the generator across calls...
- std::mt19937 generator(v);
+ std::seed_seq sseq(std::begin(scratch), std::end(scratch));
+ std::mt19937 generator(sseq);
std::generate(ptr, ptr + left, generator);
fallback_update_seed(*ptr);