Skip to content

feat(libkernel): keep the SIGIO owner of a pipe for F_GETOWN and F_SETOWN - #9557

Open
DavidSamir wants to merge 3 commits into
boykopovar:mainfrom
DavidSamir:feat/libkernel-fcntl-sigio-owner
Open

DavidSamir wants to merge 3 commits into
boykopovar:mainfrom
DavidSamir:feat/libkernel-fcntl-sigio-owner

Conversation

@DavidSamir

Copy link
Copy Markdown
Contributor

What

fcntl threw for F_GETOWN and F_SETOWN on every descriptor, and ioctl threw for FIOGETOWN and FIOSETOWN. They now follow FreeBSD 11:

  • What FreeBSD does: kern_fcntl turns F_GETOWN and F_SETOWN into fo_ioctl(FIOGETOWN/FIOSETOWN) (sys/kern/kern_descrip.c:579-598).
  • On a pipe: pipe_ioctl keeps the end's SIGIO owner through fsetown and fgetown (sys/kern/sys_pipe.c:1392-1399, kern_descrip.c:1043 and :1148). Here:
    • 0 clears the owner;
    • the guest's pid, or its negation (the guest leads its own process group), is stored;
    • any other value gives ESRCH, as pfind/pgfind find no such process or group;
    • the owner belongs to the open file, so dup, dup2 and F_DUPFD share it.
  • On a file, a directory or a file read from app0.zar: all four fail with ENOTTY, as vn_ioctl hands them to VOP_IOCTL (sys/kern/vfs_vnops.c:1488).
  • Still throwing: character devices and the random device, which aren't modelled.

No SIGIO is ever sent. O_ASYNC still throws, so a stored owner never implies a signal. The owner is kept in a weak_ptr map keyed on the descriptor's shared status object, which leaves the descriptor table's Entry and ShareDescriptor unchanged. tcgetpgrp/tcsetpgrp on a pipe (TIOCGPGRP/TIOCSPGRP) will follow in a separate PR.

Tested

Windows 11 Pro 26200, WinLibs GCC 15.2.0 r7, Release. This is CPU-side, so no GPU is involved.

New test guest_kernel_fcntl_owner (core/libs/tests/GuestKernelFcntlOwner.cpp), which covers:

  • Pipes: an owner of 0 at first; set, get and clear; ESRCH for pid + 1 and -(pid + 1) with the owner kept; sharing through dup; the other end staying independent; the FIOSETOWN/FIOGETOWN forms, including EFAULT for a NULL FIOGETOWN argument.
  • A file and a directory: ENOTTY from all four requests.
  • A closed descriptor: EBADF.

Results:

Checklist

  • Based on current main; no other open PR implements the same functions
  • One topic per PR; follow-ups go in a new PR
  • No comments in code except technical debt
  • Unimplemented paths throw (NotImplemented_nid_no_patch); silent stubs are listed under Silent stubs in their library's technical debt file
  • No notes, investigation .md files or images added to the repository (attach them to this PR)
  • New third-party code is a submodule built from source
  • Generic behaviour, not specific to one title
  • Depends on: none
  • Fixes: none
  • Unblocks: none
  • GPUs tested: n/a
  • AI-assisted: yes

@github-actions

github-actions Bot commented Oct 22, 2026 •

Copy link
Copy Markdown

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.

Pull request Shared files not compared
PR 4563 core/libs/prx/libkernel/CMakeLists.txt
PR 4630 docs/dev/debt/libkernel.md
PR 5021 core/libs/prx/libkernel/CMakeLists.txt
docs/dev/debt/libkernel.md
PR 6149 core/libs/prx/libkernel/CMakeLists.txt
docs/dev/debt/libkernel.md
PR 6740 docs/dev/debt/libkernel.md
PR 6936 core/libs/prx/libkernel/CMakeLists.txt
docs/dev/debt/libkernel.md
PR 7088 docs/dev/debt/libkernel.md
PR 7105 docs/dev/debt/libkernel.md
PR 7121 core/libs/prx/libkernel/File/src/DescriptorControl.cpp
docs/dev/debt/libkernel.md
PR 7135 docs/dev/debt/libkernel.md
PR 7149 docs/dev/debt/libkernel.md
PR 7156 core/libs/prx/libkernel/CMakeLists.txt
PR 7192 core/libs/prx/libkernel/CMakeLists.txt
docs/dev/debt/libkernel.md
PR 7447 docs/dev/debt/libkernel.md
PR 7464 docs/dev/debt/libkernel.md
PR 7532 core/libs/prx/libkernel/CMakeLists.txt
docs/dev/debt/libkernel.md
PR 7565 docs/dev/debt/libkernel.md
PR 7645 core/libs/prx/libkernel/CMakeLists.txt
PR 7804 docs/dev/debt/libkernel.md
PR 8041 core/libs/prx/libkernel/CMakeLists.txt
PR 8463 core/libs/prx/libkernel/CMakeLists.txt
PR 8497 docs/dev/debt/libkernel.md
PR 8605 docs/dev/debt/libkernel.md
PR 9019 core/libs/prx/libkernel/CMakeLists.txt
core/libs/prx/libkernel/File/src/DescriptorControl.cpp
PR 9199 docs/dev/debt/libkernel.md
PR 9326 core/libs/prx/libkernel/CMakeLists.txt
docs/dev/debt/libkernel.md
PR 9389 core/libs/prx/libkernel/CMakeLists.txt
docs/dev/debt/libkernel.md
PR 9684 core/libs/prx/libkernel/CMakeLists.txt
docs/dev/debt/libkernel.md
PR 9843 docs/dev/debt/libkernel.md
PR 9938 core/libs/prx/libkernel/CMakeLists.txt
docs/dev/debt/libkernel.md
PR 9947 core/libs/prx/libkernel/CMakeLists.txt
docs/dev/debt/libkernel.md
PR 9994 core/libs/prx/libkernel/File/src/DescriptorControl.cpp
PR 10016 core/libs/prx/libkernel/File/src/DescriptorControl.cpp
PR 10025 docs/dev/debt/libkernel.md
PR 10192 docs/dev/debt/libkernel.md
PR 10319 docs/dev/debt/libkernel.md
PR 10442 docs/dev/debt/libkernel.md
PR 10558 docs/dev/debt/libkernel.md
PR 10645 core/libs/prx/libkernel/CMakeLists.txt
docs/dev/debt/libkernel.md
PR 10749 core/libs/prx/libkernel/CMakeLists.txt
docs/dev/debt/libkernel.md
PR 10806 core/libs/prx/libkernel/CMakeLists.txt
PR 11002 core/libs/prx/libkernel/CMakeLists.txt
docs/dev/debt/libkernel.md
PR 11215 docs/dev/debt/libkernel.md
PR 11219 core/libs/prx/libkernel/File/src/DescriptorControl.cpp
docs/dev/debt/libkernel.md
PR 11223 docs/dev/debt/libkernel.md
PR 11247 docs/dev/debt/libkernel.md
PR 11446 core/libs/prx/libkernel/CMakeLists.txt
PR 11624 docs/dev/debt/libkernel.md
PR 11625 core/libs/prx/libkernel/CMakeLists.txt
docs/dev/debt/libkernel.md
PR 11628 docs/dev/debt/libkernel.md
PR 11661 docs/dev/debt/libkernel.md
PR 11689 docs/dev/debt/libkernel.md
PR 11698 docs/dev/debt/libkernel.md
PR 11831 core/libs/prx/libkernel/CMakeLists.txt
PR 11891 core/libs/prx/libkernel/CMakeLists.txt
PR 11894 core/libs/prx/libkernel/CMakeLists.txt
PR 11896 core/libs/prx/libkernel/CMakeLists.txt
docs/dev/debt/libkernel.md
PR 11939 core/libs/prx/libkernel/CMakeLists.txt
docs/dev/debt/libkernel.md
PR 12104 docs/dev/debt/libkernel.md
PR 12139 core/libs/prx/libkernel/CMakeLists.txt
PR 12149 core/libs/prx/libkernel/CMakeLists.txt
PR 12170 docs/dev/debt/libkernel.md
PR 12544 core/libs/prx/libkernel/CMakeLists.txt
PR 12560 docs/dev/debt/libkernel.md
PR 12682 core/libs/prx/libkernel/CMakeLists.txt
core/libs/prx/libkernel/File/src/DescriptorControl.cpp
docs/dev/debt/libkernel.md
PR 12688 core/libs/prx/libkernel/CMakeLists.txt
core/libs/prx/libkernel/File/src/DescriptorControl.cpp
docs/dev/debt/libkernel.md
PR 12700 core/libs/prx/libkernel/CMakeLists.txt
core/libs/prx/libkernel/File/src/DescriptorControl.cpp
docs/dev/debt/libkernel.md
PR 12854 docs/dev/debt/libkernel.md
PR 12965 core/libs/prx/libkernel/CMakeLists.txt
core/libs/prx/libkernel/File/src/DescriptorControl.cpp
docs/dev/debt/libkernel.md
PR 12970 core/libs/prx/libkernel/CMakeLists.txt
docs/dev/debt/libkernel.md
PR 13336 docs/dev/debt/libkernel.md
PR 13504 docs/dev/debt/libkernel.md
PR 13506 docs/dev/debt/libkernel.md
PR 13560 docs/dev/debt/libkernel.md
PR 13582 docs/dev/debt/libkernel.md
PR 13587 docs/dev/debt/libkernel.md
PR 13695 docs/dev/debt/libkernel.md
PR 13950 docs/dev/debt/libkernel.md
PR 13953 docs/dev/debt/libkernel.md
PR 13964 docs/dev/debt/libkernel.md
PR 13995 docs/dev/debt/libkernel.md
PR 14039 docs/dev/debt/libkernel.md
PR 14043 docs/dev/debt/libkernel.md
PR 14085 docs/dev/debt/libkernel.md
PR 14103 docs/dev/debt/libkernel.md
PR 14105 docs/dev/debt/libkernel.md
PR 14108 docs/dev/debt/libkernel.md
PR 14111 core/libs/prx/libkernel/CMakeLists.txt
docs/dev/debt/libkernel.md
PR 14128 docs/dev/debt/libkernel.md
PR 14183 docs/dev/debt/libkernel.md
PR 14190 docs/dev/debt/libkernel.md
PR 14206 docs/dev/debt/libkernel.md
PR 14212 docs/dev/debt/libkernel.md
PR 14264 core/libs/prx/libkernel/CMakeLists.txt
docs/dev/debt/libkernel.md
PR 14272 core/libs/prx/libkernel/CMakeLists.txt
PR 14299 core/libs/prx/libkernel/CMakeLists.txt
PR 14310 docs/dev/debt/libkernel.md
PR 14320 docs/dev/debt/libkernel.md
PR 14324 docs/dev/debt/libkernel.md
PR 14325 docs/dev/debt/libkernel.md
PR 14417 docs/dev/debt/libkernel.md
PR 14493 docs/dev/debt/libkernel.md
PR 14497 docs/dev/debt/libkernel.md
PR 14557 core/libs/prx/libkernel/CMakeLists.txt
PR 14566 core/libs/prx/libkernel/CMakeLists.txt
PR 14710 docs/dev/debt/libkernel.md
PR 14756 docs/dev/debt/libkernel.md
PR 14832 docs/dev/debt/libkernel.md
PR 14841 core/libs/prx/libkernel/CMakeLists.txt
PR 14854 docs/dev/debt/libkernel.md
PR 14875 docs/dev/debt/libkernel.md
PR 14876 docs/dev/debt/libkernel.md
PR 14885 docs/dev/debt/libkernel.md
PR 14886 docs/dev/debt/libkernel.md
PR 14894 docs/dev/debt/libkernel.md
PR 14970 core/libs/prx/libkernel/CMakeLists.txt
PR 15030 docs/dev/debt/libkernel.md
PR 15035 docs/dev/debt/libkernel.md
PR 15037 docs/dev/debt/libkernel.md
PR 15040 docs/dev/debt/libkernel.md
PR 15041 docs/dev/debt/libkernel.md
PR 15046 core/libs/prx/libkernel/CMakeLists.txt
PR 15064 core/libs/prx/libkernel/CMakeLists.txt
docs/dev/debt/libkernel.md
PR 15095 core/libs/prx/libkernel/CMakeLists.txt
docs/dev/debt/libkernel.md

@MarcZX10 MarcZX10 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The owner state and focused pipe tests are coherent on inspection, but there is a concrete invalid-pointer gap in the ioctl path: FIOSETOWN directly dereferences argument (*static_cast<const int*>(argument)) before validating it. FIOGETOWN explicitly returns EFAULT for a null output pointer, while FIOSETOWN with null can fault the host instead of returning guest EFAULT. Please add checked copy-in for the four-byte input (including an unreadable non-null pointer) and a regression test, matching the checked output handling. Also, the overlap report flags live shared debt edits in #9256, #8544 and #9109; those authors must agree the ordering and preserve each debt change, with a Depends on entry if sequencing is required. Finally this branch is based on 8c26eac3, 23 commits behind current main dce41a89478876a8e3ea9c346b1dac00bb31c8cd; please update and rerun relevant tests before approval. Hosted policy checks pass, product build jobs are skipped; Windows test evidence in the body is author-reported and I did not run it locally.

@harisibrar1 harisibrar1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Checked against main 4a17c71 and FreeBSD releng/11.4 (sys/kern/sys_pipe.c:1392-1410, sys/kern/kern_descrip.c:1043-1148, sys/fs/fifofs/fifo_vnops.c):

  • The owner rules match fsetown/fgetown: 0 clears, ESRCH keeps the old owner, and the owner is per open file and shared by dup. The weak_ptr map is reset correctly by pipe() and close().
  • A small correction on the FIOSETOWN NULL point: Ioctl already returns EFAULT for a NULL IOC_IN argument at DescriptorControl.cpp:559, before the dereference at :581. Only a non-NULL unreadable pointer gets through, and FIONBIO on main does the same. A checked copy-in would be nice for both, plus a test that NULL FIOSETOWN gives EFAULT, which isn't covered yet.
  • On Linux/macOS, a host socket that is not a guest socket is classified as Kind::Socket, so F_GETOWN/F_SETOWN on it throw. The debt sentence only names the character device and random device. Could you add that case?
  • On FreeBSD all opens of a FIFO share one pipe_sigio (fifo_vnops.c passes fip->fi_pipe to every open). Here two open()s of the same host FIFO keep separate owners. Worth a short debt note.

Reviewed with AI assistance (Claude Code); the checks above were run locally on my machine.

…cked read

FIOSETOWN and FIONBIO read their int argument by dereferencing the guest
pointer, so an unreadable non-null pointer faulted the host instead of
failing with EFAULT. Both now copy the int in with ReadProcessMemory,
process_vm_readv or mach_vm_read_overwrite. The owner test covers a null
and an unreadable argument. The debt line notes that a host socket that is
not a guest socket still throws, and that two opens of one FIFO keep
separate owners.
@DavidSamir

Copy link
Copy Markdown
Contributor Author

Thanks @MarcZX10 and @harisibrar1. New commits, no force-push:

  • 4aa8b79b25: FIOSETOWN and FIONBIO now copy their int argument in with a checked read: ReadProcessMemory on Windows, process_vm_readv on Linux, mach_vm_read_overwrite on macOS, the same as Stdio.cpp's CopyIovecs. An unreadable non-null pointer fails with EFAULT instead of faulting the host. As @harisibrar1 noted, a null argument already got EFAULT at the IOC_IN check, but no test covered it.
    • guest_kernel_fcntl_owner now checks FIOSETOWN with nullptr and with an unreadable pointer (0x10), each giving EFAULT with the owner unchanged, and FIONBIO with the unreadable pointer.
    • Negative control: with the direct dereference put back, the test dies with 0xc0000005.
    • The debt line now also says that F_GETOWN/F_SETOWN on a host socket that is not a guest socket still throw (Linux and macOS), and that two opens of one FIFO keep separate owners, where FreeBSD shares pipe_sigio.
  • f8698a0b66: merges current main (d6eafa54d0).

Re-run on the merge (Windows 11, WinLibs GCC 15.2): guest_kernel_fcntl, guest_kernel_fcntl_owner, guest_terminal and guest_append_writes pass, and check_conventions.py reports 0 errors. Its one warning is the fcntl debt entry, already over the limit on main.

For the debt-row overlaps (#9256, #8544, #9109), I'm asking those authors for an order and will record it in the checklist.

AI-assisted: yes

@MarcZX10

Copy link
Copy Markdown
Contributor

The checked copy-in for FIOSETOWN/FIONBIO and the added debt notes address the concrete feedback from the earlier review; the author-reported Windows focused tests pass. I checked this head against current upstream/main: the merge is clean and no intervening main commit changes DescriptorControl.cpp, the new owner test, or the debt file, but it remains 3 ahead/11 behind (merge base d6eafa5). Please update to current main and rerun the focused fcntl/owner tests and conventions. The debt-line length is still reported as a warning by conventions (0 errors). The shared debt edit also needs recorded agreement with #9256, #8544, #9109 and the adjacent #9561 update; please add Depends on where an order is required. I found the order proposal to #9256, but no confirmation from the affected author yet. Product and relinker jobs are skipped; I did not run tests locally because the filesystem is full.

@MarcZX10 MarcZX10 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The invalid-pointer safety issue is addressed, and the author reports the focused Windows tests passing. The remaining blockers are repository integration requirements: this branch is 3 ahead/11 behind current upstream/main 4777cac (merge base d6eafa5), so update and rerun relevant tests; and record merge-order agreement for the shared libkernel debt edit with #9256, #8544, #9109 and #9561, declaring Depends on if required. Conventions reports 0 errors with the inherited long debt-row warning. Hosted product/relinker tests are skipped. I did not run tests locally because the filesystem is full.

@harisibrar1 harisibrar1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rechecked at f8698a0:

  • FIOSETOWN and FIONBIO now copy their argument in through ReadGuestInt (DescriptorControl.cpp:554-574). It follows main's CopyIovecs checks (null and wrap, then ReadProcessMemory / process_vm_readv / mach_vm_read_overwrite with a full-length check), so an unreadable pointer gives EFAULT and the owner is left unchanged. The new nullptr and 0x10 cases in GuestKernelFcntlOwner cover both.
  • The fcntl debt entry now covers the host socket on Linux/macOS and the per-open FIFO owner. All my points are addressed, thanks.

Reviewed with AI assistance (Claude Code); the checks above were run locally on my machine.

@oneandonlydean

Copy link
Copy Markdown
Collaborator

@DavidSamir thanks for this one. It conflicts with main in core/libs/prx/libkernel/File/src/DescriptorControl.cpp and docs/dev/debt/libkernel.md, so it needs a rebase. After it, please rerun guest_kernel_fcntl_owner.

@Gruzzberry

Copy link
Copy Markdown
Contributor

#15081 changes the guest flock copy-in at the top of RecordLock in DescriptorControl.cpp, next to the lines this PR changes. Proposal: yours first, mine rebases.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

build docs libkernel needs rebase Conflicts with main, rebase needed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants