Skip to content

Commit

Permalink
Merge pull request #4019 from Sonicadvance1/more_efault_handlers
Browse files Browse the repository at this point in the history
More EFAULT handlers
  • Loading branch information
alyssarosenzweig authored Sep 2, 2024
2 parents 4baeffe + cf7ee98 commit 62e1767
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 0 deletions.
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

0 comments on commit 62e1767

Please sign in to comment.