FAILED: patch "[PATCH] bpf: Fix KASAN use-after-free Read in compute_effective_progs" failed to apply to 5.10-stable tree
Subsystems (2)
[email protected]
maintainerThe patch below does not apply to the 5.10-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 4c46091ee985ae84c60c5e95055d779fcd291d87 Mon Sep 17 00:00:00 2001
From: Tadeusz Struk <[email protected]>
Date: Tue, 17 May 2022 11:04:20 -0700
Subject: [PATCH] bpf: Fix KASAN use-after-free Read in compute_effective_progs
Syzbot found a Use After Free bug in compute_effective_progs(). The reproducer creates a number of BPF links, and causes a fault injected alloc to fail, while calling bpf_link_detach on them. Link detach triggers the link to be freed by bpf_link_free(), which calls __cgroup_bpf_detach() and update_effective_progs(). If the memory allocation in this function fails, the function restores the pointer to the bpf_cgroup_link on the cgroup list, but the memory gets freed just after it returns. After this, every subsequent call to update_effective_progs() causes this already deallocated pointer to be dereferenced in prog_list_length(), and triggers KASAN UAF error.
To fix this issue don't preserve the pointer to the prog or link in the list, but remove it and replace it with a dummy prog without shrinking the table. The subsequent call to __cgroup_bpf_detach() or __cgroup_bpf_detach() will correct it.
kernel/bpf/cgroup.c +60 -10
@@ -720,6 +720,60 @@ static struct bpf_prog_list *find_detach_entry(struct list_head *progs,return ERR_PTR (-ENOENT ); } +/** +* purge_effective_progs() - After compute_effective_progs fails to alloc new +* cgrp->bpf.inactive table we can recover by +* recomputing the array in place. +* +* @cgrp: The cgroup which descendants to travers +* @prog: A program to detach or NULL +* @link: A link to detach or NULL +* @atype: Type of detach operation +*/ +static void purge_effective_progs (struct cgroup *cgrp,struct bpf_prog *prog, +struct bpf_cgroup_link *link, +enum cgroup_bpf_attach_type atype) +{ +struct cgroup_subsys_state *css; +struct bpf_prog_array *progs; +struct bpf_prog_list *pl; +struct list_head *head; +struct cgroup *cg; +int pos; + +/* recompute effective prog array in place */ +css_for_each_descendant_pre (css, &cgrp->self) { + struct cgroup *desc = container_of(css, struct cgroup, self); + +if (percpu_ref_is_zero (&desc->bpf.refcnt)) +continue ; + +/* find position of link or prog in effective progs array */ +for (pos =0 , cg = desc; cg; cg =cgroup_parent (cg)) { +if (pos && !(cg->bpf.flags[atype] &BPF_F_ALLOW_MULTI )) +continue ; + + head = &cg->bpf.progs[atype]; +list_for_each_entry (pl, head, node) { +if (!prog_list_prog (pl)) +continue ; +if (pl->prog == prog && pl->link == link) + goto found; + pos++; + } + } +found: +BUG_ON (!cg); + progs =rcu_dereference_protected ( + desc->bpf.effective[atype], +lockdep_is_held (&cgroup_mutex)); + +/* Remove the program from the array */ +WARN_ONCE (bpf_prog_array_delete_safe_at (progs, pos), +"Failed to purge a prog from array at index %d" , pos); + } +} +/** * __cgroup_bpf_detach() - Detach the program or link from a cgroup, and * propagate the change to descendants
@@ -739,7 +793,6 @@ static int __cgroup_bpf_detach(struct cgroup *cgrp, struct bpf_prog *prog,struct bpf_prog_list *pl;struct list_head *progs;u32 flags; -int err; atype =to_cgroup_bpf_attach_type (type);if (atype <0 )
@@ -761,9 +814,12 @@ static int __cgroup_bpf_detach(struct cgroup *cgrp, struct bpf_prog *prog, pl->prog =NULL ; pl->link =NULL ; - err =update_effective_progs (cgrp, atype); -if (err) - goto cleanup; +if (update_effective_progs (cgrp, atype)) { +/* if update effective array failed replace the prog with a dummy prog*/ + pl->prog = old_prog; + pl->link = link; +purge_effective_progs (cgrp, old_prog, link, atype); + }/* now can actually delete it from this cgroup list */ list_del (&pl->node);
@@ -775,12 +831,6 @@ static int __cgroup_bpf_detach(struct cgroup *cgrp, struct bpf_prog *prog,bpf_prog_put (old_prog);static_branch_dec (&cgroup_bpf_enabled_key[atype]);return 0 ; - -cleanup: -/* restore back prog or link */ - pl->prog = old_prog; - pl->link = link; -return err; } static int cgroup_bpf_detach(struct cgroup *cgrp, struct bpf_prog *prog,