In a payload process on a PS5 (firmware 12.70), getrlimit returns
0x200000 for RLIMIT_STACK, infinity for RLIMIT_RSS and RLIMIT_MEMLOCK,
and 1604 for RLIMIT_NPROC, each as both soft and hard limit. These four
threw here. Whether a title process reads the same limits is not
measured.
setrlimit reads getrlimit first, so it now accepts RLIMIT_STACK,
RLIMIT_RSS and RLIMIT_MEMLOCK when the values do not change, as the
payload process does. RLIMIT_NPROC throws: in the payload process
setting it to its current value succeeds, but getrlimit then reads 1443,
and the limit is not stored here. Any other change still throws. The
getrlimit and setrlimit debt entries also record the payload process's
RLIMIT_DATA and RLIMIT_NOFILE readings, its 12555 clamp of RLIMIT_NOFILE
and its RLIMIT_NPROC reading after a same-value set.
AI-assisted: yes
Co-Authored-By: Claude Opus 5.5 <[email protected]>
FreeBSD 11.4 rejects access mode 3 in kern_openat and
O_CREAT|O_EXCL|O_DIRECTORY in vn_open_cred before namei reads the path
or resolves the directory descriptor. open, _open and openat checked a
NULL or empty path first and returned EFAULT or ENOENT for those flags.
InvalidOpenFlags moves to FileFlags.hpp and runs first in all three.
kevent threw for EV_CLEAR on a socket or the read end of a pipe; Boost.Asio's kqueue reactor, among others, registers every socket that way. On Linux such a knote now watches its host descriptor through an edge watch. It is armed when added, on every later EV_ADD or EV_ENABLE while enabled, and by each host wakeup; when armed it is checked with the level-triggered readiness test and reported with the current data and EV_EOF, or disarmed if no longer ready, as kqueue_scan re-runs the filter; reporting it disarms it until the next edge. Waits block on the watch's epoll descriptor, so a socket that stays readable does not wake them. Windows and macOS still throw. GuestSockets::NativeDescriptor exposes the host socket behind a guest one for the watch.
FreeBSD activates an EV_CLEAR knote on each state change the object reports through KNOTE (sorwakeup, sowwakeup, pipeselwakeup), not on its level, so polling the level cannot tell an EV_CLEAR knote when to fire again. EdgeWatch::Watch registers the host descriptor with a private epoll instance in edge-triggered mode: every wakeup of the descriptor with a matching mask (data arriving, buffer space freed, a hang-up) queues one edge, which TakeEdge consumes, and the epoll descriptor itself is readable while an edge is pending, so a wait can block on it. Off Linux opening a watch throws.
WaitForDescriptors always handed the knote's own descriptor to the host wait. A filter that tracks readiness through a descriptor of its own, such as an edge watch, needs the wait to block on that descriptor instead, or a descriptor that stays ready keeps waking the wait. KernelFilter gets a waitDescriptor, and the filter's owner is held for the length of the wait so the descriptor cannot be closed under it.
Address review: check the msghdr, iovec array, iovec bases and name
are mapped before MessageLength or the receive loop touches them,
pairing the HostWrite guard with committed-range validation. Add
regression tests for forged iovec-array and output pointers.
recvmsg_nid_postfix wrote the msghdr, every iovec base and the sender
address with only null checks, unlike recv_nid_postfix and the
sceNetRecvfrom sender outputs which all gate on GuestArena::HostWrite.
Validate the message, each iovec base and the name buffer the same way
so a forged pointer fails with EFAULT instead of writing received bytes
to an arbitrary host address.
getrlimit(RLIMIT_NOFILE) reports the host's limits, and libkernel
raised the soft limit to the hard one at load only on Linux. On macOS
the soft limit stayed below an unlimited hard limit (1048576 and
infinity in a shell here, 256 and infinity by default), so the two
differed. XPSemu (PPSA97358) then raises the soft limit to the hard one
in QEMU's os_setup_limits, and setrlimit refuses the change.
macOS fails with EMFILE at kern.maxfilesperproc (10240 here) whatever
the soft limit, even an unlimited one. At load, libkernel now sets both
limits to the smaller of the hard limit and kern.maxfilesperproc, so
getrlimit reports the descriptor count after which opening fails. The
Linux path still raises the soft limit to the hard one.
sceKernelFstat and fstat passed any descriptor to the UCRT's _fstat64, which
raises the invalid-parameter handler for one that is not open. The crash
report installs that handler as fatal, so the calling thread died where the
console returns EBADF. Dying Light 2 (PPSA02262) hits it on a loading thread
right after sign-in.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Operation 1 threw as unverified, so a title whose call_once path reaches it
stopped. In a payload process on a PS5 (firmware 12.70) operations 0 and 1
fail with EOPNOTSUPP and leave the word unchanged for every word tried,
as FreeBSD 11's __umtx_op_unimpl does. Answer operation 1 like operation 0.
A PS5 (firmware 13.60) reports CPU write 0x2 with CPU read 0x1, 0x80 with 0x40 and 0x200 with 0x100 after a map, sceKernelMprotect, sceKernelMtypeprotect or POSIX mprotect; GPU write 0x20 keeps GPU read 0x10 clear. sceKernelVirtualQuery and sceKernelQueryMemoryProtection now report the protection that way.