Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

More EFAULT handlers #4019

Merged
merged 4 commits into from
Sep 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Thread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<struct x32::user_desc*>(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];
Expand Down Expand Up @@ -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
Expand All @@ -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();
});

Expand All @@ -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));
Expand Down Expand Up @@ -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
Expand All @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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();
Expand All @@ -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;
}
Expand All @@ -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;
}
}
Expand Down
21 changes: 21 additions & 0 deletions Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Time.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand All @@ -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();
Expand All @@ -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;
}
Expand All @@ -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();
Expand All @@ -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;
}
Expand All @@ -95,19 +100,22 @@ 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 {
Result = ::nanosleep(nullptr, rem64_ptr);
}

if (rem) {
FaultSafeUserMemAccess::VerifyIsWritable(rem, sizeof(*rem));
*rem = rem64;
}
SYSCALL_ERRNO();
Expand All @@ -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();
Expand All @@ -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();
Expand All @@ -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;
}
Expand All @@ -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;
}
Expand All @@ -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();
Expand All @@ -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];
Expand All @@ -188,6 +203,7 @@ void RegisterTime(FEX::HLE::SyscallHandler* Handler) {
utimensat, [](FEXCore::Core::CpuStateFrame* Frame, int dirfd, const char* pathname, const compat_ptr<timespec32> 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];
Expand All @@ -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];
Expand All @@ -212,21 +229,25 @@ void RegisterTime(FEX::HLE::SyscallHandler* Handler) {
});

REGISTER_SYSCALL_IMPL_X32(adjtimex, [](FEXCore::Core::CpuStateFrame* Frame, compat_ptr<FEX::HLE::x32::timex32> 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();
});

REGISTER_SYSCALL_IMPL_X32(clock_adjtime,
[](FEXCore::Core::CpuStateFrame* Frame, clockid_t clk_id, compat_ptr<FEX::HLE::x32::timex32> 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();
Expand Down
7 changes: 7 additions & 0 deletions Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Timer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -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();
});
Expand All @@ -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();
Expand All @@ -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;
}
Expand All @@ -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();
Expand All @@ -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<FEX::HLE::x32::sigevent32> 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();
Expand Down
12 changes: 12 additions & 0 deletions Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Thread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 =
Expand All @@ -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);
});

Expand Down
Loading