[PATCH] sched_ext: fix NULL deref in bpf_scx_unreg() due to ops->priv race
From: zhidao su
Date: Wed Mar 25 2026 - 19:44:32 EST
The reload_loop selftest triggers a KASAN null-ptr-deref at
scx_claim_exit+0x83 when two threads concurrently attach and
destroy BPF schedulers using the same ops map.
The race occurs between bpf_scx_unreg() and a concurrent reg():
1. Thread A's bpf_scx_unreg() calls scx_disable() then
kthread_flush_work(), which blocks until disable completes
and transitions state back to SCX_DISABLED.
2. With state SCX_DISABLED, a concurrent reg() allocates a
new sch_B and sets ops->priv = sch_B under scx_enable_mutex.
3. Thread A's bpf_scx_unreg() then executes
RCU_INIT_POINTER(ops->priv, NULL), overwriting sch_B.
4. When Thread B's link is destroyed, bpf_scx_unreg() reads
ops->priv == NULL and passes it to scx_disable(), which
calls scx_claim_exit(NULL), crashing at NULL+0x310.
Fix by adding a NULL guard for the case where ops->priv was
never set, and by acquiring scx_enable_mutex before clearing
ops->priv so that the check-and-clear is atomic with respect
to reg() which also sets ops->priv under scx_enable_mutex.
Signed-off-by: zhidao su <suzhidao@xxxxxxxxxx>
---
kernel/sched/ext.c | 15 ++++++++++++++-
1 file changed, 14 insertions(+), 1 deletion(-)
diff --git a/kernel/sched/ext.c b/kernel/sched/ext.c
index 551bfb99157d..01077cc2eb62 100644
--- a/kernel/sched/ext.c
+++ b/kernel/sched/ext.c
@@ -7372,9 +7372,22 @@ static void bpf_scx_unreg(void *kdata, struct bpf_link *link)
struct sched_ext_ops *ops = kdata;
struct scx_sched *sch = rcu_dereference_protected(ops->priv, true);
+ if (!sch)
+ return;
+
scx_disable(sch, SCX_EXIT_UNREG);
kthread_flush_work(&sch->disable_work);
- RCU_INIT_POINTER(ops->priv, NULL);
+
+ /*
+ * A concurrent reg() may have already installed a new scheduler into
+ * ops->priv by the time disable completes. Clear ops->priv only if it
+ * still holds our sch.
+ */
+ mutex_lock(&scx_enable_mutex);
+ if (rcu_access_pointer(ops->priv) == sch)
+ RCU_INIT_POINTER(ops->priv, NULL);
+ mutex_unlock(&scx_enable_mutex);
+
kobject_put(&sch->kobj);
}
--
2.43.0