selftests/bpf: Reject refcount acquisition after RCU unlock

Add a sleepable verifier test that loads a refcount-only local kptr in an
explicit RCU read-side critical section, ends the section, and passes the
pointer to bpf_refcount_acquire().

The loaded pointer never carries NON_OWN_REF. After RCU unlock it retains
MEM_ALLOC while becoming PTR_UNTRUSTED, which previously made the kfunc
argument check accept it as a live allocated object. Expect verification to
reject the untrusted argument instead.

Signed-off-by: Ning Ding <dingning04@gmail.com>
[ kkd: Rewrote commit log ]
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Link: https://lore.kernel.org/r/20260904084325.52250-9-memxor@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
This commit is contained in:
Ning Ding 2026-09-04 10:43:21 +02:00 committed by Alexei Starovoitov
parent 7441ee8276
commit 9492baf853

View File

@ -189,6 +189,33 @@ long rbtree_remove_after_rcu_unlock(void *ctx)
return 0;
}
SEC("?syscall")
__failure __msg("R1 is neither owning or non-owning ref")
long refcount_acquire_after_rcu_unlock(void *ctx)
{
struct map_value_refcount_only *mapval;
struct node_refcount_only *node, *ref;
int idx = 0;
mapval = bpf_map_lookup_elem(&stashed_refcount_only, &idx);
if (!mapval)
return 0;
bpf_rcu_read_lock();
node = mapval->node;
if (!node) {
bpf_rcu_read_unlock();
return 0;
}
bpf_rcu_read_unlock();
ref = bpf_refcount_acquire(node);
if (ref)
bpf_obj_drop(ref);
return 0;
}
SEC("?syscall")
__failure __msg("invalid mem access 'scalar'")
long graph_kptr_after_spin_unlock(void *ctx)