BPF List
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Kaitao cheng" <kaitao.cheng@linux.dev>
Cc: bpf@vger.kernel.org
Subject: Re: [PATCH RESEND bpf-next v10 7/8] bpf: allow non-owning list-node args via __nonown_allowed
Date: Wed, 13 May 2026 22:22:58 +0000	[thread overview]
Message-ID: <20260513222258.AEB08C19425@smtp.kernel.org> (raw)
In-Reply-To: <20260512055919.95716-8-kaitao.cheng@linux.dev>

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [Critical] bpf_list_add() dynamically frees the 'new' node on failure, but the verifier unconditionally assumes success, enabling a Use-After-Free.
- [Critical] bpf_list_del() does not invalidate the passed non-owning reference, leaving a direct alias to potentially freed memory (Use-After-Free).
--

commit abe3e2cc841c335580b071d1f616bb2c9d1deba4
Author: Kaitao Cheng <chengkaitao@kylinos.cn>

bpf: allow non-owning list-node args via __nonown_allowed

This commit introduces the __nonown_allowed annotation for list-node
arguments. It allows bpf_list_add, bpf_list_del, and bpf_list_is_first/last
to accept non-owning references.

> diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c
> --- a/kernel/bpf/helpers.c
> +++ b/kernel/bpf/helpers.c
[ ... ]
> @@ -2571,10 +2571,10 @@ __bpf_kfunc int bpf_list_push_back_impl(struct bpf_list_head *head,
>  }
>  
>  __bpf_kfunc int bpf_list_add(struct bpf_list_head *head, struct bpf_list_node *new,
> -			     struct bpf_list_node *prev, struct btf_struct_meta *meta,
> -			     u64 off)
> +			     struct bpf_list_node *prev__nonown_allowed,
> +			     struct btf_struct_meta *meta, u64 off)
>  {
> -	struct bpf_list_node_kern *n = (void *)new, *p = (void *)prev;
> +	struct bpf_list_node_kern *n = (void *)new, *p = (void *)prev__nonown_allowed;
>  	struct list_head *prev_ptr = &p->list_head;
>  
>  	return __bpf_list_add(n, head, &prev_ptr, meta ? meta->record : NULL, off);

If a BPF program passes a non-owning reference from a completely different
list (protected by the same spinlock) to prev__nonown_allowed, can this
cause a use-after-free?

At runtime, __bpf_list_add() detects that the prev node doesn't belong to
the target head and aborts the insertion, calling __bpf_obj_drop_impl()
on the new node to free it back to the allocator.

However, the verifier unconditionally assumes bpf_list_add() successfully
consumed the new owning reference and safely converts it into a non-owning
reference in its internal state.

Because the verifier considers this non-owning reference valid until the
spinlock is unlocked, does this allow the BPF program to continuously
dereference the freed memory while holding the lock?

[ ... ]
> @@ -2620,9 +2620,9 @@ __bpf_kfunc struct bpf_list_node *bpf_list_pop_back(struct bpf_list_head *head)
>  }
>  
>  __bpf_kfunc struct bpf_list_node *bpf_list_del(struct bpf_list_head *head,
> -					       struct bpf_list_node *node)
> +				struct bpf_list_node *node__nonown_allowed)
>  {
> -	struct bpf_list_node_kern *kn = (void *)node;
> +	struct bpf_list_node_kern *kn = (void *)node__nonown_allowed;
>  
>  	/* verifier guarantees node is a list node rather than list head */
>  	return __bpf_list_del(head, &kn->list_head);

Does passing a non-owning reference here create an alias that leads to
a use-after-free?

When bpf_list_del() removes the node from the list, it returns a new owning
reference (with ref_obj_id > 0) pointing to the exact same object.

The verifier does not explicitly invalidate the original non-owning
reference argument (which has ref_obj_id == 0), so it remains fully valid
in the verifier's state until the active spinlock is released.

If the BPF program subsequently frees the object by passing the returned
owning reference to bpf_obj_drop(), won't the original non-owning reference
remain as a direct, unchecked alias to the freed memory?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260512055919.95716-1-kaitao.cheng@linux.dev?part=7

  parent reply	other threads:[~2026-05-13 22:22 UTC|newest]

Thread overview: 30+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-05-12  5:59 [PATCH RESEND bpf-next v10 0/8] bpf: Extend the bpf_list family of APIs Kaitao cheng
2026-05-12  5:59 ` [PATCH RESEND bpf-next v10 1/8] bpf: refactor __bpf_list_del to take list node pointer Kaitao cheng
2026-05-12  6:41   ` bot+bpf-ci
2026-05-12  8:55     ` Kaitao Cheng
2026-05-13 22:30   ` Eduard Zingerman
2026-05-12  5:59 ` [PATCH RESEND bpf-next v10 2/8] bpf: clear list node owner and unlink before drop Kaitao cheng
2026-05-12  6:41   ` bot+bpf-ci
2026-05-13 22:53     ` Eduard Zingerman
2026-05-14  1:50       ` Alexei Starovoitov
2026-05-13  6:02   ` sashiko-bot
2026-05-12  5:59 ` [PATCH RESEND bpf-next v10 3/8] bpf: Introduce the bpf_list_del kfunc Kaitao cheng
2026-05-12  6:41   ` bot+bpf-ci
2026-05-12  9:36     ` Kaitao Cheng
2026-05-13 22:32   ` Eduard Zingerman
2026-05-12  5:59 ` [PATCH RESEND bpf-next v10 4/8] bpf: refactor __bpf_list_add to take insertion point via **prev_ptr Kaitao cheng
2026-05-13 22:33   ` Eduard Zingerman
2026-05-12  5:59 ` [PATCH RESEND bpf-next v10 5/8] bpf: Add bpf_list_add to insert node after a given list node Kaitao cheng
2026-05-12  6:41   ` bot+bpf-ci
2026-05-12 12:05     ` Kaitao Cheng
2026-05-13 20:44   ` sashiko-bot
2026-05-13 22:35   ` Eduard Zingerman
2026-05-12  5:59 ` [PATCH RESEND bpf-next v10 6/8] bpf: add bpf_list_is_first/last/empty kfuncs Kaitao cheng
2026-05-13 22:35   ` Eduard Zingerman
2026-05-12  5:59 ` [PATCH RESEND bpf-next v10 7/8] bpf: allow non-owning list-node args via __nonown_allowed Kaitao cheng
2026-05-12  6:41   ` bot+bpf-ci
2026-05-13 22:22   ` sashiko-bot [this message]
2026-05-13 22:37   ` Eduard Zingerman
2026-05-13 22:55     ` Eduard Zingerman
2026-05-12  5:59 ` [PATCH RESEND bpf-next v10 8/8] selftests/bpf: Add test cases for bpf_list_del/add/is_first/is_last/empty Kaitao cheng
2026-05-13 22:44   ` sashiko-bot

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=20260513222258.AEB08C19425@smtp.kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=bpf@vger.kernel.org \
    --cc=kaitao.cheng@linux.dev \
    --cc=sashiko-reviews@lists.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