IM
IronMonkey Threat Research

CVE-2025-37964 MEDIUM

Published: 2025-05-20 | Last Modified: 2026-07-14 | Status: Modified

Description

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.

Additional Descriptions (1)

En el kernel de Linux, se ha resuelto la siguiente vulnerabilidad: x86/mm: Eliminar la ventana donde los vaciados de TLB pueden omitirse inadvertidamente tl;dr: Hay una ventana en el código de conmutación mm donde se establece el nuevo CR3 y la CPU debería obtener vaciados de TLB para el nuevo mm. Pero should_flush_tlb() tiene un error y suprime el vaciado. Arréglelo ampliando la ventana donde should_flush_tlb() envía una IPI. Versión larga: === Historial === Hubo algunas cosas que llevaron a esto. Primero, se observó que actualizar mm_cpumask() era demasiado costoso, por lo que se hizo más perezoso. Pero ser perezoso causó demasiados IPI innecesarios a las CPU debido al ahora perezoso mm_cpumask(). Entonces se agregó código para descartar mm_cpumask() periódicamente[2]. Pero ese descarte fue demasiado agresivo y omitió el envío de vaciados de TLB a las CPU que los necesitan. Así que aquí estamos de nuevo. === Problema === El código demasiado agresivo en should_flush_tlb() ataca en esta ventana: // Activa las IPI para esta combinación de CPU/mm, pero solo si should_flush_tlb() está de acuerdo: 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); // ^ Después de que 'need_flush' se establece en falso, las IPI *DEBEN* // enviarse a esta CPU y no ignorarse. this_cpu_write(cpu_tlbstate.loaded_mm, next); // ^ ¡No es hasta este punto que should_flush_tlb() // se vuelve verdadero! should_flush_tlb() suprimirá los vaciados de TLB entre load_new_mm_cr3() y la escritura en 'loaded_mm', que es una ventana donde no deberían suprimirse. ¡Uy! === Solución === Afortunadamente, la ventana difusa "a punto de escribir CR3" ya está marcada con load_mm==LOADED_MM_SWITCHING. Simplemente comprobar ese estado en should_flush_tlb() es suficiente para asegurar que la CPU esté dirigida a un IPI. Esto provocará más IPI de vaciado de TLB. Sin embargo, la ventana es relativamente pequeña y no preveo que esto tenga ningún impacto medible en el rendimiento. Actualice el comentario donde se escribe LOADED_MM_SWITCHING, ya que ha generado otro usuario. Peter Z también planteó la preocupación de que should_flush_tlb() podría no observar 'loaded_mm' e 'is_lazy' en el mismo orden en que switch_mm_irqs_off() los escribe. Añade una barrera para garantizar que se observen en el orden en que están escritos.

CVSS Metrics

Base Score: 5.5 (MEDIUM)

CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H

Attack VectorLOCAL
Attack ComplexityLOW
Privileges RequiredLOW
User InteractionNONE
ScopeUNCHANGED
Confidentiality ImpactNONE
Integrity ImpactNONE
Availability ImpactHIGH

Source: [email protected]

Type: Primary

Exploitability Score: 1.8

Impact Score: 3.6

Weaknesses

Source Type Description
[email protected] Primary
en NVD-CWE-noinfo

Affected Products

Vendor Product Version Update Type
linux linux_kernel * <built-in method update of dict object at 0x702bfc2a4f00> Operating System
linux linux_kernel * <built-in method update of dict object at 0x702bfc2a43c0> Operating System
linux linux_kernel * <built-in method update of dict object at 0x702bde165dc0> Operating System
linux linux_kernel * <built-in method update of dict object at 0x702bdc9f5b80> Operating System
linux linux_kernel * <built-in method update of dict object at 0x702bfc2a7780> Operating System
linux linux_kernel 6.15 <built-in method update of dict object at 0x702bfc2a5f40> Operating System
linux linux_kernel 6.15 <built-in method update of dict object at 0x702b70374380> Operating System
linux linux_kernel 6.15 <built-in method update of dict object at 0x702bfc2a6d00> Operating System
linux linux_kernel 6.15 <built-in method update of dict object at 0x702bde167b00> Operating System
linux linux_kernel 6.15 <built-in method update of dict object at 0x702bfc2a74c0> Operating System
debian debian_linux 11.0 <built-in method update of dict object at 0x702bde1649c0> Operating System

Affected Configurations

Operator: OR

Vulnerable CPE
Yes cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*
Yes cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*
Yes cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*
Yes cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*
Yes cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*
Yes cpe:2.3:o:linux:linux_kernel:6.15:rc1:*:*:*:*:*:*
Yes cpe:2.3:o:linux:linux_kernel:6.15:rc2:*:*:*:*:*:*
Yes cpe:2.3:o:linux:linux_kernel:6.15:rc3:*:*:*:*:*:*
Yes cpe:2.3:o:linux:linux_kernel:6.15:rc4:*:*:*:*:*:*
Yes cpe:2.3:o:linux:linux_kernel:6.15:rc5:*:*:*:*:*:*

Operator: OR

Vulnerable CPE
Yes cpe:2.3:o:debian:debian_linux:11.0:*:*:*:*:*:*:*

References

Notification
Message here