selftests/bpf: Reject non-percpu values in percpu kptr fields

Add verifier coverage for the two ways a non-percpu pointer can be stored
in a __percpu_kptr field: a program-BTF local allocation returned by
bpf_obj_new(), and a referenced kernel-BTF task_struct pointer.

Without the verifier fix, both programs are unexpectedly accepted and the
negative tests fail. Requiring MEM_PERCPU makes both programs fail
verification with the expected invalid-kptr diagnostic.

Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Link: https://lore.kernel.org/r/20260904084325.52250-3-memxor@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
This commit is contained in:
Kumar Kartikeya Dwivedi 2026-09-04 10:43:15 +02:00 committed by Alexei Starovoitov
parent 048029ba1c
commit 17487b31f4

View File

@ -33,6 +33,20 @@ struct {
__type(value, struct elem);
} array SEC(".maps");
struct kernel_percpu_elem {
struct task_struct __percpu_kptr *task;
};
struct {
__uint(type, BPF_MAP_TYPE_ARRAY);
__uint(max_entries, 1);
__type(key, int);
__type(value, struct kernel_percpu_elem);
} kernel_percpu_array SEC(".maps");
struct task_struct *bpf_task_from_pid(s32 pid) __ksym;
void bpf_task_release(struct task_struct *p) __ksym;
long ret;
SEC("?fentry/bpf_fentry_test1")
@ -137,6 +151,51 @@ int BPF_PROG(test_array_map_5)
return 0;
}
SEC("?syscall")
__failure __msg("invalid kptr access, R2 type=trusted_ptr_ expected=ptr_task_struct")
int reject_kernel_ptr_into_percpu_kptr(void *ctx)
{
struct kernel_percpu_elem *e;
struct task_struct *p, *old;
int index = 0;
e = bpf_map_lookup_elem(&kernel_percpu_array, &index);
if (!e)
return 0;
p = bpf_task_from_pid(1);
if (!p)
return 0;
old = bpf_kptr_xchg(&e->task, p);
if (old)
bpf_task_release(old);
return 0;
}
SEC("?fentry.s/bpf_fentry_test1")
__failure __msg("invalid kptr access, R2 type=ptr_ expected=ptr_val_t")
int BPF_PROG(reject_plain_alloc_into_percpu_kptr)
{
struct val_t __percpu_kptr *old;
struct val_t *p;
struct elem *e;
int index = 0;
e = bpf_map_lookup_elem(&array, &index);
if (!e)
return 0;
p = bpf_obj_new(struct val_t);
if (!p)
return 0;
old = bpf_kptr_xchg(&e->pc, p);
if (old)
bpf_percpu_obj_drop(old);
return 0;
}
SEC("?fentry.s/bpf_fentry_test1")
__failure __msg("bpf_percpu_obj_new type ID argument must be of a struct of scalars")
int BPF_PROG(test_array_map_6)