Re: [PATCH v2 sched_ext/for-7.3 15/36] sched_ext: Add scx_cmask_ref for validated arena cmask access
From: Andrea Righi
Date: Mon Jul 06 2026 - 05:38:29 EST
Hi Tejun,
On Sun, Jul 05, 2026 at 03:40:37PM -1000, Tejun Heo wrote:
> kfuncs taking struct scx_cmask * from BPF arena memory have two problems.
> The pointer can be any value the BPF prog hands in, and the header (@base
> and @nr_cids) can be mutated by the prog concurrently with kernel access.
>
> Add scx_cmask_ref, a validated handle. _init() normalizes the input pointer
> into the arena's kern_vm range via scx_arena_to_kaddr() and snapshots
> @base/@nr_cids; downstream sizing uses the snapshot, not the live header.
> _shard() reads slices, _or() / _copy() write back; all bounded by the
> snapshot. No callers yet.
>
> Signed-off-by: Tejun Heo <tj@xxxxxxxxxx>
> ---
...
> + * scx_cmask_ref_init - Bind a scx_cmask_ref to a BPF-arena cmask
> + * @sch: scheduler whose arena hosts @src
> + * @src: BPF-supplied cmask pointer
> + * @ref: output ref
> + *
> + * Snapshot @src's @base and @nr_cids. The snapshot is necessary because BPF may
> + * mutate the live header asynchronously.
> + *
> + * Return 0 on success, -EINVAL if the snapshotted header is malformed.
> + */
> +int scx_cmask_ref_init(struct scx_sched *sch, const struct scx_cmask *src,
> + struct scx_cmask_ref *ref)
> +{
> + struct scx_cmask *kern_src = scx_arena_to_kaddr(sch, src);
> + u32 base, nr_cids, npossible = num_possible_cpus();
> +
> + base = READ_ONCE(kern_src->base);
> + nr_cids = READ_ONCE(kern_src->nr_cids);
> +
> + if (unlikely(base >= npossible || nr_cids > npossible - base))
> + return -EINVAL;
We validate the requested CID range, but not whether the cmask declares enough
bits[] capacity for that range, unless I'm missing something. For example,
nr_cids can require multiple words while alloc_words is one. Does the ref also
need to account for the storage capacity described by alloc_words?
Thanks,
-Andrea
> +
> + ref->sch = sch;
> + ref->src = kern_src;
> + ref->base = base;
> + ref->nr_cids = nr_cids;
> +
> + ref->shard_first = scx_cid_to_shard[base];
> + if (likely(nr_cids))
> + ref->shard_end = scx_cid_to_shard[base + nr_cids - 1] + 1;
> + else
> + ref->shard_end = ref->shard_first;
> +
> + return 0;
> +}