[GIT PULL 07/19 for v7.4] vfs close_range

From: Christian Brauner

Date: Fri Oct 16 2026 - 06:26:12 EST


Hey Linus,

/* Summary */

This adds two new close_range() flags.

CLOSE_RANGE_EXCEPT makes close_range() operate on all file descriptors
outside of [fd, max_fd] instead of the ones inside. Alone it closes
everything but the range. With CLOSE_RANGE_CLOEXEC it marks everything
but the range close-on-exec. With CLOSE_RANGE_UNSHARE dup_fd() never
takes a reference on what is dropped. So a task between
clone(CLONE_FILES | CLONE_VM | CLONE_VFORK) and execve() that has the
descriptors for the child in one window can shed the rest of the shared
table in one call and nothing outside of the window is referenced by
the child at any point.

CLOSE_RANGE_CLOEXEC_ONLY closes the close-on-exec descriptors in the
range and leaves everything else alone. Whatever the caller
deliberately passes down, stdio, LISTEN_FDS, an inherited pipe, stays
where it is. Combined with CLOSE_RANGE_EXCEPT it names the handful of
close-on-exec descriptors that have to survive, the executable or an
error pipe, and closes every other close-on-exec descriptor.

Along the way dup_fd() stops copying a range in the middle of the table
only to close it again. close_range(CLOSE_RANGE_UNSHARE) only avoided
the copy when the range sat at the end of the table. Descriptors in a
skipped range are never copied and no reference is taken on them, so
->flush() isn't called anymore for files from a table they were never
part of. The flags are turned into an enum and selftests cover the
window positions, the shared and the private table and the unshare
form.

/* Testing */

No build failures or warnings were observed.

/* Conflicts */

Merge conflicts with mainline
=============================

No known conflicts.

Merge conflicts with other trees
================================

No known conflicts.

The following changes since commit fd73f4a6659897191fa0d40695fe370925dd3780:

Linux 7.3-rc3 (2026-09-13 14:38:02 -0700)

are available in the Git repository at:

git@xxxxxxxxxxxxxxxxxxx:pub/scm/linux/kernel/git/vfs/vfs tags/vfs-7.4-rc1.close_range

for you to fetch changes up to c73c0e243836d5dfd1c617f73b6003b1ad40b2d1:

Merge patch series "files,close_range: add CLOSE_RANGE_{CLOEXEC_ONLY,EXCEPT}" (2026-10-05 13:02:41 +0200)

----------------------------------------------------------------
vfs-7.4-rc1.close_range

Please consider pulling these changes from the signed vfs-7.4-rc1.close_range tag.

Thanks!
Christian

----------------------------------------------------------------
Christian Brauner (11):
file: let dup_fd() leave the punched hole behind
selftests/core: test the hole CLOSE_RANGE_UNSHARE leaves behind
file: rename dup_fd()'s punch_hole to range
file: let dup_fd() drop everything outside of the range
close_range: turn the flags into an enum
file: add CLOSE_RANGE_EXCEPT
selftests/core: test CLOSE_RANGE_EXCEPT
file: let dup_fd() drop only close-on-exec descriptors
file: add CLOSE_RANGE_CLOEXEC_ONLY
selftests/core: test CLOSE_RANGE_CLOEXEC_ONLY
Merge patch series "files,close_range: add CLOSE_RANGE_{CLOEXEC_ONLY,EXCEPT}"

fs/file.c | 200 ++++-
include/linux/fdtable.h | 9 +
include/uapi/linux/close_range.h | 31 +-
tools/testing/selftests/core/close_range_test.c | 951 ++++++++++++++++++++++++
4 files changed, 1151 insertions(+), 40 deletions(-)