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;
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.