> diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c
> --- a/kernel/bpf/helpers.c
> +++ b/kernel/bpf/helpers.c

[ ... ]

> @@ -2575,12 +2577,16 @@ static struct bpf_list_node *__bpf_list_del(struct 
> bpf_list_head *head,
>
>  __bpf_kfunc struct bpf_list_node *bpf_list_pop_front(struct bpf_list_head 
> *head)
>  {
> -     return __bpf_list_del(head, false);
> +     struct list_head *h = (void *)head;
> +
> +     return __bpf_list_del(head, h->next);
>  }

This addresses an unaddressed review comment from Emil Tsalapatis in v8.
The code reads h->next before __bpf_list_del checks if the list is
initialized. If the list is uninitialized (h->next is NULL), a NULL pointer
is passed to __bpf_list_del.

While the function will eventually initialize the list and return NULL without
dereferencing the NULL pointer:

kernel/bpf/helpers.c:__bpf_list_del() {
        if (unlikely(!h->next)) {
                INIT_LIST_HEAD(h);
                return NULL;
        }
        ...
}

this is counterintuitive - passing a potentially garbage value that is later
ignored.

Emil suggested moving the init check logic into the top-level kfuncs
(bpf_list_pop_front/bpf_list_pop_back) to ensure the list_head passed to
__bpf_list_del is always valid. You can also just init the list and return
NULL in that case - we know it's empty.

The same issue applies to bpf_list_pop_back() which reads h->prev before
the initialization check.

Original comment from Emil Tsalapatis (Thu, 19 Mar 2026 12:17:50 -0400):
https://lore.kernel.org/bpf/[email protected]/

"The new code reads n _before_ we check if the list is initialized. So the n
we are passing from the caller may well be NULL. However, __bpf_list_del()
will in that case now a) call INIT_LIST_HEAD(() to properly set up prev/next,
b) call list_empty() on the newly initialized list and exit without ever
reading the NULL passed by the caller.

This is kind of counterintuitive: We are passing essentially a garbage value
to __bpf_list_del that we thankfully end upi ignoring. Can you move the init
check logic into the top-level kfuncs to make sure the list_head we're passing
to __bpf_list_del is always valid? You can also just init the list and return
NULL in that case - we know it's empty."

This issue remains unaddressed in v10.


---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md

CI run summary: https://github.com/kernel-patches/bpf/actions/runs/25009536772

Reply via email to