CVE-2025-38170
Severity CVSS v4.0:
Pending analysis
Type:
Unavailable / Other
Publication date:
03/07/2025
Last modified:
03/07/2025
Description
In the Linux kernel, the following vulnerability has been resolved:<br />
<br />
arm64/fpsimd: Discard stale CPU state when handling SME traps<br />
<br />
The logic for handling SME traps manipulates saved FPSIMD/SVE/SME state<br />
incorrectly, and a race with preemption can result in a task having<br />
TIF_SME set and TIF_FOREIGN_FPSTATE clear even though the live CPU state<br />
is stale (e.g. with SME traps enabled). This can result in warnings from<br />
do_sme_acc() where SME traps are not expected while TIF_SME is set:<br />
<br />
| /* With TIF_SME userspace shouldn&#39;t generate any traps */<br />
| if (test_and_set_thread_flag(TIF_SME))<br />
| WARN_ON(1);<br />
<br />
This is very similar to the SVE issue we fixed in commit:<br />
<br />
751ecf6afd6568ad ("arm64/sve: Discard stale CPU state when handling SVE traps")<br />
<br />
The race can occur when the SME trap handler is preempted before and<br />
after manipulating the saved FPSIMD/SVE/SME state, starting and ending on<br />
the same CPU, e.g.<br />
<br />
| void do_sme_acc(unsigned long esr, struct pt_regs *regs)<br />
| {<br />
| // Trap on CPU 0 with TIF_SME clear, SME traps enabled<br />
| // task->fpsimd_cpu is 0.<br />
| // per_cpu_ptr(&fpsimd_last_state, 0) is task.<br />
|<br />
| ...<br />
|<br />
| // Preempted; migrated from CPU 0 to CPU 1.<br />
| // TIF_FOREIGN_FPSTATE is set.<br />
|<br />
| get_cpu_fpsimd_context();<br />
|<br />
| /* With TIF_SME userspace shouldn&#39;t generate any traps */<br />
| if (test_and_set_thread_flag(TIF_SME))<br />
| WARN_ON(1);<br />
|<br />
| if (!test_thread_flag(TIF_FOREIGN_FPSTATE)) {<br />
| unsigned long vq_minus_one =<br />
| sve_vq_from_vl(task_get_sme_vl(current)) - 1;<br />
| sme_set_vq(vq_minus_one);<br />
|<br />
| fpsimd_bind_task_to_cpu();<br />
| }<br />
|<br />
| put_cpu_fpsimd_context();<br />
|<br />
| // Preempted; migrated from CPU 1 to CPU 0.<br />
| // task->fpsimd_cpu is still 0<br />
| // If per_cpu_ptr(&fpsimd_last_state, 0) is still task then:<br />
| // - Stale HW state is reused (with SME traps enabled)<br />
| // - TIF_FOREIGN_FPSTATE is cleared<br />
| // - A return to userspace skips HW state restore<br />
| }<br />
<br />
Fix the case where the state is not live and TIF_FOREIGN_FPSTATE is set<br />
by calling fpsimd_flush_task_state() to detach from the saved CPU<br />
state. This ensures that a subsequent context switch will not reuse the<br />
stale CPU state, and will instead set TIF_FOREIGN_FPSTATE, forcing the<br />
new state to be reloaded from memory prior to a return to userspace.<br />
<br />
Note: this was originallly posted as [1].<br />
<br />
[ Rutland: rewrite commit message ]
Impact
References to Advisories, Solutions, and Tools
- https://git.kernel.org/stable/c/43be952e885476dafb74aa832c0847b2f4f650c6
- https://git.kernel.org/stable/c/6103f9ba51a59afb5a0f32299c837377c5a5a693
- https://git.kernel.org/stable/c/c4a4786d93e99517d6f10ed56b9ffba4ce88d3b3
- https://git.kernel.org/stable/c/d3eaab3c70905c5467e5c4ea403053d67505adeb
- https://git.kernel.org/stable/c/de89368de3894a8db27caeb8fd902ba1c49f696a