From: Leon Hwang <leon.hwang@linux.dev>
To: Pu Lehui <pulehui@huaweicloud.com>,
bpf@vger.kernel.org, linux-kernel@vger.kernel.org,
Hou Tao <houtao@huaweicloud.com>
Cc: Alexei Starovoitov <ast@kernel.org>,
Daniel Borkmann <daniel@iogearbox.net>,
Andrii Nakryiko <andrii@kernel.org>,
Eduard Zingerman <eddyz87@gmail.com>,
Kumar Kartikeya Dwivedi <memxor@gmail.com>,
Martin KaFai Lau <martin.lau@linux.dev>,
Yonghong Song <yonghong.song@linux.dev>,
Song Liu <song@kernel.org>, Jiri Olsa <jolsa@kernel.org>,
Emil Tsalapatis <emil@etsalapatis.com>,
Ihor Solodrai <ihor.solodrai@linux.dev>,
Pu Lehui <pulehui@huawei.com>
Subject: Re: [PATCH bpf v2] bpf: Fix UAF due to concurrent consumption of waiting_for_gp_ttrace
Date: Thu, 27 Aug 2026 16:51:59 +0800 [thread overview]
Message-ID: <63ae0f06-e5a8-4a21-90cd-03e0ef100fda@linux.dev> (raw)
In-Reply-To: <20260827084013.1062816-1-pulehui@huaweicloud.com>
On 27/8/26 16:40, Pu Lehui wrote:
> From: Pu Lehui <pulehui@huawei.com>
[...]
> kernel/bpf/memalloc.c | 31 +++++++++++++++++++++++++------
> 1 file changed, 25 insertions(+), 6 deletions(-)
>
> diff --git a/kernel/bpf/memalloc.c b/kernel/bpf/memalloc.c
> index e9662db7198f..58296e92a4fe 100644
> --- a/kernel/bpf/memalloc.c
> +++ b/kernel/bpf/memalloc.c
> @@ -119,6 +119,7 @@ struct bpf_mem_cache {
> struct llist_head waiting_for_gp_ttrace;
> struct rcu_head rcu_ttrace;
> atomic_t call_rcu_ttrace_in_progress;
> + raw_spinlock_t lock;
> };
>
> struct bpf_mem_caches {
> @@ -207,6 +208,7 @@ static void add_obj_to_free_list(struct bpf_mem_cache *c, void *obj)
> static void alloc_bulk(struct bpf_mem_cache *c, int cnt, int node, bool atomic)
> {
> struct mem_cgroup *memcg = NULL, *old_memcg;
> + unsigned long flags;
> gfp_t gfp;
> void *obj;
> int i;
> @@ -228,12 +230,14 @@ static void alloc_bulk(struct bpf_mem_cache *c, int cnt, int node, bool atomic)
> if (i >= cnt)
> return;
>
> + raw_spin_lock_irqsave(&c->lock, flags);
> for (; i < cnt; i++) {
> - obj = llist_del_first(&c->waiting_for_gp_ttrace);
> + obj = __llist_del_first(&c->waiting_for_gp_ttrace);
> if (!obj)
> break;
> add_obj_to_free_list(c, obj);
> }
> + raw_spin_unlock_irqrestore(&c->lock, flags);
Looks like scoped_guard() could get rid of the 'flags':
scoped_guard(raw_spinlock_irqsave, &c->lock) {
...
}
> if (i >= cnt)
> return;
>
> @@ -279,8 +283,14 @@ static int free_all(struct bpf_mem_cache *c, struct llist_node *llnode, bool per
> static void __free_rcu(struct rcu_head *head)
> {
> struct bpf_mem_cache *c = container_of(head, struct bpf_mem_cache, rcu_ttrace);
> + struct llist_node *llnode;
> + unsigned long flags;
>
> - free_all(c, llist_del_all(&c->waiting_for_gp_ttrace), !!c->percpu_size);
> + raw_spin_lock_irqsave(&c->lock, flags);
> + llnode = __llist_del_all(&c->waiting_for_gp_ttrace);
> + raw_spin_unlock_irqrestore(&c->lock, flags);
Ditto
> +
> + free_all(c, llnode, !!c->percpu_size);
> atomic_set(&c->call_rcu_ttrace_in_progress, 0);
> }
>
> @@ -297,6 +307,7 @@ static void enque_to_free(struct bpf_mem_cache *c, void *obj)
> static void do_call_rcu_ttrace(struct bpf_mem_cache *c)
> {
> struct llist_node *llnode, *t;
> + unsigned long flags;
>
> if (atomic_xchg(&c->call_rcu_ttrace_in_progress, 1)) {
> if (unlikely(READ_ONCE(c->draining))) {
> @@ -307,8 +318,10 @@ static void do_call_rcu_ttrace(struct bpf_mem_cache *c)
> }
>
> WARN_ON_ONCE(!llist_empty(&c->waiting_for_gp_ttrace));
> + raw_spin_lock_irqsave(&c->lock, flags);
> llist_for_each_safe(llnode, t, llist_del_all(&c->free_by_rcu_ttrace))
> - llist_add(llnode, &c->waiting_for_gp_ttrace);
> + __llist_add(llnode, &c->waiting_for_gp_ttrace);
> + raw_spin_unlock_irqrestore(&c->lock, flags);
Ditto
>
> if (unlikely(READ_ONCE(c->draining))) {
> __free_rcu(&c->rcu_ttrace);
> @@ -535,6 +548,7 @@ int bpf_mem_alloc_init(struct bpf_mem_alloc *ma, int size, bool percpu)
> c->objcg = objcg;
> c->percpu_size = percpu_size;
> c->tgt = c;
> + raw_spin_lock_init(&c->lock);
> init_refill_work(c);
> prefill_mem_cache(c, cpu);
> }
> @@ -557,7 +571,7 @@ int bpf_mem_alloc_init(struct bpf_mem_alloc *ma, int size, bool percpu)
> c->objcg = objcg;
> c->percpu_size = percpu_size;
> c->tgt = c;
> -
> + raw_spin_lock_init(&c->lock);
> init_refill_work(c);
> prefill_mem_cache(c, cpu);
> }
> @@ -609,7 +623,7 @@ int bpf_mem_alloc_percpu_unit_init(struct bpf_mem_alloc *ma, int size)
> c->objcg = objcg;
> c->percpu_size = percpu_size;
> c->tgt = c;
> -
> + raw_spin_lock_init(&c->lock);
> init_refill_work(c);
> prefill_mem_cache(c, cpu);
> }
> @@ -620,6 +634,8 @@ int bpf_mem_alloc_percpu_unit_init(struct bpf_mem_alloc *ma, int size)
> static void drain_mem_cache(struct bpf_mem_cache *c)
> {
> bool percpu = !!c->percpu_size;
> + struct llist_node *llnode;
> + unsigned long flags;
>
> /* No progs are using this bpf_mem_cache, but htab_map_free() called
> * bpf_mem_cache_free() for all remaining elements and they can be in
> @@ -629,7 +645,10 @@ static void drain_mem_cache(struct bpf_mem_cache *c)
> * on these lists, so it is safe to use __llist_del_all().
> */
> free_all(c, llist_del_all(&c->free_by_rcu_ttrace), percpu);
> - free_all(c, llist_del_all(&c->waiting_for_gp_ttrace), percpu);
> + raw_spin_lock_irqsave(&c->lock, flags);
> + llnode = __llist_del_all(&c->waiting_for_gp_ttrace);
> + raw_spin_unlock_irqrestore(&c->lock, flags);
Ditto
Thanks,
Leon
> + free_all(c, llnode, percpu);
> free_all(c, __llist_del_all(&c->free_llist), percpu);
> free_all(c, __llist_del_all(&c->free_llist_extra), percpu);
> free_all(c, __llist_del_all(&c->free_by_rcu), percpu);
next prev parent reply other threads:[~2026-08-27 8:52 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-27 8:40 Pu Lehui
2026-08-27 8:51 ` Leon Hwang [this message]
2026-08-27 11:45 ` Pu Lehui
2026-08-27 9:24 ` bot+bpf-ci
2026-08-27 14:40 ` Hou Tao
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=63ae0f06-e5a8-4a21-90cd-03e0ef100fda@linux.dev \
--to=leon.hwang@linux.dev \
--cc=andrii@kernel.org \
--cc=ast@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=daniel@iogearbox.net \
--cc=eddyz87@gmail.com \
--cc=emil@etsalapatis.com \
--cc=houtao@huaweicloud.com \
--cc=ihor.solodrai@linux.dev \
--cc=jolsa@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=martin.lau@linux.dev \
--cc=memxor@gmail.com \
--cc=pulehui@huawei.com \
--cc=pulehui@huaweicloud.com \
--cc=song@kernel.org \
--cc=yonghong.song@linux.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®