From 3a79b61f58f5125b1e07f642f057234b3e380dbe Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Wed, 28 Aug 2024 04:14:13 -0700 Subject: [PATCH 1/4] x64/Thread: Adds EFAULT handlers for two syscalls For the remaining syscalls we need to introduce some new concepts around checking if pointers and string arrays are readable and I don't want to do that yet. --- .../LinuxEmulation/LinuxSyscalls/x64/Thread.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Thread.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Thread.cpp index f2d666cef9..9184f0736e 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Thread.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Thread.cpp @@ -38,6 +38,16 @@ void RegisterThread(FEX::HLE::SyscallHandler* Handler) { REGISTER_SYSCALL_IMPL_X64_FLAGS( clone, SyscallFlags::DEFAULT, ([](FEXCore::Core::CpuStateFrame* Frame, uint32_t flags, void* stack, pid_t* parent_tid, pid_t* child_tid, void* tls) -> uint64_t { + // This is slightly different EFAULT behaviour, if child_tid or parent_tid is invalid then the kernel just doesn't write to the + // pointer. Still need to be EFAULT safe although. + if ((flags & (CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID)) && child_tid) { + FaultSafeUserMemAccess::VerifyIsWritable(child_tid, sizeof(*child_tid)); + } + + if ((flags & CLONE_PARENT_SETTID) && parent_tid) { + FaultSafeUserMemAccess::VerifyIsWritable(parent_tid, sizeof(*parent_tid)); + } + FEX::HLE::clone3_args args { .Type = TypeOfClone::TYPE_CLONE2, .args = @@ -59,6 +69,8 @@ void RegisterThread(FEX::HLE::SyscallHandler* Handler) { })); REGISTER_SYSCALL_IMPL_X64(sigaltstack, [](FEXCore::Core::CpuStateFrame* Frame, const stack_t* ss, stack_t* old_ss) -> uint64_t { + FaultSafeUserMemAccess::VerifyIsReadableOrNull(ss, sizeof(*ss)); + FaultSafeUserMemAccess::VerifyIsWritableOrNull(old_ss, sizeof(*old_ss)); return FEX::HLE::_SyscallHandler->GetSignalDelegator()->RegisterGuestSigAltStack(ss, old_ss); }); From 91b6aeffe13a0db774444cf4e8f1a4407c79aa71 Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Wed, 28 Aug 2024 04:19:45 -0700 Subject: [PATCH 2/4] x32/Timer: Adds EFAULT handlers --- Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Timer.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Timer.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Timer.cpp index 3a5d46621a..0bb9941e32 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Timer.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Timer.cpp @@ -32,12 +32,14 @@ void RegisterTimer(FEX::HLE::SyscallHandler* Handler) { itimerspec old_value_host {}; itimerspec* old_value_host_p {}; + FaultSafeUserMemAccess::VerifyIsReadable(new_value, sizeof(*new_value)); new_value_host = *new_value; if (old_value) { old_value_host_p = &old_value_host; } uint64_t Result = ::syscall(SYSCALL_DEF(timer_settime), timerid, flags, &new_value_host, old_value_host_p); if (Result != -1 && old_value) { + FaultSafeUserMemAccess::VerifyIsWritable(old_value, sizeof(*old_value)); *old_value = old_value_host; } SYSCALL_ERRNO(); @@ -47,6 +49,7 @@ void RegisterTimer(FEX::HLE::SyscallHandler* Handler) { timer_gettime, [](FEXCore::Core::CpuStateFrame* Frame, kernel_timer_t timerid, FEX::HLE::x32::old_itimerspec32* curr_value) -> uint64_t { itimerspec curr_value_host {}; uint64_t Result = ::syscall(SYSCALL_DEF(timer_gettime), timerid, curr_value_host); + FaultSafeUserMemAccess::VerifyIsWritable(curr_value, sizeof(*curr_value)); *curr_value = curr_value_host; SYSCALL_ERRNO(); }); @@ -59,6 +62,7 @@ void RegisterTimer(FEX::HLE::SyscallHandler* Handler) { } uint64_t Result = ::getitimer(which, val_p); if (curr_value) { + FaultSafeUserMemAccess::VerifyIsWritable(curr_value, sizeof(*curr_value)); *curr_value = val; } SYSCALL_ERRNO(); @@ -73,6 +77,7 @@ void RegisterTimer(FEX::HLE::SyscallHandler* Handler) { itimerval* old_p {}; if (new_value) { + FaultSafeUserMemAccess::VerifyIsReadable(new_value, sizeof(*new_value)); val = *new_value; val_p = &val; } @@ -84,6 +89,7 @@ void RegisterTimer(FEX::HLE::SyscallHandler* Handler) { uint64_t Result = ::setitimer(which, val_p, old_p); if (old_value) { + FaultSafeUserMemAccess::VerifyIsWritable(old_value, sizeof(*old_value)); *old_value = old; } SYSCALL_ERRNO(); @@ -92,6 +98,7 @@ void RegisterTimer(FEX::HLE::SyscallHandler* Handler) { REGISTER_SYSCALL_IMPL_X32( timer_create, [](FEXCore::Core::CpuStateFrame* Frame, clockid_t clockid, compat_ptr sevp, kernel_timer_t* timerid) -> uint64_t { + FaultSafeUserMemAccess::VerifyIsReadable(sevp, sizeof(*sevp)); sigevent Host = *sevp; uint64_t Result = ::syscall(SYSCALL_DEF(timer_create), clockid, &Host, timerid); SYSCALL_ERRNO(); From 5529948479a405f76edc78ce5fb756b0bbc069b3 Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Wed, 28 Aug 2024 04:25:13 -0700 Subject: [PATCH 3/4] x32/Time: Adds EFAULT handlers --- .../LinuxEmulation/LinuxSyscalls/x32/Time.cpp | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Time.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Time.cpp index 607128f73a..6a84efdf2c 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Time.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Time.cpp @@ -36,6 +36,7 @@ void RegisterTime(FEX::HLE::SyscallHandler* Handler) { uint64_t Result = ::time(&Host); if (tloc) { + FaultSafeUserMemAccess::VerifyIsWritable(tloc, sizeof(*tloc)); // On 32-bit this truncates *tloc = (FEX::HLE::x32::old_time32_t)Host; } @@ -47,6 +48,7 @@ void RegisterTime(FEX::HLE::SyscallHandler* Handler) { struct tms Host {}; uint64_t Result = ::times(&Host); if (buf) { + FaultSafeUserMemAccess::VerifyIsWritable(buf, sizeof(*buf)); *buf = Host; } SYSCALL_ERRNO(); @@ -56,6 +58,7 @@ void RegisterTime(FEX::HLE::SyscallHandler* Handler) { struct utimbuf Host {}; struct utimbuf* Host_p {}; if (times) { + FaultSafeUserMemAccess::VerifyIsReadable(times, sizeof(*times)); Host = *times; Host_p = &Host; } @@ -73,6 +76,7 @@ void RegisterTime(FEX::HLE::SyscallHandler* Handler) { uint64_t Result = ::gettimeofday(tv_ptr, tz); if (tv) { + FaultSafeUserMemAccess::VerifyIsWritable(tv, sizeof(*tv)); *tv = tv64; } SYSCALL_ERRNO(); @@ -82,6 +86,7 @@ void RegisterTime(FEX::HLE::SyscallHandler* Handler) { struct timeval tv64 {}; struct timeval* tv_ptr {}; if (tv) { + FaultSafeUserMemAccess::VerifyIsReadable(tv, sizeof(*tv)); tv64 = *tv; tv_ptr = &tv64; } @@ -95,12 +100,14 @@ void RegisterTime(FEX::HLE::SyscallHandler* Handler) { struct timespec* rem64_ptr {}; if (rem) { + FaultSafeUserMemAccess::VerifyIsReadable(rem, sizeof(*rem)); rem64 = *rem; rem64_ptr = &rem64; } uint64_t Result = 0; if (req) { + FaultSafeUserMemAccess::VerifyIsReadable(req, sizeof(*req)); const struct timespec req64 = *req; Result = ::nanosleep(&req64, rem64_ptr); } else { @@ -108,6 +115,7 @@ void RegisterTime(FEX::HLE::SyscallHandler* Handler) { } if (rem) { + FaultSafeUserMemAccess::VerifyIsWritable(rem, sizeof(*rem)); *rem = rem64; } SYSCALL_ERRNO(); @@ -117,6 +125,7 @@ void RegisterTime(FEX::HLE::SyscallHandler* Handler) { struct timespec tp64 {}; uint64_t Result = ::clock_gettime(clk_id, &tp64); if (tp) { + FaultSafeUserMemAccess::VerifyIsWritable(tp, sizeof(*tp)); *tp = tp64; } SYSCALL_ERRNO(); @@ -126,6 +135,7 @@ void RegisterTime(FEX::HLE::SyscallHandler* Handler) { struct timespec tp64 {}; uint64_t Result = ::clock_getres(clk_id, &tp64); if (tp) { + FaultSafeUserMemAccess::VerifyIsWritable(tp, sizeof(*tp)); *tp = tp64; } SYSCALL_ERRNO(); @@ -140,11 +150,13 @@ void RegisterTime(FEX::HLE::SyscallHandler* Handler) { struct timespec* rem64_ptr {}; if (request) { + FaultSafeUserMemAccess::VerifyIsReadable(request, sizeof(*request)); req64 = *request; req64_ptr = &req64; } if (remain) { + FaultSafeUserMemAccess::VerifyIsReadable(remain, sizeof(*remain)); rem64 = *remain; rem64_ptr = &rem64; } @@ -153,6 +165,7 @@ void RegisterTime(FEX::HLE::SyscallHandler* Handler) { uint64_t Result = ::syscall(SYSCALL_DEF(clock_nanosleep), clockid, flags, req64_ptr, rem64_ptr); if (remain && (flags & TIMER_ABSTIME) == 0) { + FaultSafeUserMemAccess::VerifyIsWritable(remain, sizeof(*remain)); // Remain is completely ignored if TIMER_ABSTIME is set. *remain = rem64; } @@ -166,6 +179,7 @@ void RegisterTime(FEX::HLE::SyscallHandler* Handler) { } uint64_t Result = 0; + FaultSafeUserMemAccess::VerifyIsReadable(tp, sizeof(*tp)); const struct timespec tp64 = *tp; Result = ::clock_settime(clockid, &tp64); SYSCALL_ERRNO(); @@ -174,6 +188,7 @@ void RegisterTime(FEX::HLE::SyscallHandler* Handler) { REGISTER_SYSCALL_IMPL_X32(futimesat, [](FEXCore::Core::CpuStateFrame* Frame, int dirfd, const char* pathname, const timeval32 times[2]) -> uint64_t { uint64_t Result = 0; if (times) { + FaultSafeUserMemAccess::VerifyIsReadable(times, sizeof(timeval32) * 2); struct timeval times64[2] {}; times64[0] = times[0]; times64[1] = times[1]; @@ -188,6 +203,7 @@ void RegisterTime(FEX::HLE::SyscallHandler* Handler) { utimensat, [](FEXCore::Core::CpuStateFrame* Frame, int dirfd, const char* pathname, const compat_ptr times, int flags) -> uint64_t { uint64_t Result = 0; if (times) { + FaultSafeUserMemAccess::VerifyIsReadable(times, sizeof(timeval32) * 2); timespec times64[2] {}; times64[0] = times[0]; times64[1] = times[1]; @@ -201,6 +217,7 @@ void RegisterTime(FEX::HLE::SyscallHandler* Handler) { REGISTER_SYSCALL_IMPL_X32(utimes, [](FEXCore::Core::CpuStateFrame* Frame, const char* filename, const timeval32 times[2]) -> uint64_t { uint64_t Result = 0; if (times) { + FaultSafeUserMemAccess::VerifyIsReadable(times, sizeof(timeval32) * 2); struct timeval times64[2] {}; times64[0] = times[0]; times64[1] = times[1]; @@ -212,10 +229,12 @@ void RegisterTime(FEX::HLE::SyscallHandler* Handler) { }); REGISTER_SYSCALL_IMPL_X32(adjtimex, [](FEXCore::Core::CpuStateFrame* Frame, compat_ptr buf) -> uint64_t { + FaultSafeUserMemAccess::VerifyIsReadable(buf, sizeof(*buf)); struct timex Host {}; Host = *buf; uint64_t Result = ::adjtimex(&Host); if (Result != -1) { + FaultSafeUserMemAccess::VerifyIsWritable(buf, sizeof(*buf)); *buf = Host; } SYSCALL_ERRNO(); @@ -223,10 +242,12 @@ void RegisterTime(FEX::HLE::SyscallHandler* Handler) { REGISTER_SYSCALL_IMPL_X32(clock_adjtime, [](FEXCore::Core::CpuStateFrame* Frame, clockid_t clk_id, compat_ptr buf) -> uint64_t { + FaultSafeUserMemAccess::VerifyIsReadable(buf, sizeof(*buf)); struct timex Host {}; Host = *buf; uint64_t Result = ::clock_adjtime(clk_id, &Host); if (Result != -1) { + FaultSafeUserMemAccess::VerifyIsWritable(buf, sizeof(*buf)); *buf = Host; } SYSCALL_ERRNO(); From cf7ee9883197dcf7a88252f5ddb4c88902512300 Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Wed, 28 Aug 2024 04:31:06 -0700 Subject: [PATCH 4/4] x32/Thread: Adds EFAULT handlers --- .../LinuxSyscalls/x32/Thread.cpp | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Thread.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Thread.cpp index dc770e6174..b752d4f704 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Thread.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Thread.cpp @@ -49,6 +49,8 @@ constexpr uint32_t TLS_MaxEntry = TLS_NextEntry + 3; uint64_t SetThreadArea(FEXCore::Core::CpuStateFrame* Frame, void* tls) { struct x32::user_desc* u_info = reinterpret_cast(tls); + FaultSafeUserMemAccess::VerifyIsReadable(u_info, sizeof(*u_info)); + if (u_info->entry_number == -1) { for (uint32_t i = TLS_NextEntry; i < TLS_MaxEntry; ++i) { auto GDT = &Frame->State.gdt[i]; @@ -106,6 +108,17 @@ void RegisterThread(FEX::HLE::SyscallHandler* Handler) { REGISTER_SYSCALL_IMPL_X32( clone, ([](FEXCore::Core::CpuStateFrame* Frame, uint32_t flags, void* stack, pid_t* parent_tid, void* tls, pid_t* child_tid) -> uint64_t { + // This is slightly different EFAULT behaviour, if child_tid or parent_tid is invalid then the kernel just doesn't write to the + // pointer. Still need to be EFAULT safe although. + if ((flags & (CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID)) && child_tid) { + FaultSafeUserMemAccess::VerifyIsWritable(child_tid, sizeof(*child_tid)); + } + + if ((flags & CLONE_PARENT_SETTID) && parent_tid) { + FaultSafeUserMemAccess::VerifyIsWritable(parent_tid, sizeof(*parent_tid)); + } + + FEX::HLE::clone3_args args {.Type = TypeOfClone::TYPE_CLONE2, .args = { .flags = flags & ~CSIGNAL, // This no longer contains CSIGNAL @@ -125,6 +138,7 @@ void RegisterThread(FEX::HLE::SyscallHandler* Handler) { REGISTER_SYSCALL_IMPL_X32(waitpid, [](FEXCore::Core::CpuStateFrame* Frame, pid_t pid, int32_t* status, int32_t options) -> uint64_t { uint64_t Result = ::waitpid(pid, status, options); + FaultSafeUserMemAccess::VerifyIsWritableOrNull(status, sizeof(*status)); SYSCALL_ERRNO(); }); @@ -143,6 +157,8 @@ void RegisterThread(FEX::HLE::SyscallHandler* Handler) { return -EINVAL; } + FaultSafeUserMemAccess::VerifyIsWritable(u_info, sizeof(*u_info)); + const auto& GDT = &Frame->State.gdt[Entry]; memset(u_info, 0, sizeof(*u_info)); @@ -178,6 +194,9 @@ void RegisterThread(FEX::HLE::SyscallHandler* Handler) { REGISTER_SYSCALL_IMPL_X32( get_robust_list, [](FEXCore::Core::CpuStateFrame* Frame, int pid, struct robust_list_head** head, uint32_t* len_ptr) -> uint64_t { + FaultSafeUserMemAccess::VerifyIsWritable(head, sizeof(uint32_t)); + FaultSafeUserMemAccess::VerifyIsWritable(len_ptr, sizeof(*len_ptr)); + auto ThreadObject = FEX::HLE::ThreadManager::GetStateObjectFromCPUState(Frame); // Give the robust list back to the application // Steam specifically checks to make sure the robust list is set @@ -192,6 +211,7 @@ void RegisterThread(FEX::HLE::SyscallHandler* Handler) { struct timespec tp64 {}; int cmd = futex_op & FUTEX_CMD_MASK; if (timeout && (cmd == FUTEX_WAIT || cmd == FUTEX_LOCK_PI || cmd == FUTEX_WAIT_BITSET || cmd == FUTEX_WAIT_REQUEUE_PI)) { + FaultSafeUserMemAccess::VerifyIsReadable(timeout, sizeof(*timeout)); // timeout argument is only handled as timespec in these cases // Otherwise just an integer tp64 = *timeout; @@ -211,17 +231,20 @@ void RegisterThread(FEX::HLE::SyscallHandler* Handler) { stack_t* old64_ptr {}; if (ss) { + FaultSafeUserMemAccess::VerifyIsReadable(ss, sizeof(*ss)); ss64 = *ss; ss64_ptr = &ss64; } if (old_ss) { + FaultSafeUserMemAccess::VerifyIsReadable(old_ss, sizeof(*old_ss)); old64 = *old_ss; old64_ptr = &old64; } uint64_t Result = FEX::HLE::_SyscallHandler->GetSignalDelegator()->RegisterGuestSigAltStack(ss64_ptr, old64_ptr); if (Result == 0 && old_ss) { + FaultSafeUserMemAccess::VerifyIsWritable(old_ss, sizeof(*old_ss)); *old_ss = old64; } return Result; @@ -291,11 +314,13 @@ void RegisterThread(FEX::HLE::SyscallHandler* Handler) { struct rusage* usage64_p {}; if (rusage) { + FaultSafeUserMemAccess::VerifyIsReadable(rusage, sizeof(*rusage)); usage64 = *rusage; usage64_p = &usage64; } uint64_t Result = ::wait4(pid, wstatus, options, usage64_p); if (rusage) { + FaultSafeUserMemAccess::VerifyIsWritable(rusage, sizeof(*rusage)); *rusage = usage64; } SYSCALL_ERRNO(); @@ -311,6 +336,7 @@ void RegisterThread(FEX::HLE::SyscallHandler* Handler) { siginfo_t* info64_p {}; if (rusage) { + FaultSafeUserMemAccess::VerifyIsReadable(rusage, sizeof(*rusage)); usage64 = *rusage; usage64_p = &usage64; } @@ -323,10 +349,12 @@ void RegisterThread(FEX::HLE::SyscallHandler* Handler) { if (Result != -1) { if (rusage) { + FaultSafeUserMemAccess::VerifyIsWritable(rusage, sizeof(*rusage)); *rusage = usage64; } if (info) { + FaultSafeUserMemAccess::VerifyIsWritable(info, sizeof(*info)); *info = info64; } }