Re: [PATCH bpf-next v3 2/2] selftests/bpf: test bpf_cpumask_populate() rejects a borrowed cpumask
"Emil Tsalapatis" <[email protected]>
| Newsgroups | dev.linux.lists.sched-ext,org.kernel.vger.bpf |
|---|---|
| Message-ID | <[email protected]> |
On Thu Jul 9, 2026 at 2:28 PM EDT, Nicholas Dudar wrote: > bpf_cpumask_populate() now takes a struct bpf_cpumask *, so update the > kfunc declaration and drop the struct cpumask * casts in the existing > populate tests. Add test_populate_borrowed_destination, which passes a > borrowed task->cpus_ptr and asserts the verifier rejects it as a writable > destination. > > Signed-off-by: Nicholas Dudar <[email protected]> > Assisted-by: Claude:claude-opus-4-8 Reviewed-by: Emil Tsalapatis <[email protected]> One thing that'd be nice is an explicit test that checks modifying the cpumask being returned by scx_bpf_get_idle_cpumask, since this was the motivation in the first place. But we don't have a sched_ext test in selftests/bpf, so it's not worth the complexity. Since what we're really testing is that bpf_cpumask -> cpumask conversions are acceptable but not the opposite, I think the tp test suffices. > --- > .../selftests/bpf/progs/cpumask_common.h | 2 +- > .../selftests/bpf/progs/cpumask_failure.c | 23 +++++++++++++++++-- > .../selftests/bpf/progs/cpumask_success.c | 6 ++--- > 3 files changed, 25 insertions(+), 6 deletions(-) > > diff --git a/tools/testing/selftests/bpf/progs/cpumask_common.h b/tools/testing/selftests/bpf/progs/cpumask_common.h > index 86085b79f5ca..8fe01308d210 100644 > --- a/tools/testing/selftests/bpf/progs/cpumask_common.h > +++ b/tools/testing/selftests/bpf/progs/cpumask_common.h > @@ -61,7 +61,7 @@ u32 bpf_cpumask_any_distribute(const struct cpumask *src) __ksym __weak; > u32 bpf_cpumask_any_and_distribute(const struct cpumask *src1, > const struct cpumask *src2) __ksym __weak; > u32 bpf_cpumask_weight(const struct cpumask *cpumask) __ksym __weak; > -int bpf_cpumask_populate(struct cpumask *cpumask, void *src, size_t src__sz) __ksym __weak; > +int bpf_cpumask_populate(struct bpf_cpumask *cpumask, void *src, size_t src__sz) __ksym __weak; > > void bpf_rcu_read_lock(void) __ksym __weak; > void bpf_rcu_read_unlock(void) __ksym __weak; > diff --git a/tools/testing/selftests/bpf/progs/cpumask_failure.c b/tools/testing/selftests/bpf/progs/cpumask_failure.c > index 4c45346fe6f7..74b4cd4bcdbb 100644 > --- a/tools/testing/selftests/bpf/progs/cpumask_failure.c > +++ b/tools/testing/selftests/bpf/progs/cpumask_failure.c > @@ -231,7 +231,7 @@ int BPF_PROG(test_populate_invalid_destination, struct task_struct *task, u64 cl > u64 bits; > int ret; > > - ret = bpf_cpumask_populate((struct cpumask *)invalid, &bits, sizeof(bits)); > + ret = bpf_cpumask_populate(invalid, &bits, sizeof(bits)); > if (!ret) > err = 2; > > @@ -252,7 +252,7 @@ int BPF_PROG(test_populate_invalid_source, struct task_struct *task, u64 clone_f > return 0; > } > > - ret = bpf_cpumask_populate((struct cpumask *)local, garbage, 8); > + ret = bpf_cpumask_populate(local, garbage, 8); > if (!ret) > err = 2; > > @@ -260,3 +260,22 @@ int BPF_PROG(test_populate_invalid_source, struct task_struct *task, u64 clone_f > > return 0; > } > + > +SEC("tp_btf/task_newtask") > +__failure __msg("expected pointer to STRUCT bpf_cpumask but R1 has a pointer to STRUCT cpumask") > +int BPF_PROG(test_populate_borrowed_destination, struct task_struct *task, u64 clone_flags) > +{ > + u64 bits; > + int ret; > + > + /* > + * task->cpus_ptr is a borrowed, read-only struct cpumask *, not an > + * owned struct bpf_cpumask *. The verifier must reject it as a > + * writable destination for bpf_cpumask_populate(). > + */ > + ret = bpf_cpumask_populate((struct bpf_cpumask *)task->cpus_ptr, &bits, sizeof(bits)); > + if (!ret) > + err = 2; > + > + return 0; > +} > diff --git a/tools/testing/selftests/bpf/progs/cpumask_success.c b/tools/testing/selftests/bpf/progs/cpumask_success.c > index 774706e7b058..36f77b9732d4 100644 > --- a/tools/testing/selftests/bpf/progs/cpumask_success.c > +++ b/tools/testing/selftests/bpf/progs/cpumask_success.c > @@ -785,7 +785,7 @@ int BPF_PROG(test_populate_reject_small_mask, struct task_struct *task, u64 clon > return 0; > > /* The kfunc should prevent this operation */ > - ret = bpf_cpumask_populate((struct cpumask *)local, &toofewbits, sizeof(toofewbits)); > + ret = bpf_cpumask_populate(local, &toofewbits, sizeof(toofewbits)); > if (ret != -EACCES) > err = 2; > > @@ -824,7 +824,7 @@ int BPF_PROG(test_populate_reject_unaligned, struct task_struct *task, u64 clone > /* Misalign the source array by a byte. */ > src = &((char *)bits)[1]; > > - ret = bpf_cpumask_populate((struct cpumask *)mask, src, CPUMASK_TEST_MASKLEN); > + ret = bpf_cpumask_populate(mask, src, CPUMASK_TEST_MASKLEN); > if (ret != -EINVAL) > err = 2; > > @@ -855,7 +855,7 @@ int BPF_PROG(test_populate, struct task_struct *task, u64 clone_flags) > } > > /* Pass the entire bits array, the kfunc will only copy the valid bits. */ > - ret = bpf_cpumask_populate((struct cpumask *)mask, bits, CPUMASK_TEST_MASKLEN); > + ret = bpf_cpumask_populate(mask, bits, CPUMASK_TEST_MASKLEN); > if (ret) { > err = 2; > goto out;