mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
fork: release the files of a failed fork after sched_cancel_fork()
Reorder copy_process() cleanup so sched_fork() taking scx_fork_rwsem
scx_pre_fork() is safe and isn't held around exiting files. Right now, a
fork that fails while another thread closed the bpf link fd will
deadlock against its own read side. It also blocks every fork on the
system:
copy_process() holds scx_fork_rwsem for read
exit_files()
close_files()
filp_close_sync()
bpf_scx_unreg()
kthread_flush_work() waits for the disable work
scx_root_disable()
percpu_down_write(&scx_fork_rwsem)
Simply release the child's files after sched_cancel_fork() dropped the
lock. The task starts out as a copy of its parent so p->files points to
the parent's table until copy_files() replaces it. exit_files() must not
run for a fork that failed before that. Clear p->files up front so
exit_files() is a no-op for those and make copy_files() set it
explicitly for CLONE_FILES.
Reported-by: Chris Mason <mason@kernel.org>
Link: https://patch.msgid.link/20260921-work-coredump-fixes-v3-7-8e4adb1619e6@kernel.org
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
This commit is contained in:
parent
97f08aa822
commit
296a98c1fa
|
|
@ -1676,6 +1676,7 @@ static int copy_files(u64 clone_flags, struct task_struct *tsk,
|
|||
|
||||
if (clone_flags & CLONE_FILES) {
|
||||
atomic_inc(&oldf->count);
|
||||
tsk->files = oldf;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -2199,6 +2200,8 @@ __latent_entropy struct task_struct *copy_process(
|
|||
INIT_LIST_HEAD(&p->sibling);
|
||||
rcu_copy_process(p);
|
||||
p->vfork_done = NULL;
|
||||
/* Set by copy_files(), exit_files() on the error path skips NULL. */
|
||||
p->files = NULL;
|
||||
spin_lock_init(&p->alloc_lock);
|
||||
|
||||
init_sigpending(&p->pending);
|
||||
|
|
@ -2300,7 +2303,7 @@ __latent_entropy struct task_struct *copy_process(
|
|||
goto bad_fork_cleanup_semundo;
|
||||
retval = copy_fs(clone_flags, p, args->umh);
|
||||
if (retval)
|
||||
goto bad_fork_cleanup_files;
|
||||
goto bad_fork_cleanup_semundo;
|
||||
retval = copy_sighand(clone_flags, p);
|
||||
if (retval)
|
||||
goto bad_fork_cleanup_fs;
|
||||
|
|
@ -2613,8 +2616,6 @@ __latent_entropy struct task_struct *copy_process(
|
|||
__cleanup_sighand(p->sighand);
|
||||
bad_fork_cleanup_fs:
|
||||
exit_fs(p); /* blocking */
|
||||
bad_fork_cleanup_files:
|
||||
exit_files(p); /* blocking */
|
||||
bad_fork_cleanup_semundo:
|
||||
exit_sem(p);
|
||||
bad_fork_cleanup_security:
|
||||
|
|
@ -2625,6 +2626,8 @@ __latent_entropy struct task_struct *copy_process(
|
|||
perf_event_free_task(p);
|
||||
bad_fork_sched_cancel_fork:
|
||||
sched_cancel_fork(p);
|
||||
/* ->release() of a file may need scx_fork_rwsem for write. */
|
||||
exit_files(p); /* blocking */
|
||||
bad_fork_cleanup_policy:
|
||||
lockdep_free_task(p);
|
||||
#ifdef CONFIG_NUMA
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user