public inbox for sched-ext@lists.linux.dev
 help / color / mirror / Atom feed
* [PATCH 1/3] sched_ext: fix NULL deref in bpf_scx_unreg() due to ops->priv race
@ 2026-03-26  2:28 zhidao su
  2026-03-26  2:28 ` [PATCH 2/3] selftests/sched_ext: Fix dsq_reenq test reliability zhidao su
                   ` (2 more replies)
  0 siblings, 3 replies; 6+ messages in thread
From: zhidao su @ 2026-03-26  2:28 UTC (permalink / raw)
  To: sched-ext
  Cc: linux-kernel, tj, void, arighi, changwoo, peterz, mingo,
	zhidao su

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@xiaomi.com>
---
 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


^ permalink raw reply related	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2026-03-26  7:06 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-26  2:28 [PATCH 1/3] sched_ext: fix NULL deref in bpf_scx_unreg() due to ops->priv race zhidao su
2026-03-26  2:28 ` [PATCH 2/3] selftests/sched_ext: Fix dsq_reenq test reliability zhidao su
2026-03-26  2:28 ` [PATCH 3/3] selftests/sched_ext: Fix consume_immed " zhidao su
2026-03-26  7:06   ` Andrea Righi
2026-03-26  2:45 ` [PATCH 1/3] sched_ext: fix NULL deref in bpf_scx_unreg() due to ops->priv race Tejun Heo
2026-03-26  5:13   ` zhidao su

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox