From 64c536258000b96343edc07d57eb90c50ff1248e Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Thu, 5 Sep 2024 14:31:00 -0700 Subject: [PATCH] LinuxSyscalls: With poll syscall, ensure fds is writable only if nfds is not zero The pointer is allowed to be null or garbage if the number of nfds passed in is zero. Unify the x86 and x86-64 implementations to ensure consistency. Fixes Warhammer 40k: Relics of War --- .../Tools/LinuxEmulation/LinuxSyscalls/Syscalls/FD.cpp | 9 +++++++++ Source/Tools/LinuxEmulation/LinuxSyscalls/x32/FD.cpp | 6 ------ Source/Tools/LinuxEmulation/LinuxSyscalls/x64/FD.cpp | 6 ------ 3 files changed, 9 insertions(+), 12 deletions(-) diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls/FD.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls/FD.cpp index b78ff322b..38c407b1b 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls/FD.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls/FD.cpp @@ -31,6 +31,15 @@ $end_info$ namespace FEX::HLE { void RegisterFD(FEX::HLE::SyscallHandler* Handler) { using namespace FEXCore::IR; + REGISTER_SYSCALL_IMPL_FLAGS(poll, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, + [](FEXCore::Core::CpuStateFrame* Frame, struct pollfd* fds, nfds_t nfds, int timeout) -> uint64_t { + if (nfds) { + // fds is allowed to be garbage if nfds is zero. + FaultSafeUserMemAccess::VerifyIsWritable(fds, sizeof(struct pollfd) * nfds); + } + uint64_t Result = ::poll(fds, nfds, timeout); + SYSCALL_ERRNO(); + }); REGISTER_SYSCALL_IMPL_FLAGS(open, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, [](FEXCore::Core::CpuStateFrame* Frame, const char* pathname, int flags, uint32_t mode) -> uint64_t { diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/FD.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/FD.cpp index 35880e72b..9a2dfabaf 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/FD.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/FD.cpp @@ -253,12 +253,6 @@ auto selectHandler = [](FEXCore::Core::CpuStateFrame* Frame, int nfds, fd_set32* }; void RegisterFD(FEX::HLE::SyscallHandler* Handler) { - REGISTER_SYSCALL_IMPL_X32(poll, [](FEXCore::Core::CpuStateFrame* Frame, struct pollfd* fds, nfds_t nfds, int timeout) -> uint64_t { - FaultSafeUserMemAccess::VerifyIsReadableOrNull(fds, sizeof(struct pollfd) * nfds); - uint64_t Result = ::poll(fds, nfds, timeout); - SYSCALL_ERRNO(); - }); - REGISTER_SYSCALL_IMPL_X32(ppoll, [](FEXCore::Core::CpuStateFrame* Frame, struct pollfd* fds, nfds_t nfds, timespec32* timeout_ts, const uint64_t* sigmask, size_t sigsetsize) -> uint64_t { diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/FD.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/FD.cpp index c7edb42e0..3e05b46b6 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/FD.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/FD.cpp @@ -29,12 +29,6 @@ $end_info$ namespace FEX::HLE::x64 { void RegisterFD(FEX::HLE::SyscallHandler* Handler) { - REGISTER_SYSCALL_IMPL_X64(poll, [](FEXCore::Core::CpuStateFrame* Frame, struct pollfd* fds, nfds_t nfds, int timeout) -> uint64_t { - FaultSafeUserMemAccess::VerifyIsWritable(fds, sizeof(struct pollfd) * nfds); - uint64_t Result = ::poll(fds, nfds, timeout); - SYSCALL_ERRNO(); - }); - REGISTER_SYSCALL_IMPL_X64( select, [](FEXCore::Core::CpuStateFrame* Frame, int nfds, fd_set* readfds, fd_set* writefds, fd_set* exceptfds, struct timeval* timeout) -> uint64_t { ///< All FD arrays need to be writable