summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Brauner <brauner@kernel.org>2026-09-10 17:48:00 +0200
committerChristian Brauner <brauner@kernel.org>2026-09-14 15:58:06 +0200
commit3a70f44797b692ea09b557bee83159cd507c5a2b (patch)
treedfa0c259f1e37c3c9d6f1982323b76b7c633b61b
parentbee7cdebd22108002a5bb5a7e5e2a804639d2e36 (diff)
downloadlinux-next-3a70f44797b692ea09b557bee83159cd507c5a2b.tar.gz
linux-next-3a70f44797b692ea09b557bee83159cd507c5a2b.zip
fs: add switch_files_struct()
Add switch_files_struct() to install another table on a task. It consumes the reference to the new table and puts the old one. Convert every place that switches a descriptor table except unshare_files(). No functional changes. Link: https://patch.msgid.link/20260910-work-coredump-unlock-self-v4-2-a5c1800dc930@kernel.org Reviewed-by: NeilBrown <neil@brown.name> Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
-rw-r--r--fs/file.c23
-rw-r--r--include/linux/fdtable.h1
-rw-r--r--kernel/fork.c6
3 files changed, 14 insertions, 16 deletions
diff --git a/fs/file.c b/fs/file.c
index 59673547de90..345011dad472 100644
--- a/fs/file.c
+++ b/fs/file.c
@@ -515,16 +515,18 @@ void put_files_struct(struct files_struct *files)
}
}
-void exit_files(struct task_struct *tsk)
+/* Install @files on @tsk, consuming the reference, and put the old table. */
+void switch_files_struct(struct task_struct *tsk, struct files_struct *files)
{
- struct files_struct * files = tsk->files;
+ scoped_guard(task_lock, tsk)
+ swap(tsk->files, files);
+ put_files_struct(files);
+}
- if (files) {
- task_lock(tsk);
- tsk->files = NULL;
- task_unlock(tsk);
- put_files_struct(files);
- }
+void exit_files(struct task_struct *tsk)
+{
+ if (tsk->files)
+ switch_files_struct(tsk, NULL);
}
struct files_struct init_files = {
@@ -855,10 +857,7 @@ SYSCALL_DEFINE3(close_range, unsigned int, fd, unsigned int, max_fd,
* We're done closing the files we were supposed to. Time to install
* the new file descriptor table and drop the old one.
*/
- task_lock(me);
- me->files = cur_fds;
- task_unlock(me);
- put_files_struct(fds);
+ switch_files_struct(me, cur_fds);
}
return 0;
diff --git a/include/linux/fdtable.h b/include/linux/fdtable.h
index c45306a9f007..9614c6ecd477 100644
--- a/include/linux/fdtable.h
+++ b/include/linux/fdtable.h
@@ -100,6 +100,7 @@ static inline bool close_on_exec(unsigned int fd, const struct files_struct *fil
struct task_struct;
void put_files_struct(struct files_struct *fs);
+void switch_files_struct(struct task_struct *tsk, struct files_struct *files);
int unshare_files(void);
struct fd_range {
unsigned int from, to;
diff --git a/kernel/fork.c b/kernel/fork.c
index a5934a317634..f09ca97411a2 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -3323,10 +3323,8 @@ int ksys_unshare(unsigned long unshare_flags)
if (new_fs)
new_fs = switch_fs_struct(new_fs);
- if (new_fd) {
- guard(task_lock)(current);
- swap(current->files, new_fd);
- }
+ if (new_fd)
+ switch_files_struct(current, no_free_ptr(new_fd));
if (new_cred) {
/* Install the new user namespace */