mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-09-18 23:09:29 +02:00
fs: add umh argument to struct kernel_clone_args
Add a umh field to struct kernel_clone_args. When set, copy_fs() copies from pid 1's fs_struct instead of the kthread's fs_struct. This ensures usermodehelper threads always get init's filesystem state regardless of their parent's (kthreadd's) fs. Usermodehelper threads are not allowed to create mount namespaces (CLONE_NEWNS), share filesystem state (CLONE_FS), or be started from a non-initial mount namespace. No usermodehelper currently does this so we don't need to worry about this restriction. Set .umh = 1 in user_mode_thread(). At this stage pid 1's fs points to rootfs which is the same as kthreadd's fs, so this is functionally equivalent. Link: https://patch.msgid.link/20260601-work-kthread-nullfs-v4-20-77ee053060e0@kernel.org Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
This commit is contained in:
@@ -31,6 +31,7 @@ struct kernel_clone_args {
|
||||
u32 io_thread:1;
|
||||
u32 user_worker:1;
|
||||
u32 no_files:1;
|
||||
u32 umh:1;
|
||||
unsigned long stack;
|
||||
unsigned long stack_size;
|
||||
unsigned long tls;
|
||||
|
||||
+21
-4
@@ -1613,11 +1613,27 @@ static int copy_exec_state(u64 clone_flags, struct task_struct *tsk)
|
||||
return task_exec_state_copy(tsk);
|
||||
}
|
||||
|
||||
static int copy_fs(u64 clone_flags, struct task_struct *tsk)
|
||||
static int copy_fs(u64 clone_flags, struct task_struct *tsk, bool umh)
|
||||
{
|
||||
struct fs_struct *fs = current->fs;
|
||||
struct fs_struct *fs;
|
||||
|
||||
/*
|
||||
* Usermodehelper may copy userspace_init_fs filesystem state but
|
||||
* they don't get to create mount namespaces, share the
|
||||
* filesystem state, or be started from a non-initial mount
|
||||
* namespace.
|
||||
*/
|
||||
if (umh) {
|
||||
if (clone_flags & (CLONE_NEWNS | CLONE_FS))
|
||||
return -EINVAL;
|
||||
if (current->nsproxy->mnt_ns != &init_mnt_ns)
|
||||
return -EINVAL;
|
||||
fs = userspace_init_fs;
|
||||
} else {
|
||||
fs = current->fs;
|
||||
VFS_WARN_ON_ONCE(current->fs != current->real_fs);
|
||||
}
|
||||
|
||||
VFS_WARN_ON_ONCE(current->fs != current->real_fs);
|
||||
if (clone_flags & CLONE_FS) {
|
||||
/* tsk->fs is already what we want */
|
||||
read_seqlock_excl(&fs->seq);
|
||||
@@ -2278,7 +2294,7 @@ __latent_entropy struct task_struct *copy_process(
|
||||
retval = copy_files(clone_flags, p, args->no_files);
|
||||
if (retval)
|
||||
goto bad_fork_cleanup_semundo;
|
||||
retval = copy_fs(clone_flags, p);
|
||||
retval = copy_fs(clone_flags, p, args->umh);
|
||||
if (retval)
|
||||
goto bad_fork_cleanup_files;
|
||||
retval = copy_sighand(clone_flags, p);
|
||||
@@ -2820,6 +2836,7 @@ pid_t user_mode_thread(int (*fn)(void *), void *arg, unsigned long flags)
|
||||
.exit_signal = (flags & CSIGNAL),
|
||||
.fn = fn,
|
||||
.fn_arg = arg,
|
||||
.umh = 1,
|
||||
};
|
||||
|
||||
return kernel_clone(&args);
|
||||
|
||||
+2
-4
@@ -71,10 +71,8 @@ static int call_usermodehelper_exec_async(void *data)
|
||||
spin_unlock_irq(¤t->sighand->siglock);
|
||||
|
||||
/*
|
||||
* Initial kernel threads share ther FS with init, in order to
|
||||
* get the init root directory. But we've now created a new
|
||||
* thread that is going to execve a user process and has its own
|
||||
* 'struct fs_struct'. Reset umask to the default.
|
||||
* Usermodehelper threads get a copy of userspace init's
|
||||
* fs_struct. Reset umask to the default.
|
||||
*/
|
||||
current->fs->umask = 0022;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user