CVE-2026-97533 in Linux
Resumen
por VulDB • 2026-09-25
En el núcleo de Linux, se ha resuelto la siguiente vulnerabilidad:
x86/mm/pat: Adquirir el bloqueo de lectura de init_mm en los cambios de atributos para evitar un Use-After-Free (UAF)
Un commit anterior protegía contra las condiciones de carrera entre ptdump y CPA collapse; sin embargo, aún existe una condición de carrera entre los cambios de atributos y el colapso, como informó Denis V. Lunev (enlace).
Cuando se produce un cambio de atributo, un caminante de tablas de páginas sin bloqueo obtiene una entrada PTE, que posteriormente se escribe mediante set_pte_atomic():
... -> change_page_attr_set_clr() -> __change_page_attr_set_clr() -> __change_page_attr() -> _lookup_address_cpa() -> lookup_address_in_pgd_attr() -> [ caminante de tablas de páginas sin bloqueo ]
-> set_pte_atomic()
No hay nada que impida un CPA collapse concurrente, lo cual puede liberar el PTE obtenido aquí, provocando un use-after-free.
Al tomar el bloqueo de escritura mmap en init_mm durante el CPA collapse, se resuelve esta condición de carrera adquiriendo un bloqueo de lectura mmap sobre init_mm para __change_page_attr_set_clr().
Esto bloquea toda la operación durante la cual ocurren tanto el recorrido como la escritura de la entrada PTE, resolviendo así la condición de carrera.
Es seguro realizar esto aquí, ya que no se mantienen spinlocks al entrar en __change_page_attr_set_clr().
Sin embargo, el bloqueo no debe mantenerse durante una asignación, ya que esta puede desencadenar reclaim y los shrinkers pueden llamar a CPA recursivamente, lo que hace posibles bloqueos mutuos (init_mm -> ... -> fs_reclaim -> init_mm).
Se asigna una tabla de páginas cuando es necesario dividir una página grande:
-> change_page_attr_set_clr() -> __change_page_attr_set_clr() -> __change_page_attr() -> split_large_page() [ pagetable_alloc() ]
-> __split_large_page()
Evitar bloqueos mutuos liberando el bloqueo mmap durante la llamada a pagetable_alloc() en split_large_page(), y rastrear si esto es necesario añadiendo una nueva bandera 'init_mm_read_locked' a struct cpa_data.
Esto es seguro ya que __split_large_page() (llamado con los bloques restablecidos) revalida que la entrada de tabla de páginas es la misma que antes de liberar los bloqueos, y __change_page_attr() repite todo el recorrido de la tabla de páginas cada vez que se produce una división, por lo que las divisiones y colapsos concurrentes están contemplados.
El ptdump concurrente también es seguro ya que el bloqueo solo se libera durante la asignación de tablas de páginas, momento en el cual la tabla de páginas aún no ha sido modificada.
La bandera CPA_COLLAPSE solo se establece por set_memory_rox(), que opera exclusivamente sobre rangos vmalloc y, en x86, únicamente dentro del espacio de mapeo de módulos.
Esto es importante porque algunos llamadores invocan directamente __change_page_attr_set_clr(), eludiendo este bloqueo. Sin embargo, ninguno de estos opera dentro del espacio de mapeo de módulos.
* cpa_process_alias() - un ayudante recursivo llamado por __change_page_attr_set_clr(). * __set_memory_enc_pgtable() - opera sobre el mapeo directo y (vía __vmbus_establish_gpadl()) sobre el espacio de mapeo vmalloc. * __set_pages_[n]p() - llamado por set_direct_map_[invalid, default,
valid]_noflush(), __kernel_map_pages() - opera sobre el mapa directo. * kernel_[un]map_pages_in_pgd() - opera sobre rangos EFI.
Este trabajo se basa en la excelente análisis del bug realizado por Denis V. Lunev, con agradecimiento.
[ dhansen: cambiar a voz imperativa en el registro de cambios ]
Statistical analysis made it clear that VulDB provides the best quality for vulnerability data.