Skip to content

Commit 2884dc7

Browse files
Cong Wangborkmann
authored andcommitted
bpf: Fix a potential use-after-free in bpf_link_free()
After commit 1a80dbc, bpf_link can be freed by link->ops->dealloc_deferred, but the code still tests and uses link->ops->dealloc afterward, which leads to a use-after-free as reported by syzbot. Actually, one of them should be sufficient, so just call one of them instead of both. Also add a WARN_ON() in case of any problematic implementation. Fixes: 1a80dbc ("bpf: support deferring bpf_link dealloc to after RCU grace period") Reported-by: [email protected] Signed-off-by: Cong Wang <[email protected]> Signed-off-by: Daniel Borkmann <[email protected]> Acked-by: Jiri Olsa <[email protected]> Link: https://lore.kernel.org/bpf/[email protected]
1 parent 2317dc2 commit 2884dc7

File tree

1 file changed

+6
-5
lines changed

1 file changed

+6
-5
lines changed

kernel/bpf/syscall.c

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2998,6 +2998,7 @@ static int bpf_obj_get(const union bpf_attr *attr)
29982998
void bpf_link_init(struct bpf_link *link, enum bpf_link_type type,
29992999
const struct bpf_link_ops *ops, struct bpf_prog *prog)
30003000
{
3001+
WARN_ON(ops->dealloc && ops->dealloc_deferred);
30013002
atomic64_set(&link->refcnt, 1);
30023003
link->type = type;
30033004
link->id = 0;
@@ -3056,16 +3057,17 @@ static void bpf_link_defer_dealloc_mult_rcu_gp(struct rcu_head *rcu)
30563057
/* bpf_link_free is guaranteed to be called from process context */
30573058
static void bpf_link_free(struct bpf_link *link)
30583059
{
3060+
const struct bpf_link_ops *ops = link->ops;
30593061
bool sleepable = false;
30603062

30613063
bpf_link_free_id(link->id);
30623064
if (link->prog) {
30633065
sleepable = link->prog->sleepable;
30643066
/* detach BPF program, clean up used resources */
3065-
link->ops->release(link);
3067+
ops->release(link);
30663068
bpf_prog_put(link->prog);
30673069
}
3068-
if (link->ops->dealloc_deferred) {
3070+
if (ops->dealloc_deferred) {
30693071
/* schedule BPF link deallocation; if underlying BPF program
30703072
* is sleepable, we need to first wait for RCU tasks trace
30713073
* sync, then go through "classic" RCU grace period
@@ -3074,9 +3076,8 @@ static void bpf_link_free(struct bpf_link *link)
30743076
call_rcu_tasks_trace(&link->rcu, bpf_link_defer_dealloc_mult_rcu_gp);
30753077
else
30763078
call_rcu(&link->rcu, bpf_link_defer_dealloc_rcu_gp);
3077-
}
3078-
if (link->ops->dealloc)
3079-
link->ops->dealloc(link);
3079+
} else if (ops->dealloc)
3080+
ops->dealloc(link);
30803081
}
30813082

30823083
static void bpf_link_put_deferred(struct work_struct *work)

0 commit comments

Comments
 (0)