Skip to content

Commit

Permalink
VDSO: Implements v6.11 vdso getrandom
Browse files Browse the repository at this point in the history
This is an interesting vdso implementation because it only exists in
x86-64 with kernel v6.11. For Arm64 the implementation is likely to land
in a couple kernel versions from now.

Some differences with vdso_getrandom versus the regular getrandom
syscall
- Has two additional arguments, opaque_state and opaque_len
- Expects the userspace to mmap/munmap this opaque state structure
- Lets userspace query information about this structure upfront
- If the opaque data structure isn't provided then it falls back to
  regular SYS_getrandom

With the "glibc" implementation, we can tell the interface to allocate a
single page that gets unused (otherwise glibc ends up not using the
interface), and fallback to the regular SYS_getrandom.

In the case of the vdso interface, currently the arguments just get
passed through.

Keeping this as a WIP until the ARM64 kernel patches land and I can
actually test the things. Running the "glibc" path works today with the
selftest, but the vdso path is currently completely untested.
  • Loading branch information
Sonicadvance1 committed Sep 28, 2024
1 parent f640dcc commit 0f54369
Show file tree
Hide file tree
Showing 6 changed files with 82 additions and 6 deletions.
2 changes: 1 addition & 1 deletion Source/Tools/FEXLoader/FEXLoader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -566,7 +566,7 @@ int main(int argc, char** argv, char** const envp) {
ThunkHandler->RegisterTLSState(ParentThread);

// Pass in our VDSO thunks
ThunkHandler->AppendThunkDefinitions(FEX::VDSO::GetVDSOThunkDefinitions());
ThunkHandler->AppendThunkDefinitions(FEX::VDSO::GetVDSOThunkDefinitions(Loader.Is64BitMode()));
SignalDelegation->SetVDSOSigReturn();

SyscallHandler->DeserializeSeccompFD(ParentThread, FEXSeccompFD);
Expand Down
74 changes: 71 additions & 3 deletions Source/Tools/LinuxEmulation/VDSO_Emulation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,14 @@ namespace VDSOHandlers {
using ClockGetTimeType = decltype(::clock_gettime)*;
using ClockGetResType = decltype(::clock_getres)*;
using GetCPUType = decltype(FHU::Syscalls::getcpu)*;
using GetRandomType = ssize_t (*)(void*, size_t, uint32_t, void*, size_t);

TimeType TimePtr;
GetTimeOfDayType GetTimeOfDayPtr;
ClockGetTimeType ClockGetTimePtr;
ClockGetResType ClockGetResPtr;
GetCPUType GetCPUPtr;
GetRandomType GetRandomPtr;
} // namespace VDSOHandlers

using HandlerPtr = void (*)(void*);
Expand Down Expand Up @@ -99,6 +101,39 @@ namespace x64 {
int Result = FHU::Syscalls::getcpu(args->cpu, args->node);
args->rv = SyscallRet(Result);
}

static void getrandom(void* ArgsRV) {
struct vgetrandom_opaque_params {
uint32_t size_of_opaque_state;
uint32_t mmap_prot;
uint32_t mmap_flags;
uint32_t reserved[13];
};
static_assert(sizeof(vgetrandom_opaque_params) == sizeof(uint32_t[16]));

struct __attribute__((packed)) ArgsRV_t {
void* buffer;
size_t len;
uint32_t flags;
vgetrandom_opaque_params* opaque_state;
size_t opaque_len;
ssize_t rv;
}* args = reinterpret_cast<ArgsRV_t*>(ArgsRV);

if (args->buffer == nullptr && args->len == 0 && args->flags == 0 && args->opaque_len == ~0ULL) [[unlikely]] {
// Special case querying for flags
// Since this is the syscall implementation, we need to return valid but unused data.
// This will cause glibc to allocate a page of memory, but it ends up being unused.
args->opaque_state->size_of_opaque_state = 4096;
args->opaque_state->mmap_prot = PROT_NONE;
args->opaque_state->mmap_flags = MAP_NORESERVE | MAP_ANONYMOUS | MAP_PRIVATE;
args->rv = 0;
return;
}

int Result = ::syscall(SYS_getrandom, args->buffer, args->len, args->flags);
args->rv = SyscallRet(Result);
}
} // namespace glibc

namespace VDSO {
Expand Down Expand Up @@ -151,13 +186,27 @@ namespace x64 {

args->rv = VDSOHandlers::GetCPUPtr(args->cpu, args->node);
}

static void getrandom(void* ArgsRV) {
struct __attribute__((packed)) ArgsRV_t {
void* buffer;
size_t len;
uint32_t flags;
void* opaque_state;
size_t opaque_len;
ssize_t rv;
}* args = reinterpret_cast<ArgsRV_t*>(ArgsRV);

args->rv = VDSOHandlers::GetRandomPtr(args->buffer, args->len, args->flags, args->opaque_state, args->opaque_len);
}
} // namespace VDSO

HandlerPtr Handler_time = FEX::VDSO::x64::glibc::time;
HandlerPtr Handler_gettimeofday = FEX::VDSO::x64::glibc::gettimeofday;
HandlerPtr Handler_clock_gettime = FEX::VDSO::x64::glibc::clock_gettime;
HandlerPtr Handler_clock_getres = FEX::VDSO::x64::glibc::clock_getres;
HandlerPtr Handler_getcpu = FEX::VDSO::x64::glibc::getcpu;
HandlerPtr Handler_getrandom = FEX::VDSO::x64::glibc::getrandom;
} // namespace x64
namespace x32 {
namespace glibc {
Expand Down Expand Up @@ -488,9 +537,20 @@ void LoadHostVDSO() {
x64::Handler_getcpu = x64::VDSO::getcpu;
x32::Handler_getcpu = x32::VDSO::getcpu;
}

SymbolPtr = VDSO.FindSymbol("__kernel_getrandom");
if (!SymbolPtr) {
SymbolPtr = VDSO.FindSymbol("__vdso_getrandom");
}

if (SymbolPtr) {
VDSOHandlers::GetRandomPtr = reinterpret_cast<VDSOHandlers::GetRandomType>(SymbolPtr);
x64::Handler_getrandom = x64::VDSO::getrandom;
// 32-bit doesn't have getrandom vdso
}
}

static std::array<FEXCore::IR::ThunkDefinition, 6> VDSODefinitions = {{
static std::array<FEXCore::IR::ThunkDefinition, 7> VDSODefinitions = {{
{
// sha256(libVDSO:time)
{0x37, 0x63, 0x46, 0xb0, 0x79, 0x06, 0x5f, 0x9d, 0x00, 0xb6, 0x8d, 0xfd, 0x9e, 0x4a, 0x62, 0xcd,
Expand Down Expand Up @@ -529,6 +589,12 @@ static std::array<FEXCore::IR::ThunkDefinition, 6> VDSODefinitions = {{
0xbb, 0x50, 0x49, 0x55, 0x6b, 0x0c, 0x9f, 0x50, 0x37, 0xf5, 0x9d, 0xb0, 0x38, 0x58, 0x57, 0x12},
nullptr,
},
{
// sha256(libVDSO:getrandom)
{0xf8, 0x03, 0xe2, 0x70, 0xe3, 0xf1, 0xbb, 0xc1, 0x7d, 0xa7, 0x8b, 0xb3, 0x1f, 0x3e, 0xbd, 0xc6,
0x8a, 0x50, 0xd3, 0x4a, 0x1f, 0xb3, 0x4b, 0x7e, 0x32, 0xcb, 0x1e, 0x18, 0x3b, 0x7c, 0xeb, 0x4b},
nullptr,
},
}};

void LoadGuestVDSOSymbols(bool Is64Bit, char* VDSOBase) {
Expand Down Expand Up @@ -702,6 +768,7 @@ VDSOMapping LoadVDSOThunks(bool Is64Bit, FEX::HLE::SyscallHandler* const Handler
VDSODefinitions[3].ThunkFunction = FEX::VDSO::x64::Handler_clock_gettime;
VDSODefinitions[4].ThunkFunction = FEX::VDSO::x64::Handler_clock_getres;
VDSODefinitions[5].ThunkFunction = FEX::VDSO::x64::Handler_getcpu;
VDSODefinitions[6].ThunkFunction = FEX::VDSO::x64::Handler_getrandom;
} else {
// Set the Thunk definition pointers for x86
VDSODefinitions[0].ThunkFunction = FEX::VDSO::x32::Handler_time;
Expand All @@ -710,6 +777,7 @@ VDSOMapping LoadVDSOThunks(bool Is64Bit, FEX::HLE::SyscallHandler* const Handler
VDSODefinitions[3].ThunkFunction = FEX::VDSO::x32::Handler_clock_gettime64;
VDSODefinitions[4].ThunkFunction = FEX::VDSO::x32::Handler_clock_getres;
VDSODefinitions[5].ThunkFunction = FEX::VDSO::x32::Handler_getcpu;
// getrandom doesn't exist on 32-bit, so leave VDSODefinitions[6] unfilled
}

return Mapping;
Expand All @@ -730,8 +798,8 @@ uint64_t GetVSyscallEntry(const void* VDSOBase) {
return 0;
}

const std::span<FEXCore::IR::ThunkDefinition> GetVDSOThunkDefinitions() {
return VDSODefinitions;
const std::span<FEXCore::IR::ThunkDefinition> GetVDSOThunkDefinitions(bool Is64Bit) {
return std::span(VDSODefinitions.begin(), VDSODefinitions.end() - (Is64Bit ? 0 : 1));
}

const VDSOSigReturn& GetVDSOSymbols() {
Expand Down
2 changes: 1 addition & 1 deletion Source/Tools/LinuxEmulation/VDSO_Emulation.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,6 @@ void UnloadVDSOMapping(const VDSOMapping& Mapping);

uint64_t GetVSyscallEntry(const void* VDSOBase);

const std::span<FEXCore::IR::ThunkDefinition> GetVDSOThunkDefinitions();
const std::span<FEXCore::IR::ThunkDefinition> GetVDSOThunkDefinitions(bool Is64Bit);
const VDSOSigReturn& GetVDSOSymbols();
} // namespace FEX::VDSO
3 changes: 2 additions & 1 deletion ThunkLibs/libVDSO/libVDSO_Guest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ __attribute__((naked)) void __kernel_rt_sigreturn() {
)" ::
: "memory");
}

#else
ssize_t __vdso_getrandom(void*, size_t, uint32_t, void*, size_t) __attribute__((alias("fexfn_pack_getrandom")));
#endif
}
2 changes: 2 additions & 0 deletions ThunkLibs/libVDSO/libVDSO_Guest.lds
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ VERSION {
clock_getres;
__vdso_getcpu;
getcpu;
__vdso_getrandom;
getrandom;
local: *;
};
}
5 changes: 5 additions & 0 deletions ThunkLibs/libVDSO/libVDSO_interface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include <sched.h>
#include <sys/time.h>
#include <sys/types.h>
#include <time.h>

#include "Types.h"
Expand All @@ -24,4 +25,8 @@ struct fex_gen_config<getcpu> {};
extern int clock_gettime64(clockid_t __clock_id, struct timespec64* __tp) __THROW;
template<>
struct fex_gen_config<clock_gettime64> {};
#else
extern ssize_t getrandom(void* buffer, size_t len, uint32_t flags, void* opaque_state, size_t opaque_len);
template<>
struct fex_gen_config<getrandom> {};
#endif

0 comments on commit 0f54369

Please sign in to comment.