mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
fork: Let nobody keep a task that may not come to life
dup_task_struct() sets rcu_users to 2. From then on bpf_task_acquire()
hands out references to the new task, which BPF programs see as a trusted
pointer long before it is sure to live: in the task_alloc LSM hook and in
ops.init_task() of sched_ext.
If copy_process() fails later on, it undoes what it has done and frees
the task without a look at the count. A program that has stored its
reference in a map is left with a pointer to freed memory:
BUG: KASAN: slab-use-after-free in put_task_struct_rcu_user+0x22/0x90
The program is loaded by the administrator, but any user can make a fork
fail, for example at the pids.max of a cgroup.
Honouring the count would not do: the task would stay behind with its mm,
files and credentials freed. Leave rcu_users at zero until copy_process()
cannot fail any more. bpf_task_acquire() returns NULL until then, which
its callers have to be prepared for, and which they get for init_task,
whose count has always been zero. The other users of rcu_users deal with
tasks that have run.
Fixes: 90660309b0 ("bpf: Add kfuncs for storing struct task_struct * as a kptr")
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
This commit is contained in:
parent
aa6439028d
commit
5cf0881344
|
|
@ -970,10 +970,10 @@ static struct task_struct *dup_task_struct(struct task_struct *orig, int node)
|
|||
dup_user_cpus_ptr(tsk, orig, node);
|
||||
|
||||
/*
|
||||
* One for the user space visible state that goes away when reaped.
|
||||
* One for the scheduler.
|
||||
* Nobody can keep the task while copy_process() may still fail, which
|
||||
* frees it no matter what.
|
||||
*/
|
||||
refcount_set(&tsk->rcu_users, 2);
|
||||
refcount_set(&tsk->rcu_users, 0);
|
||||
/* One for the rcu users */
|
||||
refcount_set(&tsk->usage, 1);
|
||||
#ifdef CONFIG_BLK_DEV_IO_TRACE
|
||||
|
|
@ -2510,6 +2510,12 @@ __latent_entropy struct task_struct *copy_process(
|
|||
|
||||
/* No more failure paths after this point. */
|
||||
|
||||
/*
|
||||
* One for the user space visible state that goes away when reaped.
|
||||
* One for the scheduler.
|
||||
*/
|
||||
refcount_set(&p->rcu_users, 2);
|
||||
|
||||
/*
|
||||
* Copy seccomp details explicitly here, in case they were changed
|
||||
* before holding sighand lock.
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user