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.
This commit is contained in:
Ryan Houdek committed 2023-01-14 12:06:12 -08:00
1 parent 1521e0a248
commit fcddf86352
1 file changed
+24 -8
+24 -8
View File
@@ -34,6 +34,7 @@
#include <sys/auxv.h>
#include <sys/mman.h>
#include <sys/personality.h>
#include <sys/random.h>
#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<uint64_t> 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<uint64_t> 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