Both waits re-checked the held sockets only before each host wait. A
close during the last slice, or one followed by a packet the retained
native socket then received, came back as a timeout or as readiness on
a descriptor that no longer exists. FreeBSD 11.4's pollrescan reports
POLLNVAL alone for such a descriptor.
The held sockets are now re-checked after every successful host wait as
well, select's socket group fails with EBADF, and poll reports POLLNVAL
without ORing in the native socket's readiness.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Both waits held the guest sockets they polled and handed the host one
poll call for the whole wait. A guest close dropped only the table entry,
so the native socket stayed open and the wait ran to its timeout: poll
returned 0 instead of POLLNVAL, and select reported EBADF only after its
next 100 ms re-lookup, or not at all when the timeout was shorter.
FreeBSD 11.4 wakes such a waiter and reports the closed descriptor.
Waits that include sockets now poll the host in slices of at most 10 ms
and, before each slice, check that every descriptor still maps to the
socket it held. A closed one answers POLLNVAL from poll and EBADF from
select.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
bind, getsockname, sendto and recvfrom validate as for a libkernel socket
before they reach libSceNet, so a forwarded descriptor reports the same
errors. recvfrom keeps its guest address handling and MSG_WAITALL, and a
zero-length datagram receive does not wait.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
A title can create a socket with sceNetSocket and then call bind, getsockname, sendto or recvfrom from libkernel, which does not hold that descriptor, so the call failed with EBADF. PPSA06866's RakNet does this, its local server fails to start and the load after difficulty selection never ends. libSceNet now registers these four calls with libkernel, as it does for setsockopt and getsockopt.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
On Windows, closing a pipe while another thread waited for it in select
terminated the process. The close releases the host handle before the C
runtime descriptor, so in between:
- the readiness query of the pipe failed on the dead handle and threw
'querying pipe descriptor ... failed';
- after that, DescriptorIsOpen still saw the descriptor mapped, select
looked it up again, found no known kind and threw 'is neither a
socket, a pipe, ...'.
QueryPipe now reports a descriptor whose handle is no longer a pipe as
not a pipe instead of throwing, DescriptorIsOpen on Windows also checks
that the mapped handle is still valid, and select answers EBADF for such
a descriptor before throwing for an unknown kind, as FreeBSD 11.4's
kern_select does for a descriptor closed during the wait.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
dup2 from a guest socket notified the event queues only when the
replaced descriptor was itself a guest socket. A kqueue replaced this
way stayed registered, so kevent on the number that now names the
socket still returned the old queue's events, and knotes registered on
a replaced pipe or file stayed attached. FreeBSD 11.4's kern_dup closes
the replaced file through closefp, whose knote_fdclose drops every
knote on the descriptor, as the other dup2 paths here already do.
Fixes#11429
Co-Authored-By: Claude Opus 5.5 <[email protected]>
ioctl(FIONBIO) on a guest socket read its int argument directly, while ioctl(FIONREAD) wrote its int result directly, so passing a non-null pointer into unmapped or read-only memory crashed the host with an access violation. FIONBIO and FIONREAD are _IOW and _IOR requests, which FreeBSD copies in and out using copyin and copyout, returning EFAULT on inaccessible memory. The argument is now safely checked using GuestCopyIn_nid_no_patch and GuestCopyOut_nid_no_patch.