CVE-2021-47553
Severity CVSS v4.0:
Pending analysis
Type:
Unavailable / Other
Publication date:
24/05/2024
Last modified:
24/05/2024
Description
In the Linux kernel, the following vulnerability has been resolved:<br />
<br />
sched/scs: Reset task stack state in bringup_cpu()<br />
<br />
To hot unplug a CPU, the idle task on that CPU calls a few layers of C<br />
code before finally leaving the kernel. When KASAN is in use, poisoned<br />
shadow is left around for each of the active stack frames, and when<br />
shadow call stacks are in use. When shadow call stacks (SCS) are in use<br />
the task&#39;s saved SCS SP is left pointing at an arbitrary point within<br />
the task&#39;s shadow call stack.<br />
<br />
When a CPU is offlined than onlined back into the kernel, this stale<br />
state can adversely affect execution. Stale KASAN shadow can alias new<br />
stackframes and result in bogus KASAN warnings. A stale SCS SP is<br />
effectively a memory leak, and prevents a portion of the shadow call<br />
stack being used. Across a number of hotplug cycles the idle task&#39;s<br />
entire shadow call stack can become unusable.<br />
<br />
We previously fixed the KASAN issue in commit:<br />
<br />
e1b77c92981a5222 ("sched/kasan: remove stale KASAN poison after hotplug")<br />
<br />
... by removing any stale KASAN stack poison immediately prior to<br />
onlining a CPU.<br />
<br />
Subsequently in commit:<br />
<br />
f1a0a376ca0c4ef1 ("sched/core: Initialize the idle task with preemption disabled")<br />
<br />
... the refactoring left the KASAN and SCS cleanup in one-time idle<br />
thread initialization code rather than something invoked prior to each<br />
CPU being onlined, breaking both as above.<br />
<br />
We fixed SCS (but not KASAN) in commit:<br />
<br />
63acd42c0d4942f7 ("sched/scs: Reset the shadow stack when idle_task_exit")<br />
<br />
... but as this runs in the context of the idle task being offlined it&#39;s<br />
potentially fragile.<br />
<br />
To fix these consistently and more robustly, reset the SCS SP and KASAN<br />
shadow of a CPU&#39;s idle task immediately before we online that CPU in<br />
bringup_cpu(). This ensures the idle task always has a consistent state<br />
when it is running, and removes the need to so so when exiting an idle<br />
task.<br />
<br />
Whenever any thread is created, dup_task_struct() will give the task a<br />
stack which is free of KASAN shadow, and initialize the task&#39;s SCS SP,<br />
so there&#39;s no need to specially initialize either for idle thread within<br />
init_idle(), as this was only necessary to handle hotplug cycles.<br />
<br />
I&#39;ve tested this on arm64 with:<br />
<br />
* gcc 11.1.0, defconfig +KASAN_INLINE, KASAN_STACK<br />
* clang 12.0.0, defconfig +KASAN_INLINE, KASAN_STACK, SHADOW_CALL_STACK<br />
<br />
... offlining and onlining CPUS with:<br />
<br />
| while true; do<br />
| for C in /sys/devices/system/cpu/cpu*/online; do<br />
| echo 0 > $C;<br />
| echo 1 > $C;<br />
| done<br />
| done