CVE-2021-47553
sched/scs: Reset task stack state in bringup_cpu()
Severity Score
Exploit Likelihood
Affected Versions
Public Exploits
0Exploited in Wild
-Decision
Descriptions
In the Linux kernel, the following vulnerability has been resolved:
sched/scs: Reset task stack state in bringup_cpu()
To hot unplug a CPU, the idle task on that CPU calls a few layers of C
code before finally leaving the kernel. When KASAN is in use, poisoned
shadow is left around for each of the active stack frames, and when
shadow call stacks are in use. When shadow call stacks (SCS) are in use
the task's saved SCS SP is left pointing at an arbitrary point within
the task's shadow call stack.
When a CPU is offlined than onlined back into the kernel, this stale
state can adversely affect execution. Stale KASAN shadow can alias new
stackframes and result in bogus KASAN warnings. A stale SCS SP is
effectively a memory leak, and prevents a portion of the shadow call
stack being used. Across a number of hotplug cycles the idle task's
entire shadow call stack can become unusable.
We previously fixed the KASAN issue in commit:
e1b77c92981a5222 ("sched/kasan: remove stale KASAN poison after hotplug")
... by removing any stale KASAN stack poison immediately prior to
onlining a CPU.
Subsequently in commit:
f1a0a376ca0c4ef1 ("sched/core: Initialize the idle task with preemption disabled")
... the refactoring left the KASAN and SCS cleanup in one-time idle
thread initialization code rather than something invoked prior to each
CPU being onlined, breaking both as above.
We fixed SCS (but not KASAN) in commit:
63acd42c0d4942f7 ("sched/scs: Reset the shadow stack when idle_task_exit")
... but as this runs in the context of the idle task being offlined it's
potentially fragile.
To fix these consistently and more robustly, reset the SCS SP and KASAN
shadow of a CPU's idle task immediately before we online that CPU in
bringup_cpu(). This ensures the idle task always has a consistent state
when it is running, and removes the need to so so when exiting an idle
task.
Whenever any thread is created, dup_task_struct() will give the task a
stack which is free of KASAN shadow, and initialize the task's SCS SP,
so there's no need to specially initialize either for idle thread within
init_idle(), as this was only necessary to handle hotplug cycles.
I've tested this on arm64 with:
* gcc 11.1.0, defconfig +KASAN_INLINE, KASAN_STACK
* clang 12.0.0, defconfig +KASAN_INLINE, KASAN_STACK, SHADOW_CALL_STACK
... offlining and onlining CPUS with:
| while true; do
| for C in /sys/devices/system/cpu/cpu*/online; do
| echo 0 > $C;
| echo 1 > $C;
| done
| done
En el kernel de Linux, se resolvió la siguiente vulnerabilidad: sched/scs: restablecer el estado de la pila de tareas en Bringup_cpu() Para desconectar en caliente una CPU, la tarea inactiva en esa CPU llama a algunas capas de código C antes de abandonar finalmente el kernel. Cuando KASAN está en uso, se deja una sombra envenenada para cada uno de los marcos de pila activos y cuando las pilas de llamadas de sombra están en uso. Cuando se utilizan pilas de llamadas ocultas (SCS), el SCS SP guardado de la tarea se deja apuntando a un punto arbitrario dentro de la pila de llamadas ocultas de la tarea. Cuando una CPU está desconectada y luego conectada nuevamente al kernel, este estado obsoleto puede afectar negativamente la ejecución. La sombra de KASAN obsoleta puede generar alias en nuevos marcos de pila y generar advertencias de KASAN falsas. Un SCS SP obsoleto es efectivamente una pérdida de memoria e impide que se utilice una parte de la pila de llamadas ocultas. Después de varios ciclos de conexión en caliente, toda la pila de llamadas ocultas de la tarea inactiva puede quedar inutilizable. Anteriormente solucionamos el problema de KASAN en el commit: e1b77c92981a5222 ("sched/kasan: eliminar el veneno de KASAN obsoleto después de la conexión en caliente")... eliminando cualquier veneno de pila de KASAN obsoleto inmediatamente antes de conectar una CPU. Posteriormente, en El commit: f1a0a376ca0c4ef1 ("sched/core: Inicialice la tarea inactiva con la preferencia deshabilitada")... la refactorización dejó la limpieza de KASAN y SCS en un código de inicialización de subproceso inactivo de una sola vez en lugar de algo invocado antes de que cada CPU se conectara. rompiendo ambos como arriba. Arreglamos SCS (pero no KASAN) en El commit: 63acd42c0d4942f7 ("sched/scs: restablecer la pila de sombra cuando idle_task_exit")... pero como esto se ejecuta en el contexto de la tarea inactiva que está fuera de línea, es potencialmente frágil. Para solucionar estos problemas de manera consistente y más sólida, restablezca la sombra SCS SP y KASAN de la tarea inactiva de una CPU inmediatamente antes de conectar esa CPU en Bringup_cpu(). Esto garantiza que la tarea inactiva siempre tenga un estado consistente cuando se está ejecutando y elimina la necesidad de tenerlo al salir de una tarea inactiva. Siempre que se crea un subproceso, dup_task_struct() le dará a la tarea una pila que está libre de sombra KASAN e inicializará el SP SCS de la tarea, por lo que no hay necesidad de inicializar especialmente ninguno de los subprocesos inactivos dentro de init_idle(), ya que esto solo era necesario para manejar ciclos de conexión en caliente. Probé esto en arm64 con: * gcc 11.1.0, defconfig +KASAN_INLINE, KASAN_STACK * clang 12.0.0, defconfig +KASAN_INLINE, KASAN_STACK, SHADOW_CALL_STACK ... offlining and onlining CPUS with: | while true; do | for C in /sys/devices/system/cpu/cpu*/online; do | echo 0 > $C; | echo 1 > $C; | done | done
CVSS Scores
SSVC
- Decision:Track
Timeline
- 2024-05-24 CVE Reserved
- 2024-05-24 CVE Published
- 2024-05-25 EPSS Updated
- 2024-12-19 CVE Updated
- ---------- Exploited in Wild
- ---------- KEV Due Date
- ---------- First Exploit
CWE
CAPEC
References (7)
URL | Tag | Source |
---|---|---|
https://git.kernel.org/stable/c/3c51d82d0b7862d7d246016c74b4390fb1fa1f11 | Vuln. Introduced | |
https://git.kernel.org/stable/c/f1a0a376ca0c4ef1fc3d24e3e502acbb5b795674 | Vuln. Introduced | |
https://git.kernel.org/stable/c/1cb358b3ac1bb43aa8c4283830a84216dda65d39 | Vuln. Introduced | |
https://git.kernel.org/stable/c/24c79a7e54ccfa29fb8cbf7ed8d1e48ff1ec6e3d | Vuln. Introduced |
URL | Date | SRC |
---|
URL | Date | SRC |
---|
Affected Vendors, Products, and Versions
Vendor | Product | Version | Other | Status | ||||||
---|---|---|---|---|---|---|---|---|---|---|
Vendor | Product | Version | Other | Status | <-- --> | Vendor | Product | Version | Other | Status |
Linux Search vendor "Linux" | Linux Kernel Search vendor "Linux" for product "Linux Kernel" | >= 5.10.50 < 5.10.83 Search vendor "Linux" for product "Linux Kernel" and version " >= 5.10.50 < 5.10.83" | en |
Affected
| ||||||
Linux Search vendor "Linux" | Linux Kernel Search vendor "Linux" for product "Linux Kernel" | >= 5.14 < 5.15.6 Search vendor "Linux" for product "Linux Kernel" and version " >= 5.14 < 5.15.6" | en |
Affected
| ||||||
Linux Search vendor "Linux" | Linux Kernel Search vendor "Linux" for product "Linux Kernel" | >= 5.14 < 5.16 Search vendor "Linux" for product "Linux Kernel" and version " >= 5.14 < 5.16" | en |
Affected
| ||||||
Linux Search vendor "Linux" | Linux Kernel Search vendor "Linux" for product "Linux Kernel" | 5.12.17 Search vendor "Linux" for product "Linux Kernel" and version "5.12.17" | en |
Affected
| ||||||
Linux Search vendor "Linux" | Linux Kernel Search vendor "Linux" for product "Linux Kernel" | 5.13.2 Search vendor "Linux" for product "Linux Kernel" and version "5.13.2" | en |
Affected
|