Skip to content

fs: implement close_range(2) - #1436

Open
gburd wants to merge 1 commit into
cloudius-systems:masterfrom
gburd:pr/close-range
Open

fs: implement close_range(2)#1436
gburd wants to merge 1 commit into
cloudius-systems:masterfrom
gburd:pr/close-range

Conversation

@gburd

@gburd gburd commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

What

close_range(2) was missing entirely. It is the standard way to close a range
of file descriptors in one call (commonly used to clean up inherited fds and by
some language runtimes), so programs that call it failed.

How

Implemented over the existing fd table: close (or, with CLOSE_RANGE_CLOEXEC,
set O_CLOEXEC on) every open fd in the inclusive range [first, last],
clamping last to the fd-table size and ignoring fds that are not open, as Linux
does. CLOSE_RANGE_UNSHARE is a no-op in a single-process unikernel (there is
nothing to unshare). first > last and unknown flags return EINVAL.

Wired as syscall SYS_close_range (adding __NR_close_range /
SYS_close_range for x86-64 and aarch64) with a tracepoint, declared in
unistd.h under _GNU_SOURCE, and the symbol exported from libc.so.6 and
ld-musl.so.1.

Testing

tests/tst-close-range.cc covers closing a contiguous run, a range that spans
not-open fds, the CLOSE_RANGE_CLOEXEC variant, and the EINVAL paths. Passes
on OSv under KVM.

(Recreated from #1417, which GitHub auto-closed when its branch was rebased onto current master. Same change, rebased and verified on master 3aba46c.)

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Adds Linux-compatible close_range(2) support to OSv so software that relies on the syscall (common in runtimes and fd-sanitization paths) no longer fails, including libc exposure and a regression test.

Changes:

  • Implement close_range() over OSv’s fd table (close fds in range, or set CLOEXEC).
  • Wire up syscall metadata (syscall list, tracepoint, arch syscall numbers) and export the symbol in libc/loader symbol lists.
  • Add tst-close-range to the test suite and build.

Reviewed changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
tests/tst-close-range.cc New test covering close-range behavior, CLOEXEC variant, and EINVAL paths.
syscalls/syscalls.cc.in Adds close_range to the syscall wrapper list.
syscalls/syscall_tracepoints.cc.in Adds a syscall tracepoint for close_range.
modules/tests/Makefile Includes the new tst-close-range.so in the test image build.
linux.cc Adds an extern "C" declaration for close_range.
include/api/x64/bits/syscall.h Defines SYS_close_range / __NR_close_range for x86-64.
include/api/aarch64/bits/syscall.h Defines SYS_close_range / __NR_close_range for aarch64.
include/api/unistd.h Declares close_range() under _GNU_SOURCE.
fs/vfs/main.cc Implements close_range() using fdclose() / fget() and O_CLOEXEC.
exported_symbols/osv_libc.so.6.symbols Exports close_range from libc.so.6.
exported_symbols/osv_ld-musl.so.1.symbols Exports close_range from ld-musl.so.1.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread tests/tst-close-range.cc Outdated
Comment thread fs/vfs/main.cc
Add Linux close_range(2) over OSv's fd table: close (or, with
CLOSE_RANGE_CLOEXEC, set close-on-exec on) every open fd in the inclusive
range [first, last]. CLOSE_RANGE_UNSHARE is a no-op in a single-process
unikernel (there is nothing to unshare). Reject first > last and unknown
flags with EINVAL. Wired through libc/syscall dispatch/tracepoints with a
regression test.

Signed-off-by: Greg Burd <greg@burd.me>
@gburd

gburd commented Jul 29, 2026

Copy link
Copy Markdown
Contributor Author

Thanks Copilot. Addressed / responded in the current tip (7c95715, rebased onto master):

  • Test false positive on fcntl(b, F_GETFD) & FD_CLOEXEC: the test now captures the fcntl() return, asserts it is not -1, then checks the FD_CLOEXEC bit, so a failed fcntl cannot masquerade as a set bit.
  • CLOSE_RANGE_UNSHARE / CLOSE_RANGE_CLOEXEC defined locally rather than in a public header: kept as local #ifndef-guarded defines for now. musl does not ship these flags in a stable header across the versions OSv tracks, and OSv is a single-process unikernel where CLOSE_RANGE_UNSHARE is a no-op, so there is no external consumer that needs the macros today. If a public close_range flag header lands upstream in musl I am happy to switch to it. Open to putting them in include/api if you prefer that convention.

Needs a build to confirm the test passes; queued.

@gburd

gburd commented Jul 29, 2026

Copy link
Copy Markdown
Contributor Author

Build-validated on x86_64: image=tests builds (EXIT 0) and tst-close-range passes with the false-positive test-hardening fix.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants