On Tue, Oct 27, 2026 at 02:36:21PM +0800, Chris Down wrote:
quoted hunk ↗ jump to hunk
CONFIG_SCHED_STACK_END_CHECK makes schedule_debug() check the magic at
the end of the outgoing task's stack and panic if it has been
overwritten.
Right now this can only be configured by setting the Kconfig option at
build time. At Meta we have it on for some hosts and off for others,
since it is helpful but adds cost on context switching. That means today
we have to build separate kernels for each, which is less than ideal.
So let's make this configurable at boot time. In benchmarking sched pipe
and sched messaging performance is unaffected.
Signed-off-by: Chris Down <chris@chrisdown.name>
---
.../admin-guide/kernel-parameters.txt | 8 +++++
kernel/sched/core.c | 33 +++++++++++++++----
2 files changed, 35 insertions(+), 6 deletions(-)
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index fbee7b544903..95911d33c0fe 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -6811,6 +6811,14 @@ Kernel parameters
core priority to both SMT siblings, so this option
does not favor either sibling.
+ sched_stack_end_check= [KNL]
+ Format: <bool>
+ Check the magic value at the end of the outgoing
+ task's stack (and its shadow call stack, if any) on
+ every call to schedule(), and panic if it has been
+ overwritten.
+ Default set by CONFIG_SCHED_STACK_END_CHECK.
+
sched_verbose [KNL,EARLY] Enables verbose scheduler debug messages.
schedstats= [KNL,X86] Enable or disable scheduled statistics.
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index fc269fd10192..c1fb86b813bb 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -6143,18 +6143,39 @@ static noinline void __schedule_bug(struct task_struct *prev)
add_taint(TAINT_WARN, LOCKDEP_STILL_OK);
}
+static DEFINE_STATIC_KEY_MAYBE_RO(CONFIG_SCHED_STACK_END_CHECK, sched_stack_end_check);
+
+static int __init setup_sched_stack_end_check(char *str)
+{
+ bool enable;
+
+ if (kstrtobool(str, &enable)) {
+ pr_warn("Unable to parse sched_stack_end_check=\n");
+ return 0;
+ }
+
+ if (enable)
+ static_branch_enable(&sched_stack_end_check);
+ else
+ static_branch_disable(&sched_stack_end_check);
+
+ return 1;
+}
+__setup("sched_stack_end_check=", setup_sched_stack_end_check);
+
/*
* Various schedule()-time debugging checks and statistics:
*/
static inline void schedule_debug(struct task_struct *prev, bool preempt)
{
-#ifdef CONFIG_SCHED_STACK_END_CHECK
- if (task_stack_end_corrupted(prev))
- panic("corrupted stack end detected inside scheduler\n");
+ if (static_branch_maybe(CONFIG_SCHED_STACK_END_CHECK,
+ &sched_stack_end_check)) {
+ if (task_stack_end_corrupted(prev))
+ panic("corrupted stack end detected inside scheduler\n");
- if (scs_is_enabled() && task_scs_end_corrupted(prev))
- panic("corrupted shadow stack detected inside scheduler\n");
-#endif
+ if (scs_is_enabled() && task_scs_end_corrupted(prev))
+ panic("corrupted shadow stack detected inside scheduler\n");
+ }
I just noticed that there's a number of task_stack_end_corrupted()
checks that:
- do not also do task_scs_end_corrupted(); should
task_scs_end_corrupted() be put inside task_stack_end_corrupted() to
make sure they're always done in tandem and the shadow stack check
isn't lost?
- should these other sites also respect this switch? It seems weird to
only have this one site affected.