summaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
authorChristian Brauner <brauner@kernel.org>2026-09-21 16:15:37 +0200
committerChristian Brauner <brauner@kernel.org>2026-10-05 13:02:41 +0200
commit06074fbbf092b1a6292c108eef2b94f43333ea1c (patch)
tree7eec081c3ffec10dd325b96177ea416b84434b84 /include
parent4587f99cc2c87079167b18e284f64b66cafade76 (diff)
downloadlinux-next-06074fbbf092b1a6292c108eef2b94f43333ea1c.tar.gz
linux-next-06074fbbf092b1a6292c108eef2b94f43333ea1c.zip
file: add CLOSE_RANGE_CLOEXEC_ONLY
CLOSE_RANGE_CLOEXEC marks a range close-on-exec. Nothing happens to these fds unless an exec happens. Add CLOSE_RANGE_CLOEXEC_ONLY which closes the close-on-exec file descriptors in the range. When combined with CLOSE_RANGE_EXCEPT it names the close-on-exec file descriptors that are supposed to survive. Every close-on-exec fd outside of the range is closed. File descriptors without that flag are left alone. 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, sit in a specific range. That is what a task between clone(CLONE_FILES) and execve() actually wants: 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. The range is expressed in the parent's numbering. So a caller that cannot name the file descriptors it keeps contiguously picks a range wide enough to cover them, unshares, and tidies up with a second close_range() on the table it now owns alone. That one is cheap. To keep nothing, name a range that cannot hold an open descriptor, e.g. close_range(~0U, ~0U, ...). CLOSE_RANGE_CLOEXEC and CLOSE_RANGE_CLOEXEC_ONLY are mutually exclusive. Link: https://patch.msgid.link/20260921-work-file-close_range_except-v1-9-c20d0b49270d@kernel.org Reviewed-by: Jann Horn <jannh@google.com> Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
Diffstat (limited to 'include')
-rw-r--r--include/uapi/linux/close_range.h5
1 files changed, 5 insertions, 0 deletions
diff --git a/include/uapi/linux/close_range.h b/include/uapi/linux/close_range.h
index 39eddb3ab613..7da9ed95258a 100644
--- a/include/uapi/linux/close_range.h
+++ b/include/uapi/linux/close_range.h
@@ -9,6 +9,7 @@
#undef CLOSE_RANGE_UNSHARE
#undef CLOSE_RANGE_CLOEXEC
#undef CLOSE_RANGE_EXCEPT
+#undef CLOSE_RANGE_CLOEXEC_ONLY
enum close_range_flags {
/* Unshare the file descriptor table before closing file descriptors. */
@@ -19,12 +20,16 @@ enum close_range_flags {
/* 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 */