diff options
| author | Christian Brauner <brauner@kernel.org> | 2026-09-22 13:40:12 +0200 |
|---|---|---|
| committer | Christian Brauner <brauner@kernel.org> | 2026-10-05 13:02:41 +0200 |
| commit | c73c0e243836d5dfd1c617f73b6003b1ad40b2d1 (patch) | |
| tree | 0dbbe2d22ab8dc1d281dd3de402863870816750f /include/uapi | |
| parent | fd73f4a6659897191fa0d40695fe370925dd3780 (diff) | |
| parent | 0a0f88fcb434f58fc5b444e7c9eeae791cdbbeda (diff) | |
Merge patch series "files,close_range: add CLOSE_RANGE_{CLOEXEC_ONLY,EXCEPT}"
Christian Brauner <brauner@kernel.org> says:
close_range(CLOSE_RANGE_CLOEXEC) marks a range of file descriptors
close-on-exec. It only marks them. The file descriptors are only ever
closed during an exec. This series adds two new flags to extend the
abilities of close_range():
(1) CLOSE_RANGE_EXCEPT
While regular close_range() operates on all file descriptors in the
range [fd, max_fd] and not on any others, CLOSE_RANGE_EXCEPT makes
close_range() operate on all file descriptors outside of the range.
When combined with CLOSE_RANGE_UNSHARE dup_fd() never takes a
reference on what is dropped.
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:
close_range(lo, hi, CLOSE_RANGE_UNSHARE | CLOSE_RANGE_EXCEPT)
Nothing outside of the window is referenced by the child at any point.
(2) CLOSE_RANGE_CLOEXEC_ONLY closes the close-on-exec file descriptors
in the range
Whatever the caller deliberately passes down, stdio, LISTEN_FDS, an
inherited pipe, remains where it is.
The handful of close-on-exec descriptors the caller still needs for the
exec such as the executable, an error pipe, can sit in a specific
range. A task between clone(CLONE_FILES) and execve() may do:
clone(CLONE_FILES | CLONE_VM | CLONE_VFORK)
child: close_range(lo, hi, CLOSE_RANGE_UNSHARE |
CLOSE_RANGE_CLOEXEC_ONLY |
CLOSE_RANGE_EXCEPT)
child: rearrange descriptors in the now private table
child: execve()
Between the clone and the close_range() the child holds no reference of
its own on any file because copy_files() only bumps the fdtable
refcount. So a close() in the parent takes effect immediately. The
unshare also never takes a reference on the fds it leaves behind either.
* patches from https://patch.msgid.link/20260921-work-file-close_range_except-v1-0-c20d0b49270d@kernel.org:
selftests/core: test CLOSE_RANGE_CLOEXEC_ONLY
file: add CLOSE_RANGE_CLOEXEC_ONLY
file: let dup_fd() drop only close-on-exec descriptors
selftests/core: test CLOSE_RANGE_EXCEPT
file: add CLOSE_RANGE_EXCEPT
close_range: turn the flags into an enum
file: let dup_fd() drop everything outside of the range
file: rename dup_fd()'s punch_hole to range
selftests/core: test the hole CLOSE_RANGE_UNSHARE leaves behind
file: let dup_fd() leave the punched hole behind
Link: https://patch.msgid.link/20260921-work-file-close_range_except-v1-0-c20d0b49270d@kernel.org
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
Diffstat (limited to 'include/uapi')
| -rw-r--r-- | include/uapi/linux/close_range.h | 31 |
1 files changed, 27 insertions, 4 deletions
diff --git a/include/uapi/linux/close_range.h b/include/uapi/linux/close_range.h index 2d804281554c..7da9ed95258a 100644 --- a/include/uapi/linux/close_range.h +++ b/include/uapi/linux/close_range.h @@ -2,11 +2,34 @@ #ifndef _UAPI_LINUX_CLOSE_RANGE_H #define _UAPI_LINUX_CLOSE_RANGE_H -/* Unshare the file descriptor table before closing file descriptors. */ -#define CLOSE_RANGE_UNSHARE (1U << 1) +/* + * A macro of one of these names defined before this header is parsed, by + * a libc or by a program's own fallback, would replace the enumerator. + */ +#undef CLOSE_RANGE_UNSHARE +#undef CLOSE_RANGE_CLOEXEC +#undef CLOSE_RANGE_EXCEPT +#undef CLOSE_RANGE_CLOEXEC_ONLY -/* Set the FD_CLOEXEC bit instead of closing the file descriptor. */ -#define CLOSE_RANGE_CLOEXEC (1U << 2) +enum close_range_flags { + /* Unshare the file descriptor table before closing file descriptors. */ + CLOSE_RANGE_UNSHARE = (1U << 1), + + /* Set the FD_CLOEXEC bit instead of closing the file descriptor. */ + CLOSE_RANGE_CLOEXEC = (1U << 2), + + /* Act on every file descriptor outside of the given range instead. */ + CLOSE_RANGE_EXCEPT = (1U << 3), + + /* Only close file descriptors that have the FD_CLOEXEC bit set. */ + CLOSE_RANGE_CLOEXEC_ONLY = (1U << 4), +}; + +/* Keep #ifdef working and let glibc skip its own definitions. */ +#define CLOSE_RANGE_UNSHARE CLOSE_RANGE_UNSHARE +#define CLOSE_RANGE_CLOEXEC CLOSE_RANGE_CLOEXEC +#define CLOSE_RANGE_EXCEPT CLOSE_RANGE_EXCEPT +#define CLOSE_RANGE_CLOEXEC_ONLY CLOSE_RANGE_CLOEXEC_ONLY #endif /* _UAPI_LINUX_CLOSE_RANGE_H */ |
