Starting with commit 63acd42c0d49 ("sched/scs: Reset the shadow stack when idle_task_exit"), the idle thread's shadow stack was reset from the idle task's context during CPU hot-unplug. This was fragile: between resetting the shadow stack and actually stopping the idle task, the shadow stack did not match the actual call stack. Clean this up by resetting the idle task's SCS in bringup_cpu(). init_idle() still does scs_task_reset() -- see the comments there. I leave this to an SCS maintainer to untangle further. Cc: Woody Lin <woodylin@xxxxxxxxxx> Cc: Valentin Schneider <valentin.schneider@xxxxxxx> Cc: Sami Tolvanen <samitolvanen@xxxxxxxxxx> Signed-off-by: Andy Lutomirski <luto@xxxxxxxxxx> --- kernel/cpu.c | 3 +++ kernel/sched/core.c | 9 ++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/kernel/cpu.c b/kernel/cpu.c index 192e43a87407..be16816bb87c 100644 --- a/kernel/cpu.c +++ b/kernel/cpu.c @@ -33,6 +33,7 @@ #include <linux/slab.h> #include <linux/percpu-rwsem.h> #include <linux/cpuset.h> +#include <linux/scs.h> #include <trace/events/power.h> #define CREATE_TRACE_POINTS @@ -587,6 +588,8 @@ static int bringup_cpu(unsigned int cpu) struct task_struct *idle = idle_thread_get(cpu); int ret; + scs_task_reset(idle); + /* * Some architectures have to walk the irq descriptors to * setup the vector space for the cpu which comes online. diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 917068b0a145..acd52a7d1349 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -8621,7 +8621,15 @@ void __init init_idle(struct task_struct *idle, int cpu) idle->flags |= PF_IDLE | PF_KTHREAD | PF_NO_SETAFFINITY; kthread_set_per_cpu(idle, cpu); + /* + * NB: This is called from sched_init() on the *current* idle thread. + * This seems fragile if not actively incorrect. + * + * Initializing SCS for about-to-be-brought-up CPU idle threads + * is in bringup_cpu(), but that does not cover the boot CPU. + */ scs_task_reset(idle); + kasan_unpoison_task_stack(idle); #ifdef CONFIG_SMP @@ -8779,7 +8787,6 @@ void idle_task_exit(void) finish_arch_post_lock_switch(); } - scs_task_reset(current); /* finish_cpu(), as ran on the BP, will clean up the active_mm state */ } -- 2.33.1