Detectaron un fallo en el recolector de elementos no utilizados de Linux que podía conducir a una escalada de privilegios
Hace pocos dias Jann Horn del equipo de Google Project Zero, que previamente identificó las vulnerabilidades de Spectre y Meltdown, dio a conocer una técnica para explotar una vulnerabilidad que encontró en el recolector de elementos no utilizados del kernel de Linux (CVE-2021-4083).
La vulnerabilidad es causada por una condición de carrera cuando se limpian los descriptores de archivo de socket de Unix y potencialmente permite que un usuario local sin privilegios ejecute su código en el nivel del kernel.
El problema es interesante porque la ventana de tiempo durante la cual ocurre la condición de carrera se evaluó como demasiado pequeña para crear vulnerabilidades reales, pero el autor del estudio demostró que incluso las vulnerabilidades inicialmente escépticas pueden convertirse en una fuente de ataques reales si el creador de la vulnerabilidad tiene las habilidades y el tiempo necesarios.
Yann Horn mostró cómo, con la ayuda de manipulaciones de filigrana, es posible reducir la condición de carrera que ocurre cuando se llama a las funciones close() y fget() al mismo tiempo a una vulnerabilidad de clase use-after-free totalmente explotada y lograr acceso a una estructura de datos ya liberada dentro del kernel.
Se produce una condición de carrera durante el proceso de cerrar un descriptor de archivo mientras se llama a las funciones close() y fget() al mismo tiempo. La llamada a close() puede ejecutarse antes de que se ejecute fget(), lo que confundirá al recolector de elementos no utilizados porque, según refcount, la estructura del archivo no tendrá referencias externas, pero permanecerá adjunta al descriptor del archivo, es decir el recolector de elementos no utilizados supondrá que tiene acceso exclusivo a la estructura, pero de hecho, durante un breve período de tiempo, la entrada restante en la tabla de descriptores de archivos seguirá indicando que la estructura se está liberando.
Para aumentar la probabilidad de entrar en una condición de carrera, se utilizaron varios trucos que permitieron aumentar la probabilidad de éxito de la explotación al 30 % al realizar optimizaciones específicas del sistema. Por ejemplo, para aumentar el tiempo de acceso a una estructura con descriptores de archivo en varios cientos de nanosegundos, los datos se expulsaron del caché del procesador al contaminar el caché con actividad en otro núcleo de CPU, lo que hizo posible devolver la estructura de la memoria y no de la memoria caché rápida de la CPU.
La segunda característica importante fue el uso de interrupciones generadas por un temporizador de hardware para aumentar el tiempo de carrera. El momento se eligió para que el controlador de interrupciones se disparara durante la ocurrencia de la condición de carrera e interrumpiera la ejecución del código por un tiempo. Para retrasar aún más el regreso del control, epoll generó alrededor de 50 mil entradas en la cola de espera, lo que requería una iteración en el controlador de interrupciones.
La técnica de explotación de la vulnerabilidad se reveló después de un período de no divulgación de 90 días. El problema
y se solucionó a principios de diciembre. La solución se incluyó en el kernel 5.16 y también se trasladó a las ramas LTS del kernel y los paquetes con el kernel suministrado en las distribuciones. Cabe señalar que la vulnerabilidad se identificó durante el análisis de un problema similar CVE-2021-0920, que se manifiesta en el recolector de basura al procesar el indicador MSG_PEEK.
Otra vulnerabilidad que fue encontrada hace poco en el kernel de Linux, fue la CVE-2022-0742 que puede agotar la memoria disponible y provocar de forma remota una denegación de servicio mediante el envío de paquetes icmp6 especialmente diseñados. El problema está relacionado con una fuga de memoria que ocurre al procesar mensajes ICMPv6 con tipos 130 o 131.
El problema ha estado presente desde el kernel 5.13 y se solucionó en las versiones 5.16.13 y 5.15.27. El problema no afectó a Debian, SUSE, Ubuntu LTS (18.04, 20.04) y las ramas estables de RHEL, se solucionó en Arch Linux.
Finalmente si estás interesado en poder conocer más al respecto de la nota, puedes consultar los detalles en el siguiente enlace.