Skip to content

Commit

Permalink
Merge pull request #4116 from Sonicadvance1/personality_handling
Browse files Browse the repository at this point in the history
LinuxEmulation: Personality handling
  • Loading branch information
Sonicadvance1 authored Oct 16, 2024
2 parents 4b945a9 + 3398f22 commit 0897cd8
Show file tree
Hide file tree
Showing 6 changed files with 86 additions and 5 deletions.
38 changes: 36 additions & 2 deletions Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls/Info.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ tags: LinuxSyscalls|syscalls-shared
#include <sys/syscall.h>
#include <sys/utsname.h>
#include <sys/klog.h>
#include <sys/personality.h>
#include <unistd.h>

#include <git_version.h>
Expand All @@ -37,6 +38,8 @@ void RegisterInfo(FEX::HLE::SyscallHandler* Handler) {

REGISTER_SYSCALL_IMPL_FLAGS(
uname, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, [](FEXCore::Core::CpuStateFrame* Frame, struct utsname* buf) -> uint64_t {
auto Thread = FEX::HLE::ThreadManager::GetStateObjectFromCPUState(Frame);

struct utsname Local {};
if (::uname(&Local) == 0) {
memcpy(buf->nodename, Local.nodename, sizeof(Local.nodename));
Expand All @@ -49,17 +52,48 @@ void RegisterInfo(FEX::HLE::SyscallHandler* Handler) {
}
strcpy(buf->sysname, "Linux");
uint32_t GuestVersion = FEX::HLE::_SyscallHandler->GetGuestKernelVersion();
if (Thread->persona & UNAME26) {
// Kernel version converts from 6.x.y to 2.6.60+x.
GuestVersion = FEX::HLE::SyscallHandler::KernelVersion(2, 6, 60 + FEX::HLE::SyscallHandler::KernelMinor(GuestVersion));
}
snprintf(buf->release, sizeof(buf->release), "%d.%d.%d", FEX::HLE::SyscallHandler::KernelMajor(GuestVersion),
FEX::HLE::SyscallHandler::KernelMinor(GuestVersion), FEX::HLE::SyscallHandler::KernelPatch(GuestVersion));

const char version[] = "#" GIT_DESCRIBE_STRING " SMP " __DATE__ " " __TIME__;
strcpy(buf->version, version);
static_assert(sizeof(version) <= sizeof(buf->version), "uname version define became too large!");
// Tell the guest that we are a 64bit kernel
strcpy(buf->machine, "x86_64");
if (Thread->persona & PER_LINUX32) {
// Tell the guest that we are a 32bit kernel
strcpy(buf->machine, "i686");
} else {
// Tell the guest that we are a 64bit kernel
strcpy(buf->machine, "x86_64");
}
return 0;
});

REGISTER_SYSCALL_IMPL_PASS_FLAGS(personality, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
[](FEXCore::Core::CpuStateFrame* Frame, uint32_t persona) -> uint64_t {
auto Thread = FEX::HLE::ThreadManager::GetStateObjectFromCPUState(Frame);

if (persona == ~0U) {
// Special case, only queries the persona.
return Thread->persona;
}

// Mask off `PER_LINUX32` because AArch64 doesn't support it.
uint32_t NewPersona = persona & ~PER_LINUX32;

// This syscall can not physically fail with PER_LINUX32 masked off.
// It also can not fail on a real x86 kernel.
(void)::syscall(SYSCALL_DEF(personality), NewPersona);

// Return the old persona while setting the new one.
auto OldPersona = Thread->persona;
Thread->persona = persona;
return OldPersona;
});

REGISTER_SYSCALL_IMPL_FLAGS(seccomp, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
[](FEXCore::Core::CpuStateFrame* Frame, unsigned int operation, unsigned int flags, void* args) -> uint64_t {
return FEX::HLE::_SyscallHandler->SeccompEmulator.Handle(Frame, operation, flags, args);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -330,8 +330,6 @@ void RegisterCommon(FEX::HLE::SyscallHandler* Handler) {
SyscallPassthrough2<SYSCALL_DEF(capget)>);
REGISTER_SYSCALL_IMPL_PASS_FLAGS(capset, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
SyscallPassthrough2<SYSCALL_DEF(capset)>);
REGISTER_SYSCALL_IMPL_PASS_FLAGS(personality, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
SyscallPassthrough1<SYSCALL_DEF(personality)>);
REGISTER_SYSCALL_IMPL_PASS_FLAGS(getpriority, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
SyscallPassthrough2<SYSCALL_DEF(getpriority)>);
REGISTER_SYSCALL_IMPL_PASS_FLAGS(setpriority, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ FEX::HLE::ThreadStateObject* ThreadManager::CreateThread(uint64_t InitialRIP, ui

if (InheritThread) {
FEX::HLE::_SyscallHandler->SeccompEmulator.InheritSeccompFilters(InheritThread, ThreadStateObject);
ThreadStateObject->persona = InheritThread->persona;
}

++IdleWaitRefCount;
Expand Down
3 changes: 3 additions & 0 deletions Source/Tools/LinuxEmulation/LinuxSyscalls/ThreadManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ struct ThreadStateObject : public FEXCore::Allocator::FEXAllocOperators {
// Seccomp thread specific data.
uint32_t SeccompMode {SECCOMP_MODE_DISABLED};
fextl::vector<FEX::HLE::SeccompEmulator::FilterInformation*> Filters {};

// personality emulation.
uint32_t persona {};
};

class ThreadManager final {
Expand Down
2 changes: 1 addition & 1 deletion unittests/FEXLinuxTests/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 3.14)
project(FEXLinuxTests)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD 20)

unset(CMAKE_C_FLAGS)
unset(CMAKE_CXX_FLAGS)
Expand Down
45 changes: 45 additions & 0 deletions unittests/FEXLinuxTests/tests/syscalls/personality.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#include <catch2/catch_test_macros.hpp>

#include <cstdint>
#include <sys/personality.h>
#include <sys/utsname.h>
#include <string_view>

constexpr uint32_t QUERY_PERSONA = ~0U;
TEST_CASE("default - query") {
REQUIRE(::personality(0) != -1);

auto persona = ::personality(QUERY_PERSONA);
CHECK(persona == 0);
}

TEST_CASE("default - set all") {
REQUIRE(::personality(-2U) != -1);
auto persona = ::personality(QUERY_PERSONA);
CHECK(persona == -2U);
}

TEST_CASE("default - check linux32") {
REQUIRE(::personality(0) != -1);

struct utsname name {};
uname(&name);
CHECK(std::string_view(name.machine) == "x86_64");

CHECK(::personality(PER_LINUX32) != -1);
auto persona = ::personality(QUERY_PERSONA);
CHECK(persona == PER_LINUX32);

uname(&name);
CHECK(std::string_view(name.machine) == "i686");
}

TEST_CASE("default - check uname26") {
REQUIRE(::personality(UNAME26) != -1);
auto persona = ::personality(QUERY_PERSONA);
CHECK(persona == UNAME26);

struct utsname name {};
uname(&name);
CHECK(std::string_view(name.release).starts_with("2.6."));
}

0 comments on commit 0897cd8

Please sign in to comment.