[PATCH] sched/numa: Prevent race on sysctl_numa_balancing static key
From: Chen Jinghuang
Date: Mon Aug 03 2026 - 09:16:26 EST
While fuzzing with syzkaller, a concurrent 1/0 write race to
/proc/sys/kernel/numa_balancing was found that trips a jump_label
WARN_ON_ONCE().
Concurrent writes of 1/0 to /proc/sys/kernel/numa_balancing enable/disable
the same static key. Enable sets key->enabled to -1 while holding the
lock, restoring it to 1 only after jump_label_update(); disable checks
enabled before taking the lock. Under concurrency, disable reads -1 and
trips WARN_ON_ONCE().
Timeline:
write 1 → enable write 0 → disable
│ │
├─ static_key_enable_cpuslocked() ├─ static_key_disable_cpuslocked()
│ jump_label_lock() │ atomic_read(enabled) ← before lock
│ atomic_set(enabled, -1) ◄───────┼── reads -1
│ jump_label_update() │ WARN_ON_ONCE(enabled!=0)
│ atomic_set_release(enabled,1) │ return ← disable skipped
│ jump_label_unlock() │
Serialize the enable/disable switch at the convergence point in
set_numabalancing_state() with a mutex, so the transient -1 in
key->enabled never leaks to a concurrent disable and this WARN_ON_ONCE
no longer trips.
This follows existing kernel practice, e.g. timer_key_mutex guarding
timers_update_migration() (kernel/time/timer.c) and perf_sched_mutex
guarding static_branch_enable() (kernel/events/core.c).
Fixes: 1dbb6704de91 ("jump_label: Fix concurrent static_key_enable/disable()")
Reported-by: Zhang zhaotian <zhangzhaotian@xxxxxxxxxxxxxx>
Signed-off-by: Chen Jinghuang <chenjinghuang2@xxxxxxxxxx>
---
kernel/sched/core.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index 96226707c2f6..61fb0d7966e4 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -4629,13 +4629,17 @@ static void __set_numabalancing_state(bool enabled)
static_branch_disable(&sched_numa_balancing);
}
+static DEFINE_MUTEX(numabalancing_mutex);
+
void set_numabalancing_state(bool enabled)
{
+ mutex_lock(&numabalancing_mutex);
if (enabled)
sysctl_numa_balancing_mode = NUMA_BALANCING_NORMAL;
else
sysctl_numa_balancing_mode = NUMA_BALANCING_DISABLED;
__set_numabalancing_state(enabled);
+ mutex_unlock(&numabalancing_mutex);
}
#ifdef CONFIG_PROC_SYSCTL
--
2.34.1