mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH] sched/numa: Prevent race on sysctl_numa_balancing static key
@ 2026-08-03 12:30 Chen Jinghuang
  2026-08-04  5:09 ` K Prateek Nayak
  0 siblings, 1 reply; 5+ messages in thread
From: Chen Jinghuang @ 2026-08-03 12:30 UTC (permalink / raw)
  To: Ingo Molnar, Peter Zijlstra, Juri Lelli, Vincent Guittot, Paolo Bonzini
  Cc: Dietmar Eggemann, Steven Rostedt, Ben Segall, Mel Gorman,
	Valentin Schneider, K Prateek Nayak, linux-kernel

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@h-partners.com>
Signed-off-by: Chen Jinghuang <chenjinghuang2@huawei.com>
---
 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


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

* Re: [PATCH] sched/numa: Prevent race on sysctl_numa_balancing static key
  2026-08-03 12:30 [PATCH] sched/numa: Prevent race on sysctl_numa_balancing static key Chen Jinghuang
@ 2026-08-04  5:09 ` K Prateek Nayak
  2026-08-04  8:35   ` chenjinghuang
  0 siblings, 1 reply; 5+ messages in thread
From: K Prateek Nayak @ 2026-08-04  5:09 UTC (permalink / raw)
  To: Chen Jinghuang, Ingo Molnar, Peter Zijlstra, Juri Lelli,
	Vincent Guittot, Paolo Bonzini
  Cc: Dietmar Eggemann, Steven Rostedt, Ben Segall, Mel Gorman,
	Valentin Schneider, linux-kernel

Hell Chen,

On 8/3/2026 6:00 PM, Chen Jinghuang wrote:
> +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);
>  }

Doesn't sysctl_numa_balancing() directly call __set_numabalancing_state()
and this bit is only used by check_numabalancing_enable() on the mm side
during early init?

I think you should move this serialization into sysctl_numa_balancing()
because nothing can race during early init and we only need this for sysfs
writes.

-- 
Thanks and Regards,
Prateek


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

* Re: [PATCH] sched/numa: Prevent race on sysctl_numa_balancing static key
  2026-08-04  5:09 ` K Prateek Nayak
@ 2026-08-04  8:35   ` chenjinghuang
  2026-08-04  8:44     ` K Prateek Nayak
  0 siblings, 1 reply; 5+ messages in thread
From: chenjinghuang @ 2026-08-04  8:35 UTC (permalink / raw)
  To: K Prateek Nayak, Ingo Molnar, Peter Zijlstra, Juri Lelli,
	Vincent Guittot, Paolo Bonzini
  Cc: Dietmar Eggemann, Steven Rostedt, Ben Segall, Mel Gorman,
	Valentin Schneider, linux-kernel

On 8/4/2026 1:09 PM, K Prateek Nayak wrote:
> Hell Chen,
> 
> On 8/3/2026 6:00 PM, Chen Jinghuang wrote:
>> +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);
>>  }
> 
> Doesn't sysctl_numa_balancing() directly call __set_numabalancing_state()
> and this bit is only used by check_numabalancing_enable() on the mm side
> during early init?
> 
> I think you should move this serialization into sysctl_numa_balancing()
> because nothing can race during early init and we only need this for sysfs
> writes.
> 
You're right - my mistake, I'll move numabalancing_mutex into sysctl_numa_balancing()
and drop it from the early-init path. No one races during init, so the lock is only
needed for sysfs writes:

+static DEFINE_MUTEX(numabalancing_mutex);
+
 static int sysctl_numa_balancing(const struct ctl_table *table, int write,
 			  void *buffer, size_t *lenp, loff_t *ppos)
 {
@@ -4666,11 +4668,13 @@ static int sysctl_numa_balancing(const struct ctl_table *table, int write,
 	if (err < 0)
 		return err;
 	if (write) {
+		mutex_lock(&numabalancing_mutex);
 		if (!(sysctl_numa_balancing_mode & NUMA_BALANCING_MEMORY_TIERING) &&
 		    (state & NUMA_BALANCING_MEMORY_TIERING))
 			reset_memory_tiering();
 		sysctl_numa_balancing_mode = state;
 		__set_numabalancing_state(state);
+		mutex_unlock(&numabalancing_mutex);
 	}
 	return err;
 }

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

* Re: [PATCH] sched/numa: Prevent race on sysctl_numa_balancing static key
  2026-08-04  8:35   ` chenjinghuang
@ 2026-08-04  8:44     ` K Prateek Nayak
  2026-08-04  8:52       ` chenjinghuang
  0 siblings, 1 reply; 5+ messages in thread
From: K Prateek Nayak @ 2026-08-04  8:44 UTC (permalink / raw)
  To: chenjinghuang, Ingo Molnar, Peter Zijlstra, Juri Lelli,
	Vincent Guittot, Paolo Bonzini
  Cc: Dietmar Eggemann, Steven Rostedt, Ben Segall, Mel Gorman,
	Valentin Schneider, linux-kernel

Hello Chen,

On 8/4/2026 2:05 PM, chenjinghuang wrote:
> You're right - my mistake, I'll move numabalancing_mutex into sysctl_numa_balancing()
> and drop it from the early-init path. No one races during init, so the lock is only
> needed for sysfs writes:
> 
> +static DEFINE_MUTEX(numabalancing_mutex);
> +
>  static int sysctl_numa_balancing(const struct ctl_table *table, int write,
>  			  void *buffer, size_t *lenp, loff_t *ppos)
>  {
> @@ -4666,11 +4668,13 @@ static int sysctl_numa_balancing(const struct ctl_table *table, int write,
>  	if (err < 0)
>  		return err;
>  	if (write) {
> +		mutex_lock(&numabalancing_mutex);

nit. You can just use a:

		guard(mutex)(&numabalancing_mutex); 

>  		if (!(sysctl_numa_balancing_mode & NUMA_BALANCING_MEMORY_TIERING) &&
>  		    (state & NUMA_BALANCING_MEMORY_TIERING))
>  			reset_memory_tiering();
>  		sysctl_numa_balancing_mode = state;
>  		__set_numabalancing_state(state);
> +		mutex_unlock(&numabalancing_mutex);

... and save on the need to explicitly call unlock here.

>  	}
>  	return err;
>  }

-- 
Thanks and Regards,
Prateek


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

* Re: [PATCH] sched/numa: Prevent race on sysctl_numa_balancing static key
  2026-08-04  8:44     ` K Prateek Nayak
@ 2026-08-04  8:52       ` chenjinghuang
  0 siblings, 0 replies; 5+ messages in thread
From: chenjinghuang @ 2026-08-04  8:52 UTC (permalink / raw)
  To: K Prateek Nayak, Ingo Molnar, Peter Zijlstra, Juri Lelli,
	Vincent Guittot, Paolo Bonzini
  Cc: Dietmar Eggemann, Steven Rostedt, Ben Segall, Mel Gorman,
	Valentin Schneider, linux-kernel

On 8/4/2026 4:44 PM, K Prateek Nayak wrote:
> Hello Chen,
> 
> On 8/4/2026 2:05 PM, chenjinghuang wrote:
>> You're right - my mistake, I'll move numabalancing_mutex into sysctl_numa_balancing()
>> and drop it from the early-init path. No one races during init, so the lock is only
>> needed for sysfs writes:
>>
>> +static DEFINE_MUTEX(numabalancing_mutex);
>> +
>>  static int sysctl_numa_balancing(const struct ctl_table *table, int write,
>>  			  void *buffer, size_t *lenp, loff_t *ppos)
>>  {
>> @@ -4666,11 +4668,13 @@ static int sysctl_numa_balancing(const struct ctl_table *table, int write,
>>  	if (err < 0)
>>  		return err;
>>  	if (write) {
>> +		mutex_lock(&numabalancing_mutex);
> 
> nit. You can just use a:
> 
> 		guard(mutex)(&numabalancing_mutex); 
> 
>>  		if (!(sysctl_numa_balancing_mode & NUMA_BALANCING_MEMORY_TIERING) &&
>>  		    (state & NUMA_BALANCING_MEMORY_TIERING))
>>  			reset_memory_tiering();
>>  		sysctl_numa_balancing_mode = state;
>>  		__set_numabalancing_state(state);
>> +		mutex_unlock(&numabalancing_mutex);
> 
> ... and save on the need to explicitly call unlock here.
> 
>>  	}
>>  	return err;
>>  }
> 
Thanks Prateek, I'll update the patch accordingly.

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

end of thread, other threads:[~2026-08-04  8:52 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-08-03 12:30 [PATCH] sched/numa: Prevent race on sysctl_numa_balancing static key Chen Jinghuang
2026-08-04  5:09 ` K Prateek Nayak
2026-08-04  8:35   ` chenjinghuang
2026-08-04  8:44     ` K Prateek Nayak
2026-08-04  8:52       ` chenjinghuang

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

all inboxes | Powered by JetHome®