# CVE-2025-38170: arm64/fpsimd: Discard stale CPU state when handling SME traps

Status: published. Published: 2025-07-03. Updated: 2026-11-05.

In the Linux kernel, the following vulnerability has been resolved:

arm64/fpsimd: Discard stale CPU state when handling SME traps

The logic for handling SME traps manipulates saved FPSIMD/SVE/SME state
incorrectly, and a race with preemption can result in a task having
TIF_SME set and TIF_FOREIGN_FPSTATE clear even though the live CPU state
is stale (e.g. with SME traps enabled). This can result in warnings from
do_sme_acc() where SME traps are not expected while TIF_SME is set:

|        /* With TIF_SME userspace shouldn't generate any traps */
|        if (test_and_set_thread_flag(TIF_SME))
|                WARN_ON(1);

This is very similar to the SVE issue we fixed in commit:

  751ecf6afd6568ad ("arm64/sve: Discard stale CPU state when handling SVE traps")

The race can occur when the SME trap handler is preempted before and
after manipulating the saved FPSIMD/SVE/SME state, starting and ending on
the same CPU, e.g.

| void do_sme_acc(unsigned long esr, struct pt_regs *regs)
| {
|         // Trap on CPU 0 with TIF_SME clear, SME traps enabled
|         // task->fpsimd_cpu is 0.
|         // per_cpu_ptr(&fpsimd_last_state, 0) is task.
|
|         ...
|
|         // Preempted; migrated from CPU 0 to CPU 1.
|         // TIF_FOREIGN_FPSTATE is set.
|
|         get_cpu_fpsimd_context();
|
|         /* With TIF_SME userspace shouldn't generate any traps */
|         if (test_and_set_thread_flag(TIF_SME))
|                 WARN_ON(1);
|
|         if (!test_thread_flag(TIF_FOREIGN_FPSTATE)) {
|                 unsigned long vq_minus_one =
|                         sve_vq_from_vl(task_get_sme_vl(current)) - 1;
|                 sme_set_vq(vq_minus_one);
|
|                 fpsimd_bind_task_to_cpu();
|         }
|
|         put_cpu_fpsimd_context();
|
|         // Preempted; migrated from CPU 1 to CPU 0.
|         // task->fpsimd_cpu is still 0
|         // If per_cpu_ptr(&fpsimd_last_state, 0) is still task then:
|         // - Stale HW state is reused (with SME traps enabled)
|         // - TIF_FOREIGN_FPSTATE is cleared
|         // - A return to userspace skips HW state restore
| }

Fix the case where the state is not live and TIF_FOREIGN_FPSTATE is set
by calling fpsimd_flush_task_state() to detach from the saved CPU
state. This ensures that a subsequent context switch will not reuse the
stale CPU state, and will instead set TIF_FOREIGN_FPSTATE, forcing the
new state to be reloaded from memory prior to a return to userspace.

Note: this was originallly posted as [1].

[ Rutland: rewrite commit message ]

## Remediation

No remediation reported in collected sources

## Affected products and versions

- Linux / Linux: ≥ 8bd7f91c03d886f41d35f6108078d20be5a4a1bd; < de89368de3894a8db27caeb8fd902ba1c49f696a (affected, git); ≥ 8bd7f91c03d886f41d35f6108078d20be5a4a1bd; < 43be952e885476dafb74aa832c0847b2f4f650c6 (affected, git); ≥ 8bd7f91c03d886f41d35f6108078d20be5a4a1bd; < 6103f9ba51a59afb5a0f32299c837377c5a5a693 (affected, git); ≥ 8bd7f91c03d886f41d35f6108078d20be5a4a1bd; < c4a4786d93e99517d6f10ed56b9ffba4ce88d3b3 (affected, git); ≥ 8bd7f91c03d886f41d35f6108078d20be5a4a1bd; < d3eaab3c70905c5467e5c4ea403053d67505adeb (affected, git). Source: CNA: Linux
- Linux / Linux: 5.19 (affected); ≥ 0; < 5.19 (unaffected, semver); ≥ 6.1.142; ≤ 6.1.* (unaffected, semver); ≥ 6.6.94; ≤ 6.6.* (unaffected, semver); ≥ 6.12.34; ≤ 6.12.* (unaffected, semver); ≥ 6.15.3; ≤ 6.15.* (unaffected, semver); ≥ 6.16; ≤ * (unaffected, original_commit_for_fix). Source: CNA: Linux

## Severity and prioritization

- CISA KEV: No listing in collected sources

- EPSS: 0.17% as of 2026-11-05; percentile 6.05%

- SSVC: exploitation none; automatable no; technical impact partial; source ADP: CISA-ADP

- Weaknesses: Not reported

## Exploit evidence

No exploit evidence in collected sources. This is not proof of no exploitation.

## References

- https://git.kernel.org/stable/c/de89368de3894a8db27caeb8fd902ba1c49f696a (CNA: Linux)

- https://git.kernel.org/stable/c/43be952e885476dafb74aa832c0847b2f4f650c6 (CNA: Linux)

- https://git.kernel.org/stable/c/6103f9ba51a59afb5a0f32299c837377c5a5a693 (CNA: Linux)

- https://git.kernel.org/stable/c/c4a4786d93e99517d6f10ed56b9ffba4ce88d3b3 (CNA: Linux)

- https://git.kernel.org/stable/c/d3eaab3c70905c5467e5c4ea403053d67505adeb (CNA: Linux)

- https://lists.debian.org/debian-lts-announce/2025/10/msg00008.html (ADP: CVE)

## Provenance

- CNA: Linux: https://www.cve.org/CVERecord?id=CVE-2025-38170; retrieved 2026-11-05; source updated 2026-11-05

- FIRST EPSS: https://api.first.org/data/v1/epss?cve=CVE-2025-38170; retrieved 2026-11-05; source updated Not reported

Revision: b6ed9882395f52f9cde83d523ba92cc6ec802f8901cd3f03eddb0aa97a85f711

Canonical: https://y2.dev/cve/CVE-2025-38170

## Agent and API access

Public CVE pages, Markdown, and JSON are free to read without an account or API key.

- Public catalog: https://y2.dev/cve/index.json. Follow nextCursor with the same search, filters, sort, and limit (1–100). A null cursor marks the end.

- WebMCP: search_cve_disclosures, get_cve_disclosure, get_cve_page_markdown, get_y2_cve_access. Available in compatible browsers.

- Cyber API: https://api.y2.dev/api/v2/cyber/cves and https://api.y2.dev/api/v2/cyber/cves/{cveId}.

- Y2 Pro or Elite: create a workspace API key with the intel:cyber scope and send Authorization: Bearer <Y2_API_KEY>. Setup: https://y2.dev/docs/api/create-key.

- x402: Pay per request without an account or API key. Omit Authorization, read the HTTP 402 PAYMENT-REQUIRED challenge, validate its current requirements, and retry with PAYMENT-SIGNATURE through an authorized payment client. These browser tools never make payments. Guide: https://y2.dev/docs/api/x402.

- OpenAPI: https://y2.dev/api/openapi.yaml. Agent access metadata: https://y2.dev/cve/agent.json.

Collected public records only. Check source status for coverage and freshness.