From: Zhan Xusheng <zhanxusheng1024@gmail.com>
To: Ingo Molnar <mingo@redhat.com>,
Peter Zijlstra <peterz@infradead.org>,
Juri Lelli <juri.lelli@redhat.com>,
Vincent Guittot <vincent.guittot@linaro.org>
Cc: Mel Gorman <mgorman@suse.de>,
Dietmar Eggemann <dietmar.eggemann@arm.com>,
Steven Rostedt <rostedt@goodmis.org>,
Ben Segall <bsegall@google.com>,
Valentin Schneider <vschneid@redhat.com>,
K Prateek Nayak <kprateek.nayak@amd.com>,
zhanxusheng@xiaomi.com, linux-kernel@vger.kernel.org
Subject: [PATCH] sched/debug: Validate writes to the scan_size_mb debugfs knob
Date: Mon, 10 Aug 2026 16:18:29 +0800 [thread overview]
Message-ID: <20260810081829.3149958-1-zhanxusheng@xiaomi.com> (raw)
sysctl_numa_balancing_scan_size is used as a divisor, so two kinds of
write to scan_size_mb kill the machine.
Zero makes task_scan_min() divide by it:
windows = MAX_SCAN_WINDOW / scan_size;
# echo 0 > /sys/kernel/debug/sched/numa_balancing/scan_size_mb
Oops: divide error: 0000 [#1] SMP PTI
RIP: 0010:task_scan_max+0x30/0x1a0
RAX: 0000000000000a00 RCX: 0000000000000000
Call Trace:
init_numa_balancing+0xe0/0x200
__sched_fork+0x13b/0x180
sched_fork+0x12/0x1d0
copy_process+0xdea/0x2370
kernel_clone+0xd6/0x4a0
__do_sys_clone3+0xf4/0x140
task_scan_min() is inlined there. The trigger is thread creation rather
than fork, since init_numa_balancing() returns early for a new address
space and only reaches task_scan_max() for a CLONE_VM child.
A multiple of 2^24 (with 4K pages) is the second kind. MB_TO_PAGES()
shifts an unsigned int, so the result wraps to zero and
task_nr_scan_windows() divides by that instead:
# echo 16777216 > /sys/kernel/debug/sched/numa_balancing/scan_size_mb
Oops: divide error: 0000 [#1] SMP PTI
RIP: 0010:task_nr_scan_windows.isra.0+0x5c/0x70
The move to debugfs kept validation where a bad value was harmful:
tunable_scaling gained sched_scaling_fops, so an out-of-range write there
returns -EINVAL rather than being stored. scan_size_mb went to a plain
debugfs_create_u32() instead, and the
.procname = "numa_balancing_scan_size_mb",
.extra1 = SYSCTL_ONE,
it used to have was not carried over, so zero became storable. No upper
bound was ever enforced, so the wrap predates that commit.
Follow sched_scaling_fops and refuse both instead of storing them. The
knob is described in Documentation/scheduler/sched-debug.rst as one of the
files controlling the scan rate, so returning -EINVAL is friendlier than
quietly substituting a different value.
Checked in a 2-node qemu guest: on an unpatched 7.2.0-rc6 the two writes
above panic at the two RIPs shown, and with this patch writes of 0, 2^24
and 3*2^24 all get -EINVAL while a write of 512 still takes effect.
Fixes: 8a99b6833c88 ("sched: Move SCHED_DEBUG sysctl to debugfs")
Signed-off-by: Zhan Xusheng <zhanxusheng@xiaomi.com>
---
kernel/sched/debug.c | 51 +++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 50 insertions(+), 1 deletion(-)
diff --git a/kernel/sched/debug.c b/kernel/sched/debug.c
index 40584b27ea0c..e09fe94e7b9c 100644
--- a/kernel/sched/debug.c
+++ b/kernel/sched/debug.c
@@ -210,6 +210,55 @@ static const struct file_operations sched_scaling_fops = {
.release = single_release,
};
+#ifdef CONFIG_NUMA_BALANCING
+/*
+ * scan_size_mb is fed to MB_TO_PAGES() and then used as a divisor by
+ * task_nr_scan_windows() and task_scan_min(). Zero divides by zero, and a
+ * value big enough to overflow the 32-bit shift in MB_TO_PAGES() wraps to
+ * zero and does the same, so refuse both rather than store them.
+ */
+#define NUMA_SCAN_SIZE_MB_MAX (UINT_MAX >> (20 - PAGE_SHIFT))
+
+static ssize_t sched_numa_scan_size_write(struct file *filp,
+ const char __user *ubuf,
+ size_t cnt, loff_t *ppos)
+{
+ unsigned int mb;
+ int ret;
+
+ ret = kstrtouint_from_user(ubuf, cnt, 10, &mb);
+ if (ret)
+ return ret;
+
+ if (!mb || mb > NUMA_SCAN_SIZE_MB_MAX)
+ return -EINVAL;
+
+ sysctl_numa_balancing_scan_size = mb;
+
+ *ppos += cnt;
+ return cnt;
+}
+
+static int sched_numa_scan_size_show(struct seq_file *m, void *v)
+{
+ seq_printf(m, "%u\n", sysctl_numa_balancing_scan_size);
+ return 0;
+}
+
+static int sched_numa_scan_size_open(struct inode *inode, struct file *filp)
+{
+ return single_open(filp, sched_numa_scan_size_show, NULL);
+}
+
+static const struct file_operations sched_numa_scan_size_fops = {
+ .open = sched_numa_scan_size_open,
+ .write = sched_numa_scan_size_write,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+#endif /* CONFIG_NUMA_BALANCING */
+
#ifdef CONFIG_SCHED_CACHE
static ssize_t
sched_cache_enable_write(struct file *filp, const char __user *ubuf,
@@ -664,7 +713,7 @@ static __init int sched_init_debug(void)
debugfs_create_u32("scan_delay_ms", 0644, numa, &sysctl_numa_balancing_scan_delay);
debugfs_create_u32("scan_period_min_ms", 0644, numa, &sysctl_numa_balancing_scan_period_min);
debugfs_create_u32("scan_period_max_ms", 0644, numa, &sysctl_numa_balancing_scan_period_max);
- debugfs_create_u32("scan_size_mb", 0644, numa, &sysctl_numa_balancing_scan_size);
+ debugfs_create_file("scan_size_mb", 0644, numa, NULL, &sched_numa_scan_size_fops);
debugfs_create_u32("hot_threshold_ms", 0644, numa, &sysctl_numa_balancing_hot_threshold);
#endif /* CONFIG_NUMA_BALANCING */
--
2.43.0
next reply other threads:[~2026-08-10 8:18 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-10 8:18 Zhan Xusheng [this message]
2026-08-10 13:57 ` Chen Yu
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260810081829.3149958-1-zhanxusheng@xiaomi.com \
--to=zhanxusheng1024@gmail.com \
--cc=bsegall@google.com \
--cc=dietmar.eggemann@arm.com \
--cc=juri.lelli@redhat.com \
--cc=kprateek.nayak@amd.com \
--cc=linux-kernel@vger.kernel.org \
--cc=mgorman@suse.de \
--cc=mingo@redhat.com \
--cc=peterz@infradead.org \
--cc=rostedt@goodmis.org \
--cc=vincent.guittot@linaro.org \
--cc=vschneid@redhat.com \
--cc=zhanxusheng@xiaomi.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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®