CVE-2025-37964

CVE-2025-37964

High · published May 20, 2025

CVSS v3.1
7.8
EPSS
0%
Percentile
10.5
In the wild
Unconfirmed
What it is

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

x86/mm: Eliminate window where TLB flushes may be inadvertently skipped

tl;dr: There is a window in the mm switching code where the new CR3 is

set and the CPU should be getting TLB flushes for the new mm. But

should_flush_tlb() has a bug and suppresses the flush. Fix it by

widening the window where should_flush_tlb() sends an IPI.

Long Version:

=== History ===

There were a few things leading up to this.

First, updating mm_cpumask() was observed to be too expensive, so it was

made lazier. But being lazy caused too many unnecessary IPIs to CPUs

due to the now-lazy mm_cpumask(). So code was added to cull

mm_cpumask() periodically[2]. But that culling was a bit too aggressive

and skipped sending TLB flushes to CPUs that need them. So here we are

again.

=== Problem ===

The too-aggressive code in should_flush_tlb() strikes in this window:

// Turn on IPIs for this CPU/mm combination, but only

// if should_flush_tlb() agrees:

cpumask_set_cpu(cpu, mm_cpumask(next));

next_tlb_gen = atomic64_read(&next->context.tlb_gen);

choose_new_asid(next, next_tlb_gen, &new_asid, &need_flush);

load_new_mm_cr3(need_flush);

// ^ After 'need_flush' is set to false, IPIs *MUST*

// be sent to this CPU and not be ignored.

this_cpu_write(cpu_tlbstate.loaded_mm, next);

// ^ Not until this point does should_flush_tlb()

// become true!

should_flush_tlb() will suppress TLB flushes between load_new_mm_cr3()

and writing to 'loaded_mm', which is a window where they should not be

suppressed. Whoops.

=== Solution ===

Thankfully, the fuzzy "just about to write CR3" window is already marked

with loaded_mm==LOADED_MM_SWITCHING. Simply checking for that state in

should_flush_tlb() is sufficient to ensure that the CPU is targeted with

an IPI.

This will cause more TLB flush IPIs. But the window is relatively small

and I do not expect this to cause any kind of measurable performance

impact.

Update the comment where LOADED_MM_SWITCHING is written since it grew

yet another user.

Peter Z also raised a concern that should_flush_tlb() might not observe

'loaded_mm' and 'is_lazy' in the same order that switch_mm_irqs_off()

writes them. Add a barrier to ensure that they are observed in the

order they are written.

The record
Technical detail
CVSS v3.1
7.8 · HIGH
Vector
CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
CVSS v4.0
Not supplied
EPSS
0.00209 · 10.5th percentile
Published
2025-05-20T20:15Z
Affected products (11)
ProductVersionsFixed in
linux/linux_kernel≥ 5.15.179, < 5.15.1835.15.183
linux/linux_kernel≥ 6.1.129, < 6.1.1396.1.139
linux/linux_kernel≥ 6.6.79, < 6.6.916.6.91
linux/linux_kernel≥ 6.12.16, < 6.12.296.12.29
linux/linux_kernel≥ 6.13.4, < 6.14.76.14.7
linux/linux_kernelall versions—
linux/linux_kernelall versions—
linux/linux_kernelall versions—
linux/linux_kernelall versions—
linux/linux_kernelall versions—
debian/debian_linuxall versions—
References (9)
EPSS history
Timeline
  • 20 MAY 16:01Z
    x86/mm: Eliminate window where TLB flushes may be inadvertently skipped
    cvelistv5