From f51ad39ad99fdfbef50a32dd26770f505678a2e3 Mon Sep 17 00:00:00 2001 From: Chocobo1 Date: Sun, 18 May 2025 15:37:17 +0800 Subject: [PATCH] Add fallback for random number generator `getrandom()` is available since Linux 3.17 (2014/10/05) yet there are older devices that don't meet this requirement. Closes #22691. PR #22723. --- src/base/utils/random.cpp | 2 +- src/base/utils/randomlayer_linux.cpp | 45 ++++++++++++++++++++++++++-- src/base/utils/randomlayer_other.cpp | 8 ++--- src/base/utils/randomlayer_win.cpp | 2 +- 4 files changed, 49 insertions(+), 8 deletions(-) diff --git a/src/base/utils/random.cpp b/src/base/utils/random.cpp index 57f84c753..bc0ec3392 100644 --- a/src/base/utils/random.cpp +++ b/src/base/utils/random.cpp @@ -42,7 +42,7 @@ uint32_t Utils::Random::rand(const uint32_t min, const uint32_t max) { - static RandomLayer layer; + static const RandomLayer layer; // new distribution is cheap: https://stackoverflow.com/a/19036349 std::uniform_int_distribution uniform(min, max); diff --git a/src/base/utils/randomlayer_linux.cpp b/src/base/utils/randomlayer_linux.cpp index 29b24631c..81310f3bb 100644 --- a/src/base/utils/randomlayer_linux.cpp +++ b/src/base/utils/randomlayer_linux.cpp @@ -27,6 +27,7 @@ */ #include +#include #include #include @@ -44,6 +45,27 @@ namespace RandomLayer() { + if (::getrandom(nullptr, 0, 0) < 0) + { + if (errno == ENOSYS) + { + // underlying kernel does not implement this system call + // fallback to `urandom` + m_randDev = fopen("/dev/urandom", "rb"); + if (!m_randDev) + qFatal("Failed to open /dev/urandom. Reason: \"%s\". Error code: %d.", std::strerror(errno), errno); + } + else + { + qFatal("getrandom() error. Reason: \"%s\". Error code: %d.", std::strerror(errno), errno); + } + } + } + + ~RandomLayer() + { + if (m_randDev) + fclose(m_randDev); } static constexpr result_type min() @@ -56,7 +78,15 @@ namespace return std::numeric_limits::max(); } - result_type operator()() + result_type operator()() const + { + if (!m_randDev) + return getRandomViaAPI(); + return getRandomViaFile(); + } + + private: + result_type getRandomViaAPI() const { const int RETRY_MAX = 3; @@ -68,10 +98,21 @@ namespace return buf; if (result < 0) - qFatal("getrandom() error. Reason: %s. Error code: %d.", std::strerror(errno), errno); + qFatal("getrandom() error. Reason: \"%s\". Error code: %d.", std::strerror(errno), errno); } qFatal("getrandom() failed. Reason: too many retries."); } + + result_type getRandomViaFile() const + { + result_type buf = 0; + if (fread(&buf, sizeof(buf), 1, m_randDev) == 1) + return buf; + + qFatal("Read /dev/urandom error. Reason: \"%s\". Error code: %d.", std::strerror(errno), errno); + } + + FILE *m_randDev = nullptr; }; } diff --git a/src/base/utils/randomlayer_other.cpp b/src/base/utils/randomlayer_other.cpp index fa7e61f38..4e794a1ae 100644 --- a/src/base/utils/randomlayer_other.cpp +++ b/src/base/utils/randomlayer_other.cpp @@ -46,7 +46,7 @@ namespace : m_randDev {fopen("/dev/urandom", "rb")} { if (!m_randDev) - qFatal("Failed to open /dev/urandom. Reason: %s. Error code: %d.", std::strerror(errno), errno); + qFatal("Failed to open /dev/urandom. Reason: \"%s\". Error code: %d.", std::strerror(errno), errno); } ~RandomLayer() @@ -67,10 +67,10 @@ namespace result_type operator()() const { result_type buf = 0; - if (fread(&buf, sizeof(buf), 1, m_randDev) != 1) - qFatal("Read /dev/urandom error. Reason: %s. Error code: %d.", std::strerror(errno), errno); + if (fread(&buf, sizeof(buf), 1, m_randDev) == 1) + return buf; - return buf; + qFatal("Read /dev/urandom error. Reason: \"%s\". Error code: %d.", std::strerror(errno), errno); } private: diff --git a/src/base/utils/randomlayer_win.cpp b/src/base/utils/randomlayer_win.cpp index 916ed6acf..946a26c94 100644 --- a/src/base/utils/randomlayer_win.cpp +++ b/src/base/utils/randomlayer_win.cpp @@ -60,7 +60,7 @@ namespace return std::numeric_limits::max(); } - result_type operator()() + result_type operator()() const { result_type buf = 0; const bool result = m_processPrng(reinterpret_cast(&buf), sizeof(buf));