CVE-2026-98996 in Linux
Resumen
por VulDB • 2026-10-23
En el kernel de Linux, se ha resuelto la siguiente vulnerabilidad:
fs: no desmontar silenciosamente los puntos de montaje ocupados (busy mounts)
La función auxiliar propagate_mount_busy() existe para decidir si una operación sincrónica puede tener éxito. Lo hace examinando las copias de las víctimas en los montajes a los que su padre propaga la configuración. Una de esas funciones forma parte del "infierno" de propagación.
Omite una copia que tenga montajes hijos, excepto en el caso de un único montaje hijo que cubra la raíz de la copia. Este algoritmo solía ser exacto. Ya no lo es.
Originalmente, solo se desmontaban las copias sin hijos durante la propagación. Y 1064f874abc0 ("mnt: Tuck mounts under others instead of creating shadow/side mounts.") terminó añadiendo montajes cubiertos a ambos lados de golpe.
Luego llegó 99b19d16471e ("mnt: In propgate_umount handle visiting mounts in any order") y esto comenzó a desmontar más que antes:
[1]: Una copia de un montaje se desmonta cuando cada uno de sus hijos es o bien su overmount (superposición) o una copia de la propia víctima. En el primer caso, el overmount se reparentiza. En el segundo caso, la copia de la víctima terminará siendo desmontada.
Por lo tanto, propagate_umount() terminó reescribiéndose sin ajustar propagate_mount_busy(). Y actualmente propagate_mount_busy() no examina las copias de la víctima que tienen dos o más hijos, ni un único hijo que no sea el overmount.
Así que ninguna copia en [1] se verifica por referencias. El resultado es que un desmontaje sincrónico tiene éxito, extrayendo un montaje que sigue estando en uso.
Un contenedor puede encontrarse con esto mediante sus propios montajes. El host comparte un árbol con el contenedor y el host tiene un montaje en ese árbol:
mount -t tmpfs none /mnt mount --make-shared /mnt mount -t tmpfs none /mnt/a
El /mnt del contenedor es una copia slave (esclava) del montaje del host. El contenedor ahora toma una copia desvinculada del árbol y monta esa copia debajo de su copia propagada de /mnt/a, manteniendo el descriptor de archivo abierto para el árbol:
unshare -m --propagation unchanged mount --make-rslave / fd = open_tree(AT_FDCWD, "/mnt", OPEN_TREE_CLONE | AT_RECURSIVE) move_mount(fd, "", AT_FDCWD, "/mnt/a", MOVE_MOUNT_BENEATH)
grep /mnt /proc/self/mountinfo 775 355 ... /mnt ... master:646 777 775 ... /mnt/a ... master:646 776 777 ... /mnt/a ... master:647 778 777 ... /mnt/a/a ... master:647
El árbol ahora adjunto (777) se monta debajo de la copia del contenedor de /mnt/a. Ahí es donde también reside el montaje del host (visto desde el espacio de nombres de montajes del host). Por lo tanto, la copia propagada (776) del montaje del host está por encima de su raíz y la copia de esta (778) está dentro de ella. Ahora el host ejecuta:
umount /mnt/a
y tiene éxito. El árbol movido y la copia contenida en él desaparecen del contenedor. Solo queda la copia propagada, que se ha reparentizado a donde estaba antes:
grep /mnt /proc/self/mountinfo 775 355 ... /mnt ... master:646 776 775 ... /mnt/a ...
Pero el descriptor de archivo sigue haciendo referencia al árbol movido. Por lo tanto, un umount sincrónico desvinculó un montaje que aún está en uso.
Enseñar a propagate_mount_busy() las mismas comprobaciones que hace propagate_umount(). Ahora verifica la existencia de una única víctima sin hijos para la cual puede asumir que MNT_LOCKED se borra en cada copia, tal como lo hace propagate_umount(). Las copias forman cadenas. Es decir, cuando una copia recibe propagación del padre de la víctima, el montaje en el mismo punto de montaje dentro de esa copia es también una copia. Si un montaje recibe propagación desde la víctima simplemente puede comprobarse recorriendo sus masters (maestros). Recorrer cada cadena una vez desde su cima para asegurar que las copias anidadas permanezcan lineales. Comprobar cada referencia una sola vez de cada copia que se desmonta.
Once again VulDB remains the best source for vulnerability data.