Skip to content

Commit

Permalink
LinuxSyscalls: Log unhandled clone3 fork flags
Browse files Browse the repository at this point in the history
Make sure to pass the clone3 arguments all the way to the fork handler
so it can check the flags. Currently nothing I know of uses fork plus
the new clone3 flags, but it would be hard to see without any logging.
  • Loading branch information
Sonicadvance1 committed Jan 3, 2025
1 parent 6bc7a83 commit 8efa5fe
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 15 deletions.
4 changes: 1 addition & 3 deletions Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -676,9 +676,7 @@ uint64_t CloneHandler(FEXCore::Core::CpuStateFrame* Frame, FEX::HLE::clone3_args

if (!(flags & CLONE_THREAD)) {
// CLONE_PARENT is ignored (Implied by CLONE_THREAD)
return FEX::HLE::ForkGuest(Thread, Frame, flags, reinterpret_cast<void*>(args->args.stack), args->args.stack_size,
reinterpret_cast<pid_t*>(args->args.parent_tid), reinterpret_cast<pid_t*>(args->args.child_tid),
reinterpret_cast<void*>(args->args.tls), args->args.exit_signal);
return FEX::HLE::ForkGuest(Thread, Frame, args);
} else {
auto NewThread = FEX::HLE::CreateNewThread(Thread->CTX, Frame, args);

Expand Down
64 changes: 54 additions & 10 deletions Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls/Thread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -250,10 +250,24 @@ static int CloneFork(uint32_t flags, uint64_t exit_signal) {
return ::syscall(SYSCALL_DEF(clone), (flags & (CLONE_FS | CLONE_FILES)) | exit_signal, nullptr, nullptr, nullptr, nullptr);
}

uint64_t ForkGuest(FEXCore::Core::InternalThreadState* Thread, FEXCore::Core::CpuStateFrame* Frame, uint32_t flags, void* stack,
size_t StackSize, pid_t* parent_tid, pid_t* child_tid, void* tls, uint64_t exit_signal) {
// Just before we fork, we lock all syscall mutexes so that both processes will end up with a locked mutex
uint64_t ForkGuest(FEXCore::Core::InternalThreadState* Thread, FEXCore::Core::CpuStateFrame* Frame, FEX::HLE::clone3_args* args) {
const uint64_t flags = args->args.flags;
auto stack = reinterpret_cast<const void*>(args->args.stack);
const uint64_t stack_size = args->args.stack_size;
auto parent_tid = reinterpret_cast<pid_t*>(args->args.parent_tid);
auto child_tid = reinterpret_cast<pid_t*>(args->args.child_tid);
auto tls = reinterpret_cast<void*>(args->args.tls);
const uint64_t exit_signal = args->args.exit_signal;

// Sanity check flags here.
if (args->Type == TypeOfClone::TYPE_CLONE3) {
constexpr uint64_t UnsupportedFlags = CLONE_CLEAR_SIGHAND | CLONE_INTO_CGROUP | CLONE_NEWTIME;
if (args->args.flags & UnsupportedFlags) {
LogMan::Msg::EFmt("fork: Unsupported flags passed. {:#x}", args->args.flags & UnsupportedFlags);
}
}

// Just before we fork, we lock all syscall mutexes so that both processes will end up with a locked mutex
uint64_t Mask {~0ULL};
::syscall(SYS_rt_sigprocmask, SIG_SETMASK, &Mask, &Mask, sizeof(Mask));

Expand Down Expand Up @@ -304,7 +318,7 @@ uint64_t ForkGuest(FEXCore::Core::InternalThreadState* Thread, FEXCore::Core::Cp
// Handle child setup now
if (stack != nullptr) {
// use specified stack
Frame->State.gregs[FEXCore::X86State::REG_RSP] = reinterpret_cast<uint64_t>(stack) + StackSize;
Frame->State.gregs[FEXCore::X86State::REG_RSP] = reinterpret_cast<uint64_t>(stack) + stack_size;
} else {
// In the case of fork and nullptr stack then the child uses the same stack space as the parent
// Same virtual address, different addressspace
Expand Down Expand Up @@ -378,13 +392,43 @@ void RegisterThread(FEX::HLE::SyscallHandler* Handler) {
FEX_UNREACHABLE;
});

REGISTER_SYSCALL_IMPL_FLAGS(fork, SyscallFlags::DEFAULT, [](FEXCore::Core::CpuStateFrame* Frame) -> uint64_t {
return ForkGuest(Frame->Thread, Frame, 0, 0, 0, 0, 0, 0, SIGCHLD);
});
REGISTER_SYSCALL_IMPL_FLAGS(fork, SyscallFlags::DEFAULT, ([](FEXCore::Core::CpuStateFrame* Frame) -> uint64_t {
FEX::HLE::clone3_args args {.Type = TypeOfClone::TYPE_CLONE2,
.args = {
.flags = 0,
.pidfd = 0,
.child_tid = 0,
.parent_tid = 0,
.exit_signal = SIGCHLD,
.stack = 0,
.stack_size = 0,
.tls = 0,
.set_tid = 0,
.set_tid_size = 0,
.cgroup = 0,
}};

return ForkGuest(Frame->Thread, Frame, &args);
}));

REGISTER_SYSCALL_IMPL_FLAGS(vfork, SyscallFlags::DEFAULT, [](FEXCore::Core::CpuStateFrame* Frame) -> uint64_t {
return ForkGuest(Frame->Thread, Frame, CLONE_VFORK, 0, 0, 0, 0, 0, SIGCHLD);
});
REGISTER_SYSCALL_IMPL_FLAGS(vfork, SyscallFlags::DEFAULT, ([](FEXCore::Core::CpuStateFrame* Frame) -> uint64_t {
FEX::HLE::clone3_args args {.Type = TypeOfClone::TYPE_CLONE2,
.args = {
.flags = CLONE_VFORK,
.pidfd = 0,
.child_tid = 0,
.parent_tid = 0,
.exit_signal = SIGCHLD,
.stack = 0,
.stack_size = 0,
.tls = 0,
.set_tid = 0,
.set_tid_size = 0,
.cgroup = 0,
}};

return ForkGuest(Frame->Thread, Frame, &args);
}));

REGISTER_SYSCALL_IMPL_FLAGS(getpgrp, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
[](FEXCore::Core::CpuStateFrame* Frame) -> uint64_t {
Expand Down
3 changes: 1 addition & 2 deletions Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls/Thread.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,5 @@ struct ThreadStateObject;
FEX::HLE::ThreadStateObject* CreateNewThread(FEXCore::Context::Context* CTX, FEXCore::Core::CpuStateFrame* Frame, FEX::HLE::clone3_args* args);
uint64_t HandleNewClone(FEX::HLE::ThreadStateObject* Thread, FEXCore::Context::Context* CTX, FEXCore::Core::CpuStateFrame* Frame,
FEX::HLE::clone3_args* GuestArgs);
uint64_t ForkGuest(FEXCore::Core::InternalThreadState* Thread, FEXCore::Core::CpuStateFrame* Frame, uint32_t flags, void* stack,
size_t StackSize, pid_t* parent_tid, pid_t* child_tid, void* tls, uint64_t exit_signal);
uint64_t ForkGuest(FEXCore::Core::InternalThreadState* Thread, FEXCore::Core::CpuStateFrame* Frame, FEX::HLE::clone3_args* args);
} // namespace FEX::HLE

0 comments on commit 8efa5fe

Please sign in to comment.