Files
AnyPS5/core/libs/tests/GuestOutputPointerFault.cpp
T
4ab16365fb fix(libc): check the guest read on macOS and pin the setitimer order
GuestCopyIn_nid_no_patch fell through to a plain memcpy on macOS, so an
unreadable pointer was dereferenced in the host. Read with
mach_vm_read_overwrite and require KERN_SUCCESS and a full copy, the
mirror of the mach_vm_write branch in GuestCopyOut_nid_no_patch and of
CopyGuestBytes.

The test now also checks the order FreeBSD 11.4 uses in sys_setitimer
(sys/kern/kern_time.c:803-808): the new timer is set first and the old
value is copied out afterwards, so a failing copyout reports EFAULT and
leaves the timer armed. The macOS branch has not been run.

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Co-authored-by: AdnanKhan-ak47 <[email protected]>
2026-10-25 13:40:56 +01:00

65 lines
2.7 KiB
C++

#include "prx/libc/include/Api.hpp"
#include "prx/libkernel/Time/include/Time.hpp"
#include "prx/libkernel/include/Api.hpp"
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <initializer_list>
static void Check(bool value, int line) {
if (!value) {
std::fprintf(stderr, "output pointer check failed at line %d\n", line);
std::abort();
}
}
#define Require(value) Check((value), __LINE__)
static constexpr int GuestEfault = 14;
static constexpr int KernelEfault = static_cast<int>(0x8002000Eu);
static bool Efault(int result) {
return result == -1 && *__error_nid_postfix() == GuestEfault;
}
int main() {
alignas(8) unsigned char valid[512]{};
alignas(8) unsigned char zeroTimer[32]{};
auto* timeValid = reinterpret_cast<KernelTimeval*>(valid);
auto* zoneValid = reinterpret_cast<KernelTimezone*>(valid + 32);
auto* timerValid = reinterpret_cast<GuestItimerval*>(valid);
auto* zeroTimerValue = reinterpret_cast<const GuestItimerval*>(zeroTimer);
for (const std::uintptr_t address : {std::uintptr_t{1}, ~std::uintptr_t{0xfff}}) {
void* bad = reinterpret_cast<void*>(address);
auto* badTime = reinterpret_cast<KernelTimeval*>(address);
auto* badZone = reinterpret_cast<KernelTimezone*>(address);
auto* badTimer = reinterpret_cast<GuestItimerval*>(address);
*__error_nid_postfix() = 0;
*__error_nid_postfix() = 0;
*__error_nid_postfix() = 0;
Require(Efault(gettimeofday_nid_postfix(badTime, nullptr)));
*__error_nid_postfix() = 0;
Require(Efault(gettimeofday_nid_postfix(timeValid, badZone)));
*__error_nid_postfix() = 0;
Require(Efault(getitimer_nid_postfix(0, badTimer)));
*__error_nid_postfix() = 0;
Require(Efault(setitimer_nid_postfix(0, zeroTimerValue, badTimer)));
*__error_nid_postfix() = 0;
Require(Efault(setitimer_nid_postfix(0, badTimer, timerValid)));
Require(sceKernelGettimeofday(badTime) == KernelEfault);
Require(sceKernelGettimezone(badZone) == KernelEfault);
}
Require(gettimeofday_nid_postfix(timeValid, zoneValid) == 0);
Require(getitimer_nid_postfix(0, timerValid) == 0);
Require(setitimer_nid_postfix(0, zeroTimerValue, timerValid) == 0);
GuestItimerval armed{};
armed.value.tv_sec = 3600;
*__error_nid_postfix() = 0;
Require(Efault(setitimer_nid_postfix(0, &armed, reinterpret_cast<GuestItimerval*>(~std::uintptr_t{0xfff}))));
GuestItimerval current{};
Require(getitimer_nid_postfix(0, &current) == 0 && current.value.tv_sec > 0);
Require(setitimer_nid_postfix(0, zeroTimerValue, nullptr) == 0);
Require(sceKernelGettimeofday(timeValid) == 0);
Require(sceKernelGettimezone(zoneValid) == 0);
}