On Mon, 2024-04-08 at 10:09 +0200, Benjamin Tissoires wrote: [...] > diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c > index 9234174ccb21..fd05d4358b31 100644 > --- a/kernel/bpf/helpers.c > +++ b/kernel/bpf/helpers.c > @@ -1096,12 +1096,19 @@ const struct bpf_func_proto bpf_snprintf_proto = { > * freeing the timers when inner map is replaced or deleted by user space. > */ > struct bpf_hrtimer { > - struct hrtimer timer; > + union { > + struct hrtimer timer; > + struct work_struct work; > + }; > struct bpf_map *map; > struct bpf_prog *prog; > void __rcu *callback_fn; > void *value; > - struct rcu_head rcu; > + union { > + struct rcu_head rcu; > + struct work_struct sync_work; Nit: I find this name very confusing, the field is used to cancel timer execution, is it a convention to call such things '...sync...'? > + }; > + u64 flags; > }; > [...] > +static void bpf_timer_sync_work_cb(struct work_struct *work) > +{ > + struct bpf_hrtimer *t = container_of(work, struct bpf_hrtimer, sync_work); > + > + cancel_work_sync(&t->work); > + > + kfree_rcu(t, rcu); Sorry, I might be wrong, but this looks suspicious. The 'rcu' field of 'bpf_hrtimer' is defined as follows: struct bpf_hrtimer { ... union { struct rcu_head rcu; struct work_struct sync_work; }; ... }; And for sleepable timers the 'sync_work' field is set as follows: BPF_CALL_3(bpf_timer_init, struct bpf_timer_kern *, timer, struct bpf_map *, map, u64, flags) { ... INIT_WORK(&t->sync_work, bpf_timer_sync_work_cb); ... } So, it looks like 'kfree_rcu' would be called for a non-rcu pointer. > +} > +