Re: [PATCH 11/34] sched_ext: Enforce scheduler ownership when updating slice and dsq_vtime
From: Andrea Righi
Date: Thu Feb 26 2026 - 10:31:54 EST
Hi Tejun,
On Tue, Feb 24, 2026 at 07:00:46PM -1000, Tejun Heo wrote:
> scx_bpf_task_set_slice() and scx_bpf_task_set_dsq_vtime() now verify that
> the calling scheduler has authority over the task before allowing updates.
> This prevents schedulers from modifying tasks that don't belong to them in
> hierarchical scheduling configurations.
>
> Direct writes to p->scx.slice and p->scx.dsq_vtime are deprecated and now
> trigger warnings. They will be disallowed in a future release.
>
> Signed-off-by: Tejun Heo <tj@xxxxxxxxxx>
My concern with this is that we may introduce some overhead for those
schedulers that require frequent adjustment of slice / dsq_vtime directly.
While the scx_task_on_sched() check itself has likely zero impact, the
kfunc invocations can potentially introduce measurable overhead.
I'm wondering if we could instead delegate the authority check at
verification time, introducing something similar to PTR_TRUSTED
(PTR_SCX_AUTH?) to struct task_struct * to represent that the scheduler has
authority to access the task and allow direct writes to p->scx.slice /
p->scx.dsq_vtime only when the register has that flag.
Then:
- for tasks passed from the core opts (enqueue, dispatch, etc.) we
automatically tag them with PTR_SCX_AUTH,
- tasks obtained externally (e.g., via bpf_task_from_pid()): they don't
have the flag (so no modification allowed) and in this case maybe we
provide a scx_bpf_auth_task() kfunc to perform the scx_task_on_sched()
check that returns p (or NULL) setting the auth flag if the scheduler
has full access to the task.
What do you think?
Thanks,
-Andrea
> ---
> kernel/sched/ext.c | 41 ++++++++++++++++++++++++++++++++---------
> 1 file changed, 32 insertions(+), 9 deletions(-)
>
> diff --git a/kernel/sched/ext.c b/kernel/sched/ext.c
> index 56ac2d5655a2..f16ce4deed88 100644
> --- a/kernel/sched/ext.c
> +++ b/kernel/sched/ext.c
> @@ -5872,12 +5872,17 @@ static int bpf_scx_btf_struct_access(struct bpf_verifier_log *log,
>
> t = btf_type_by_id(reg->btf, reg->btf_id);
> if (t == task_struct_type) {
> - if (off >= offsetof(struct task_struct, scx.slice) &&
> - off + size <= offsetofend(struct task_struct, scx.slice))
> - return SCALAR_VALUE;
> - if (off >= offsetof(struct task_struct, scx.dsq_vtime) &&
> - off + size <= offsetofend(struct task_struct, scx.dsq_vtime))
> + /*
> + * COMPAT: Will be removed in v6.23.
> + */
> + if ((off >= offsetof(struct task_struct, scx.slice) &&
> + off + size <= offsetofend(struct task_struct, scx.slice)) ||
> + (off >= offsetof(struct task_struct, scx.dsq_vtime) &&
> + off + size <= offsetofend(struct task_struct, scx.dsq_vtime))) {
> + pr_warn("sched_ext: Writing directly to p->scx.slice/dsq_vtime is deprecated, use scx_bpf_task_set_slice/dsq_vtime()");
> return SCALAR_VALUE;
> + }
> +
> if (off >= offsetof(struct task_struct, scx.disallow) &&
> off + size <= offsetofend(struct task_struct, scx.disallow))
> return SCALAR_VALUE;
> @@ -7096,12 +7101,21 @@ __bpf_kfunc_start_defs();
> * scx_bpf_task_set_slice - Set task's time slice
> * @p: task of interest
> * @slice: time slice to set in nsecs
> + * @aux: implicit BPF argument to access bpf_prog_aux hidden from BPF progs
> *
> * Set @p's time slice to @slice. Returns %true on success, %false if the
> * calling scheduler doesn't have authority over @p.
> */
> -__bpf_kfunc bool scx_bpf_task_set_slice(struct task_struct *p, u64 slice)
> +__bpf_kfunc bool scx_bpf_task_set_slice(struct task_struct *p, u64 slice,
> + const struct bpf_prog_aux *aux)
> {
> + struct scx_sched *sch;
> +
> + guard(rcu)();
> + sch = scx_prog_sched(aux);
> + if (unlikely(!scx_task_on_sched(sch, p)))
> + return false;
> +
> p->scx.slice = slice;
> return true;
> }
> @@ -7110,12 +7124,21 @@ __bpf_kfunc bool scx_bpf_task_set_slice(struct task_struct *p, u64 slice)
> * scx_bpf_task_set_dsq_vtime - Set task's virtual time for DSQ ordering
> * @p: task of interest
> * @vtime: virtual time to set
> + * @aux: implicit BPF argument to access bpf_prog_aux hidden from BPF progs
> *
> * Set @p's virtual time to @vtime. Returns %true on success, %false if the
> * calling scheduler doesn't have authority over @p.
> */
> -__bpf_kfunc bool scx_bpf_task_set_dsq_vtime(struct task_struct *p, u64 vtime)
> +__bpf_kfunc bool scx_bpf_task_set_dsq_vtime(struct task_struct *p, u64 vtime,
> + const struct bpf_prog_aux *aux)
> {
> + struct scx_sched *sch;
> +
> + guard(rcu)();
> + sch = scx_prog_sched(aux);
> + if (unlikely(!scx_task_on_sched(sch, p)))
> + return false;
> +
> p->scx.dsq_vtime = vtime;
> return true;
> }
> @@ -7995,8 +8018,8 @@ __bpf_kfunc void scx_bpf_events(struct scx_event_stats *events,
> __bpf_kfunc_end_defs();
>
> BTF_KFUNCS_START(scx_kfunc_ids_any)
> -BTF_ID_FLAGS(func, scx_bpf_task_set_slice, KF_RCU);
> -BTF_ID_FLAGS(func, scx_bpf_task_set_dsq_vtime, KF_RCU);
> +BTF_ID_FLAGS(func, scx_bpf_task_set_slice, KF_IMPLICIT_ARGS | KF_RCU);
> +BTF_ID_FLAGS(func, scx_bpf_task_set_dsq_vtime, KF_IMPLICIT_ARGS | KF_RCU);
> BTF_ID_FLAGS(func, scx_bpf_kick_cpu, KF_IMPLICIT_ARGS)
> BTF_ID_FLAGS(func, scx_bpf_dsq_nr_queued)
> BTF_ID_FLAGS(func, scx_bpf_destroy_dsq)
> --
> 2.53.0
>