Repository navigation
feat(libkernel): pass descriptors in SCM_RIGHTS messages on Unix sockets - #7090
milescoviello wants to merge 5 commits into
Conversation
|
Other open pull requests touch the same code. Merging one will break the other, or both implement the same thing. If this one builds on them, list them in Depends on.
Some comparisons could not be completed because a pull request conflicts with the base branch. Review these shared files manually before concluding that there is no overlap.
|
sendmsg on a guest Unix-domain socket now takes FreeBSD SCM_RIGHTS control messages (SOL_SOCKET level, data at offset 16) and sends their descriptors with the host's SCM_RIGHTS; recvmsg receives them, installs received sockets as guest sockets and writes FreeBSD's control record back, truncated to the caller's buffer with MSG_CTRUNC. A closed descriptor returns EBADF, another level or an overlong record EINVAL. Windows, other control types, IP sockets and MSG_PEEK with a control buffer still throw. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…indows builds Windows never takes the SCM_RIGHTS path, so the received descriptors and the truncation flag are declared only where they are used. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
b89d198 to
4cd70d4
Compare
|
This doesn't compile on Windows (head
AI-assisted: yes (Claude Code); results above were run on this machine. |
…ilds too recvmsg masks MSG_CMSG_CLOEXEC on every host, but its constant was declared inside the block that only non-Windows builds compile, so the Windows build stopped on an undeclared GuestControlCloseOnExec. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Thanks @wachi35676, that's right. 17d9e0a declares Checked here with MinGW-w64 ( AI-assisted: yes (Claude Code) |
|
Windows build of head
Titles: PPSA99030 is not available here. Not checked: the descriptor passing itself (Linux only, Written with Claude Code assistance (validation by a subagent, reviewed in this session). |
|
Thanks @screamm for the full Windows build, the control and the probe. I added it to the description. AI-assisted: yes (Claude Code) |
jotitadev
left a comment
There was a problem hiding this comment.
macOS build note on head 17d9e0a51.
The new code sits under #ifndef _WIN32, so it is also compiled on macOS hosts, but two of its identifiers do not exist in XNU's headers:
core/libs/prx/libkernel/Socket/src/Udp.cpp:1315:getsockopt(native, SOL_SOCKET, SO_DOMAIN, ...). macOS has noSO_DOMAIN.core/libs/prx/libkernel/Socket/src/Udp.cpp:1396:MSG_CMSG_CLOEXEC. macOS has no such recv flag.
Repro on an M2 Max (macOS 27.2, Apple clang 21.0.0, arm64): merging this head onto #7332 (b182750ca, the PR that builds libkernel on macOS) is conflict-free. A -fsyntax-only compile of the merged Udp.cpp then fails with exactly these two errors:
Udp.cpp:1421:42: error: use of undeclared identifier 'SO_DOMAIN'
Udp.cpp:1502:122: error: use of undeclared identifier 'MSG_CMSG_CLOEXEC'
The same file from #7332 alone compiles cleanly. The line numbers above are in the merged file; the lines in this PR are 1315 and 1396. guest_socket_rights is registered under if(NOT WIN32), so it would be built on macOS too.
Suggestion that keeps one path for both Unix hosts:
- Take the family from
getsockname()(sockaddr_storage::ss_family) instead ofSO_DOMAIN. On macOS this returnsAF_UNIXfor asocketpairend andAF_INET6for an unbound IPv6 socket, andSO_TYPEworks as it is. - Drop
MSG_CMSG_CLOEXECand setFD_CLOEXECwithfcntlon each received descriptor when the guest asked for it, beforeInstallPassed. Alternatively, guard the flag with#ifdef MSG_CMSG_CLOEXECand use thefcntlpath otherwise.
Not checked: running guest_socket_rights on macOS. The full libs build on macOS needs #7332 and an x86-64 build, which I could not run here.
AI-assisted: yes (Claude Code)
…ut Linux-only names macOS has no SO_DOMAIN socket option and no MSG_CMSG_CLOEXEC receive flag, so the descriptor-passing code didn't compile there. A received socket's family now comes from getsockname, and where the receive flag doesn't exist the received descriptors are marked close-on-exec with fcntl when the guest asked for it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
@jotitadev thanks, both are right. I took your first suggestion and the
I'm running AI-assisted: yes (Claude Code) |
|
@milescoviello thanks. M2 Max, macOS 27.2, Apple clang 21.0.0. Base: #7332 at
One gap in the test: it never checks close-on-exec on the received host descriptor. The only
So your forced-fallback run on Linux will pass whether or not the Not checked: your actual aff8c2a, arm64 runtime (the libs build is x86-64 only on macOS). Written with AI assistance (Claude Code). I ran the builds and tests above on my machine. |
The only MSG_CMSG_CLOEXEC case received sockets, whose F_GETFD reads the guest's close-on-exec set, so it passed whether or not the received host descriptor was marked. A pipe end goes through unchanged, so receiving one with the flag now has to read back FD_CLOEXEC. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
@jotitadev thanks, and sorry the commit wasn't up yet when you looked. Both are pushed now:
You're right that my forced-fallback run proved nothing before that check. With it, on Linux (Ubuntu 24.04, GCC 13.3):
A run of AI-assisted: yes (Claude Code) |
What
sendmsgthrewcontrol data is not supportedfor any control buffer. Wine passes descriptors to and from its wineserver this way, so Forever Launcher's in-process Wine (PPSA99030) stops on it. On a guest Unix-domain socket,SCM_RIGHTScontrol messages now pass descriptors, as FreeBSD 11'sunp_internalizeandunp_externalizedo.sendmsg: reads FreeBSD's layout: a 12-bytecmsghdrwith the descriptors at offset 16, and recordsCMSG_SPACEbytes apart. It sends the descriptors with the host'sSCM_RIGHTS, because a guest descriptor here is a host descriptor (a guest socket's number is a duplicate of its host socket).EBADFfor a descriptor that is not open, andEINVALfor a level other thanSOL_SOCKETor a record longer than the buffer.recvmsgwith a control buffer: receives with the host'sSCM_RIGHTS. A received socket is installed as a guest socket (family and type fromSO_DOMAIN/SO_TYPE); any other descriptor is used as it is.CMSG_LENincmsg_lenandCMSG_SPACEbytes, truncated to the caller's buffer withMSG_CTRUNC, askern_recvitcopies it.MSG_CMSG_CLOEXECmarks the received descriptors close-on-exec.SCM_RIGHTS, control data on IP sockets, andMSG_PEEKwith a control buffer. The debt entry says so.Tested
Ubuntu 24.04, GCC 13.3, Release, on
main673f740. The PR is rebased onto 864729d, whose two newer commits touch neither libkernel nor its tests.guest_socket_rightstest (Linux), over a stream socket pair:MSG_CMSG_CLOEXEC, and checks that both received sockets are close-on-exec and send and receive.MSG_CMSG_CLOEXECand checks that the received host descriptor is close-on-exec. A pipe end goes through unchanged, so this reads the host flag, while the sockets' check reads the guest's close-on-exec set.MSG_CTRUNC, and a receive without a control buffer gets the data only.EBADF, and another level or an overlong record givesEINVAL.main'sUdp.cppit aborts onsendmsg: control data is not supported. It passes 3 of 3, withguest_socket_pairtoo.ctest -R '^guest_|libc': 402 of 402 pass.sendmsgon a socket-pair end withMSG_NOSIGNAL | MSG_DONTWAIT, one byte of data and a 24-byte control buffer holding oneSOL_SOCKET/SCM_RIGHTSrecord (cmsg_len20) that passes the end of another socket pair.mainwith the PRs for its earlier stops merged locally (feat(libkernel): declare physhm_open and physhm_unlink #6915, fix(libkernel): export sysarch so modules that import it load #6028, fix(libSceSystemService): declare the PsmKit local process exports #6939, feat(libSceKeyboard): export missing firmware functions from database #6787, feat(libkernel): report the guest address-space map through kern.proc.vmmap #7070, fix(memory): honor low guest mapping hints #6469), it stops at 0 s onsendmsg: control data is not supported, 2 of 2.kevent: NOTE_LOWAT(wineserver's kqueue registersEVFILT_READandEVFILT_WRITEwithNOTE_LOWAT1). That is a separate PR.NOTE_LOWAT) merged, that next stop is gone. Onmain98c251f with feat(libkernel): declare physhm_open and physhm_unlink #6915, fix(libSceSystemService): declare the PsmKit local process exports #6939, feat(libSceKeyboard): export missing firmware functions from database #6787, feat(libkernel): report the guest address-space map through kern.proc.vmmap #7070, fix(memory): honor low guest mapping hints #6469 and this PR (17d9e0a), Forever Launcher runs the whole 60 s in 2 of 2 runs with no unimplemented call. Its first-start prefix setup then reportstitle wineboot skipped; prefix must be initialized by payload Wineandfailed to open "C:\\windows\\system32\\wineboot.exe", and Wine exits with 0xC0000135, the launcher's "Setting up the Windows files did not finish". I read that as the launcher's own setup, not a missing emulator call, but I haven't looked further.Udp.cppdid not compile there:GuestControlCloseOnExecwas declared inside the non-Windows block. 17d9e0a moves the declaration out of it. A MinGW-w64-fsyntax-onlycompile ofUdp.cppstops on that line before and passes after, and the 11 socket tests and 411^guest_tests pass again on Linux. @screamm then built head 17d9e0a516 on Windows (Windows 11, WinLibs GCC 15.2.0, full build andlibs). Moving the declaration back reproduces the compile error, and the 35 Windows socket, poll, select, rudp, equeue and kqueue tests pass 3 of 3. On Windows,sendmsgwith anSCM_RIGHTSbuffer still stops withcontrol data is not supported on Windows, as this PR intends. None of their local titles sends or receives such a message.SO_DOMAINandMSG_CMSG_CLOEXECdon't exist in XNU's headers, soUdp.cppdidn't compile on top of feat: macOS on Apple Silicon host support (Rosetta 2 and MoltenVK) #7332. aff8c2a takes the received socket's family fromgetsockname(). WhereMSG_CMSG_CLOEXECdoesn't exist, it marks each received descriptor withfcntl(F_SETFD, FD_CLOEXEC)when the guest asked for it. Their local equivalent compiled with-Wall -Wextraon arm64 and x86_64, andguest_socket_rightspassed 5 of 5 under Rosetta. They also found that the test didn't check the host flag, so a3b3801 adds the pipe-end case above. On Linux the head passes 3 of 3, and so does a build with the receive flag forced to 0, through thefcntlpath. With the flag forced to 0 and thefcntlloop removed, the test fails.^guest_|libcpassed 411 of 411 on aff8c2a.Checklist
main; no other open PR implements the same functionsNotImplemented_nid_no_patch); silent stubs are listed under Silent stubs in their library's technical debt file.mdfiles or images added to the repository (attach them to this PR)🤖 Generated with Claude Code