Re: [PATCH bpf v2 2/2] bpf: Reject untrusted pointers in refcount_acquire
Ning Ding <[email protected]>
| Newsgroups | dev.linux.lists.sashiko-reviews,org.kernel.vger.bpf |
|---|---|
| Message-ID | <CAJP4ius__AtzaGNVAPbHn+JyfR6+E8=SHNhcZA-dKdGVfnbk0A@mail.gmail.com> |
This seems to be a separate issue from the refcount_acquire argument check... For a pointer without NON_OWN_REF, code inspection shows that direct access can reach verifier_bug(). If that warning is emitted, a system configured with panic_on_warn may panic. (haven't reproduced that yet) In my runtime experiment, the stale address was reused for another BPF object before physical reclamation. A read through the stale pointer returned a value belonging to the recycled object. And I did not observe a WARN, panic, physical-kfree UAF, or a successful stale write in my experiment configuration. So the current experimental evidence shows only a stale read from a recycled object, while the panic only remains possibilities in the source code, but haven't done any experiments to prove that it is feasible. Regards, Ning Ding On Sun, Jul 26, 2026 at 5:13 PM <[email protected]> wrote: > > Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: > > Pre-existing issues: > - [Critical] check_ptr_to_btf_access() incorrectly allows writes to PTR_UNTRUSTED allocated objects or triggers a verifier_bug WARN_ONCE when reading from them. > -- > > --- Patch [2]: [PATCH bpf v2 2/2] bpf: Reject untrusted pointers in refcount_acquire --- > commit 80e6c61503b2eee2d4804b0a7ec8927827ed7d92 > Author: Ning Ding <[email protected]> > > bpf: Reject untrusted pointers in refcount_acquire > > This commit fixes an issue where a refcounted map kptr could still be passed > to bpf_refcount_acquire() after being marked PTR_UNTRUSTED due to > bpf_rcu_read_unlock(). It updates check_kfunc_args() to reject PTR_UNTRUSTED > arguments for KF_ARG_PTR_TO_REFCOUNTED_KPTR. > > Link: https://lore.kernel.org/r/[email protected] > > > diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c > > index 1e7343b625de5..63b1d997fe804 100644 > > --- a/kernel/bpf/verifier.c > > +++ b/kernel/bpf/verifier.c > > @@ -12414,6 +12414,11 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_kfunc_call_ > > meta->subprogno = reg->subprogno; > > break; > > case KF_ARG_PTR_TO_REFCOUNTED_KPTR: > > + if (reg->type & PTR_UNTRUSTED) { > > + verbose(env, "%s is an untrusted refcounted kptr\n", > > + reg_arg_name(env, argno)); > > + return -EACCES; > > + } > > [Severity: Critical] > This is a pre-existing issue, but I noticed a similar problem with > PTR_UNTRUSTED handling in check_ptr_to_btf_access() for allocated objects: > > kernel/bpf/verifier.c:check_ptr_to_btf_access() { > ... > if (atype != BPF_READ && !type_is_ptr_alloc_obj(reg->type)) { > verbose(env, "only read is supported\n"); > return -EACCES; > } > > if (type_is_alloc(reg->type) && !type_is_non_owning_ref(reg->type) && > !(reg->type & MEM_RCU) && !reg_is_referenced(env, reg)) { > verifier_bug(env, "allocated object must have a referenced id"); > return -EFAULT; > } > ... > } > > Does this logic incorrectly allow writes to PTR_UNTRUSTED allocated objects > or trigger a verifier_bug WARN_ONCE when reading from them? > > If a program loads a program-allocated kptr containing an RCU-protected field > inside bpf_rcu_read_lock(), the verifier marks it MEM_ALLOC | MEM_RCU (and > NON_OWN_REF if it contains a bpf_rb_node or bpf_list_node). When the program > calls bpf_rcu_read_unlock(), it strips MEM_RCU and adds PTR_UNTRUSTED. > > If the program subsequently tries to read or write this pointer, > type_is_ptr_alloc_obj(reg->type) evaluates to true because it ignores > PTR_UNTRUSTED, bypassing the read-only check for writes. > > Then, if the pointer lacks NON_OWN_REF, it hits the type_is_alloc() condition > and triggers a verifier_bug(), leading to a BPF_WARN_ONCE. If it has > NON_OWN_REF, it bypasses the verifier_bug() check entirely, and proceeds to > allow a memory write to the untrusted pointer. > > Could a malicious BPF program exploit this to achieve a local denial of > service via panic_on_warn or a use-after-free memory write? > > > if (!type_is_ptr_alloc_obj(reg->type)) { > > verbose(env, "%s is neither owning or non-owning ref\n", > > reg_arg_name(env, argno)); > > [ ... ] > > -- > Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=2