Vulnerabilidad en kernel de Linux (CVE-2024-46787)
Gravedad CVSS v3.1:
MEDIA
Tipo:
No Disponible / Otro tipo
Fecha de publicación:
18/09/2024
Última modificación:
20/11/2024
Descripción
En el kernel de Linux, se ha resuelto la siguiente vulnerabilidad: userfaultfd: corregir comprobaciones para PMD enormes Serie de parches "userfaultfd: corregir ejecucións en torno a la comprobación pmd_trans_huge()", v2. El código pmd_trans_huge() en mfill_atomic() es incorrecto de tres maneras diferentes según la versión del kernel: 1. La comprobación pmd_trans_huge() es rápida y puede llevar a un BUG_ON() (si alcanza las dos ventanas de ejecución correctas) - He probado esto en una compilación del kernel con algunas llamadas mdelay() adicionales. Vea el mensaje de confirmación para obtener una descripción del escenario de ejecución. En kernels más antiguos (antes de 6.5), creo que el mismo error puede incluso teóricamente llevar a acceder a los contenidos de la página transhuge como una tabla de páginas si alcanza las 5 ventanas de ejecución estrechas correctas (no he probado este caso). 2. Como señaló Qi Zheng, pmd_trans_huge() no es suficiente para detectar PMD que no apuntan a tablas de páginas. En kernels más antiguos (anteriores a 6.5), solo tendrías que ganar una única ejecución bastante amplia para alcanzar esto. He probado esto en 6.1 estable haciendo una ejecución de migración (con un mdelay() parcheado en try_to_migrate()) contra UFFDIO_ZEROPAGE - en mi VM x86, eso causa un error de kernel en ptlock_ptr(). 3. En kernels más nuevos (>=6.5), para asignaciones shmem, khugepaged puede arrancar tablas de páginas de debajo de nosotros (aunque no lo he probado), así que creo que las comprobaciones BUG_ON() en mfill_atomic() son simplemente incorrectas. Decidí escribir dos correcciones separadas para estos (una corrección para los errores 1+2, una corrección para el error 3), de modo que la primera corrección pueda ser retroportada a kernels afectados por errores 1+2. Este parche (de 2): Esto corrige dos problemas. Descubrí que puede ocurrir la siguiente ejecución: mfill_atomic other thread ============ ============ pmdp_get_lockless() [reads none pmd] __pte_alloc [no-op] BUG_ON(pmd_none(*dst_pmd)) He verificado esto experimentalmente en un kernel con llamadas mdelay() adicionales; se activa BUG_ON(pmd_none(*dst_pmd)). En los kernels más nuevos que el commit 0d940a9b270b ("mm/pgtable: permitir que pte_offset_map[_lock]() falle"), esto no puede llevar a nada peor que un BUG_ON(), ya que los ayudantes de acceso a la tabla de páginas están manipulados para lidiar con la desaparición simultánea de tablas de páginas; pero en kernels más antiguos (<=6.4), creo que probablemente podríamos teóricamente pasar por alto las dos comprobaciones de BUG_ON() y terminar tratando una página enorme como una tabla de páginas. El segundo problema es que, como señaló Qi Zheng, hay otros tipos de PMD enormes que pmd_trans_huge() no puede detectar: PMD de devmap y PMD de intercambio (en particular, PMD de migración). En <=6.4, esto es peor que el primer problema: si mfill_atomic() se ejecuta en un PMD que contiene una entrada de migración (que solo requiere ganar una ejecución única y bastante amplia), pasará el PMD a pte_offset_map_lock(), que asume que el PMD apunta a una tabla de páginas. A continuación, se produce una ruptura: primero, el núcleo intenta tomar el bloqueo PTE (que se bloqueará o tal vez será peor si no hay una "página de estructura" para los bits de dirección en el PMD de la entrada de migración; creo que al menos en X86 no suele haber una "página de estructura" correspondiente gracias a la mitigación de inversión de PTE; amd64 se ve diferente). Si eso no se bloquea, el núcleo intentará escribir un PTE en lo que cree erróneamente que es una tabla de páginas. Como parte de la solución de estos problemas, elimine la verificación de pmd_trans_huge() antes de __pte_alloc(); eso es redundante, vamos a tener que verificar eso después de __pte_alloc() de todos modos. --- truncada ----
Impacto
Puntuación base 3.x
4.70
Gravedad 3.x
MEDIA
Productos y versiones vulnerables
| CPE | Desde | Hasta |
|---|---|---|
| cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:* | 4.3 (incluyendo) | 6.6.51 (excluyendo) |
| cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:* | 6.7 (incluyendo) | 6.10.10 (excluyendo) |
| cpe:2.3:o:linux:linux_kernel:6.11:rc1:*:*:*:*:*:* | ||
| cpe:2.3:o:linux:linux_kernel:6.11:rc2:*:*:*:*:*:* | ||
| cpe:2.3:o:linux:linux_kernel:6.11:rc3:*:*:*:*:*:* | ||
| cpe:2.3:o:linux:linux_kernel:6.11:rc4:*:*:*:*:*:* | ||
| cpe:2.3:o:linux:linux_kernel:6.11:rc5:*:*:*:*:*:* | ||
| cpe:2.3:o:linux:linux_kernel:6.11:rc6:*:*:*:*:*:* |
Para consultar la lista completa de nombres de CPE con productos y versiones, ver esta página



