diff options
author | Thiago Macieira <thiago.macieira@intel.com> | 2017-06-16 21:39:04 -0700 |
---|---|---|
committer | Thiago Macieira <thiago.macieira@intel.com> | 2017-06-30 21:19:10 +0000 |
commit | 120ecc976fc3d5504d234702f68c2ad3898b77a4 (patch) | |
tree | bfd8b6248a3e1d1e1cd90ab5f29e2bf4012aca79 /src/corelib/global/qrandom.cpp | |
parent | 078f04254e1ab7e4e7cb4b7ff5f371ab22a020cc (diff) |
QRandomGenerator: use getentropy on Linux & OpenBSD
The getentropy function, first found in OpenBSD, is present in glibc
since version 2.25 and Bionic since Android 6.0 and NDK r11. It uses the
Linux 3.17 getrandom system call. Unlike glibc's getrandom() wrapper,
the glibc implementation of getentropy() function is not a POSIX thread
cancellation point, so we prefer to use that even though we have to
break the reading into 256-byte blocks.
The big advantage is that these functions work even in the absence of a
/dev/urandom device node, in addition to a few cycles shaved off by not
having to open a file descriptor and close it at exit. What's more, the
glibc implementation blocks until entropy is available on early boot, so
we don't have to worry about a failure mode. The Bionic implementation
will fall back by itself to /dev/urandom and, failing that, gathering
entropy from elsewhere in the system in a way it cannot fail either.
uClibc has a wrapper to getrandom(2) but no getentropy(3). MUSL has
neither.
Change-Id: Ia53158e207a94bf49489fffd14c8cee1b968a619
Reviewed-by: Lars Knoll <lars.knoll@qt.io>
Diffstat (limited to 'src/corelib/global/qrandom.cpp')
-rw-r--r-- | src/corelib/global/qrandom.cpp | 47 |
1 files changed, 38 insertions, 9 deletions
diff --git a/src/corelib/global/qrandom.cpp b/src/corelib/global/qrandom.cpp index 0fa67f69f8..daa9f25122 100644 --- a/src/corelib/global/qrandom.cpp +++ b/src/corelib/global/qrandom.cpp @@ -48,15 +48,19 @@ #include <errno.h> -#if QT_CONFIG(cxx11_random) -# include <random> -# include "qdeadlinetimer.h" -# include "qhashfunctions.h" -#endif +#if QT_CONFIG(getentropy) +# include <sys/random.h> +#else +# if QT_CONFIG(cxx11_random) +# include <random> +# include "qdeadlinetimer.h" +# include "qhashfunctions.h" +# endif -#if QT_CONFIG(sys_auxv) -# include <sys/auxv.h> -#endif +# if QT_CONFIG(sys_auxv) +# include <sys/auxv.h> +# endif +#endif // !QT_CONFIG(getentropy) #ifdef Q_OS_UNIX # include <fcntl.h> @@ -111,7 +115,26 @@ out: #endif namespace { -#ifdef Q_OS_UNIX +#if QT_CONFIG(getentropy) +class SystemRandom +{ +public: + enum { EfficientBufferFill = true }; + static qssize_t fillBuffer(void *buffer, qssize_t count) Q_DECL_NOTHROW + { + // getentropy can read at most 256 bytes, so break the reading + qssize_t read = 0; + while (count - read > 256) { + // getentropy can't fail under normal circumstances + read += getentropy(reinterpret_cast<uchar *>(buffer) + read, 256); + } + + getentropy(reinterpret_cast<uchar *>(buffer) + read, count - read); + return count; + } +}; + +#elif defined(Q_OS_UNIX) class SystemRandom { static QBasicAtomicInt s_fdp1; // "file descriptor plus 1" @@ -208,6 +231,12 @@ static void fallback_fill(quint32 *ptr, qssize_t left) Q_DECL_NOTHROW return value; }); } +#elif QT_CONFIG(getentropy) +static void fallback_update_seed(unsigned) {} +static void fallback_fill(quint32 *, qssize_t) Q_DECL_NOTHROW +{ + // no fallback necessary, getentropy cannot fail under normal circumstances +} #elif defined(Q_OS_BSD4) static void fallback_update_seed(unsigned) {} static void fallback_fill(quint32 *ptr, qssize_t left) Q_DECL_NOTHROW |