From fcddf86352687c78daba0cf4fcc218c76cc789e2 Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Thu, 12 Jan 2023 18:26:21 -0800 Subject: [PATCH] ELFCodeLoader: Don't use std::random_device for RNG Fixes #2095 std::random_device can fail to find a random source and throw an assert during initialization. The constructor allows you to provide a token string to select an explicit random source, but this is c++ library specific and will still assert if the source isn't found. Also specific tokens are very much target and library specific, so it is unsafe to use. In the libstdc++ case, the default implementation will try to open `/dev/urandom` which might not be available on all targets. Instead of relying on this C++ object, use the `getrandom` syscall directly to generate our RNG used in the ELFCodeLoader. Resolves any sort of asserting case, blocks on RNG generation, and is guaranteed to be available since this syscall has been available since a very old kernel version. --- Source/Tests/ELFCodeLoader2.h | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/Source/Tests/ELFCodeLoader2.h b/Source/Tests/ELFCodeLoader2.h index 643609c27..7d03e1af1 100644 --- a/Source/Tests/ELFCodeLoader2.h +++ b/Source/Tests/ELFCodeLoader2.h @@ -34,6 +34,7 @@ #include #include #include +#include #define PAGE_START(x) ((x) & ~(uintptr_t)(4095)) #define PAGE_OFFSET(x) ((x) & 4095) @@ -176,6 +177,17 @@ class ELFCodeLoader2 final : public FEXCore::CodeLoader { return LoadBase; } + static bool GetRandom(void *Data, size_t DataSize) { + ssize_t Result{}; + do { + // This is guaranteed to not be interrupted by a signal, + // since fewer than 256 bytes of RNG data are requested + Result = getrandom(Data, DataSize, 0); + } while (Result != -1 && Result != DataSize); + + return Result != -1; + } + public: static std::string ResolveRootfsFile(std::string const &File, std::string RootFS) { @@ -472,9 +484,12 @@ class ELFCodeLoader2 final : public FEXCore::CodeLoader { if (!NoRandomize) { constexpr uint64_t ASLR_BITS_64 = 28; constexpr uint64_t ASLR_BITS_32 = 8; - std::random_device rd; - std::uniform_int_distribution d(0); - uint64_t ASLR_Offset = d(rd); + uint64_t ASLR_Offset{}; + if (!GetRandom(&ASLR_Offset, sizeof(ASLR_Offset))) { + // getrandom failed for some reason. + ASLR_Offset = 0; + LogMan::Msg::EFmt("RNG failed. ASLR will not work."); + } if (Is64BitMode()) { ASLR_Offset &= (1ULL << ASLR_BITS_64) - 1; @@ -720,11 +735,12 @@ class ELFCodeLoader2 final : public FEXCore::CodeLoader { } else { // Nothing provided from the kernel, generate our own random values. - std::random_device rd; - std::uniform_int_distribution d(0); - - RandomLoc[0] = d(rd); - RandomLoc[1] = d(rd); + if (!GetRandom(&RandomLoc[0], sizeof(uint64_t) * 2)) { + // getrandom failed for some reason. + RandomLoc[0] = 0; + RandomLoc[1] = 0; + LogMan::Msg::EFmt("RNG failed. AT_RANDOM will not be random."); + } } // Stack setup