selftests/bpf: Test nullable per-CPU kptr identity after exchange

Pass two unchecked bpf_percpu_obj_new() results to bpf_kptr_xchg()
inside an RCU critical section. The exchanges consume ownership and
leave nullable RCU-protected aliases.

Checking the first alias must not make the second non-NULL. Verify that
bpf_this_cpu_ptr() still rejects the unchecked second alias.

Signed-off-by: Amery Hung <ameryhung@gmail.com>
Link: https://lore.kernel.org/r/20260911220415.1396439-23-ameryhung@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
This commit is contained in:
Amery Hung 2026-09-11 15:04:14 -07:00 committed by Alexei Starovoitov
parent 5dc1549afa
commit 4f18de58a4

View File

@ -24,6 +24,7 @@ struct val_600b_t {
struct elem {
long sum;
struct val_t __percpu_kptr *pc;
struct val_t __percpu_kptr *pc2;
};
struct {
@ -46,6 +47,8 @@ struct {
struct task_struct *bpf_task_from_pid(s32 pid) __ksym;
void bpf_task_release(struct task_struct *p) __ksym;
void bpf_rcu_read_lock(void) __ksym;
void bpf_rcu_read_unlock(void) __ksym;
long ret;
@ -123,6 +126,38 @@ int BPF_PROG(test_array_map_3)
return 0;
}
SEC("?fentry.s/bpf_fentry_test1")
__failure __msg("Possibly NULL pointer passed to trusted R1")
int BPF_PROG(reject_nullable_percpu_xchg_alias)
{
struct val_t __percpu_kptr *p1, *p2, *old;
struct val_t *v;
struct elem *e;
int index = 0;
e = bpf_map_lookup_elem(&array, &index);
if (!e)
return 0;
p1 = bpf_percpu_obj_new(struct val_t);
p2 = bpf_percpu_obj_new(struct val_t);
bpf_rcu_read_lock();
old = bpf_kptr_xchg(&e->pc, p1);
if (old)
bpf_percpu_obj_drop(old);
old = bpf_kptr_xchg(&e->pc2, p2);
if (old)
bpf_percpu_obj_drop(old);
if (p1) {
v = bpf_this_cpu_ptr(p2);
v->b = 1;
}
bpf_rcu_read_unlock();
return 0;
}
SEC("?fentry.s/bpf_fentry_test1")
__failure __msg("R1 expected for bpf_percpu_obj_drop()")
int BPF_PROG(test_array_map_4)