[PATCH] sched_ext: Reject scx_bpf_destroy_dsq() in tracing programs
From: Shubhang Kaushik (Ampere)
Date: Mon Nov 02 2026 - 00:33:00 EST
scx_bpf_destroy_dsq() takes the target user DSQ's raw spinlock. However,
it is in scx_kfunc_ids_any, which is also registered for
BPF_PROG_TYPE_TRACING.
For an active root scheduler without ops.sub_attach, the compatibility
path in scx_prog_sched() lets an unassociated tracing program resolve to
that scheduler. The tracing program can then call
scx_bpf_destroy_dsq() while the target DSQ lock is already held.
For example, a scheduler which mixes FIFO and priority-queue insertions
into a user DSQ triggers scx_error() from scx_dispatch_enqueue() while
holding that DSQ's lock. scx_claim_exit() emits sched_ext_exit before
the lock is released:
scx_dispatch_enqueue()
raw_spin_lock(&dsq->lock)
scx_error()
scx_claim_exit()
trace_sched_ext_exit()
tracing BPF program
scx_bpf_destroy_dsq(dsq_id)
destroy_dsq()
raw_spin_lock_irqsave(&dsq->lock)
The tracing program recursively acquires the same raw spinlock and locks
up the CPU. Because the tracepoint runs before scx_finish_exit(),
disable_irq_work is not queued and the scheduler cannot enter its normal
disable path.
Reject scx_bpf_destroy_dsq() from tracing programs at verification time.
The kfunc remains available to SCX struct_ops and syscall programs.
Fixes: f0e1a0643a59 ("sched_ext: Implement BPF extensible scheduler class")
Signed-off-by: Shubhang Kaushik (Ampere) <sh@xxxxxxxxxx>
---
kernel/sched/ext/ext.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/kernel/sched/ext/ext.c b/kernel/sched/ext/ext.c
index f74ffb3b1aca6ee325ba583e8272be2afb0f1ecf..3ae21991b64ae51f61fe3c22f241b8c215fb4fd1 100644
--- a/kernel/sched/ext/ext.c
+++ b/kernel/sched/ext/ext.c
@@ -12134,6 +12134,9 @@ static const struct btf_kfunc_id_set scx_kfunc_set_any = {
* when scx_locked_rq() returns NULL. Taking it while the context already holds
* an rq lock, the same one or another cpu's, can deadlock.
*
+ * scx_bpf_destroy_dsq() takes a user DSQ lock. A tracing program can run while
+ * that lock is already held and recursively acquire it.
+ *
* Before returning, scx_bpf_sub_grant() and scx_bpf_sub_revoke() invoke
* ops.sub_caps_updated() of the sub-schedulers whose caps changed, so those ops
* run in the tracing program's context. No SCX op expects to run from an
@@ -12148,6 +12151,7 @@ BTF_ID_FLAGS(func, scx_bpf_cpuperf_set, KF_IMPLICIT_ARGS)
BTF_ID_FLAGS(func, scx_bpf_cidperf_set, KF_IMPLICIT_ARGS)
BTF_ID_FLAGS(func, scx_bpf_sub_grant, KF_IMPLICIT_ARGS)
BTF_ID_FLAGS(func, scx_bpf_sub_revoke, KF_IMPLICIT_ARGS)
+BTF_ID_FLAGS(func, scx_bpf_destroy_dsq, KF_IMPLICIT_ARGS)
BTF_KFUNCS_END(scx_kfunc_ids_no_tracing)
/*
---
base-commit: 6628e7d4c6b25c8d18f1345e3a20d21829aae7e4
change-id: 20261101-scx-destroy-dsq-tracing-53c0c541c155
Best regards,
--
Shubhang Kaushik (Ampere) <sh@xxxxxxxxxx>