CVE-2026-46242: Vulnerabilidad de epoll en Linux que permite obtener privilegios de root

Ya están disponibles los parches de php2shell (CVE-2026-109618 y CVE-2026-109619) para PHP en fin de vida útil. Dado que las respuestas del departamento de ventas están tardando más de lo habitual debido a la elevada demanda, la forma más rápida de obtener los paquetes parcheados es comprar ELS para Runtimes en línea (se abre en una pestaña nueva). Lee las preguntas frecuentes sobre los parches

Ir directamente al resumen generado por IA de esta entrada del blog

  • Resume esta entrada con Perplexity
  • Resume esta publicación con Gemini

La versión resumida

Ir a la versión completa ↓

Qué: «Bad Epoll», registrado como CVE-2026-46242, es una condición de carrera de tipo «use-after-free» en el subsistema epoll del núcleo de Linux. En la ruta de limpieza de ep_remove(), una ruta de cierre borra el enlace epoll del archivo y sigue utilizándolo, mientras que una liberación simultánea del archivo, al detectar ese enlace borrado, libera el objeto subyacente. Un usuario sin privilegios aprovecha esa escritura errónea para obtener privilegios de root.

Impacto: Un usuario local sin privilegios se adelanta en la carrera, convierte la escritura de 8 bytes tras una liberación de memoria (use-after-free) en el control de una estructura «file» mediante un ataque de caché cruzada y, a continuación, escala los privilegios para obtener acceso de lectura arbitrario al núcleo y secuestrar el flujo de control, lo que le otorga privilegios de root completos. El PoC público (J-jaeyoung/bad-epoll, enviado a Google kernelCTF) indica una fiabilidad del 99 % en un núcleo 6.12, la misma base que AlmaLinux 10.

Estado: El fallo es real y ya se ha corregido en el código fuente original. Se notificó de forma privada en febrero, se corrigió el 24 de abril y se hizo público el 30 de mayo; la corrección es anterior a la divulgación en cinco semanas y no se ha producido ningún uso en el mundo real. Comenzó como un «0-day» en el kernelCTF, pero para los defensores hoy en día es un «N-day» con un exploit público.

Gravedad: kernel.org y NVD le otorgan una puntuación CVSS de 7,8 (Alta: AV:L/AC:L/PR:L); Red Hat le asigna una puntuación de 7,0, al considerar que la carrera de ~6 instrucciones es difícil de ganar. En cualquier caso, el resultado es el acceso como usuario root, y la fiabilidad de ~99 % de la prueba de concepto (PoC) convierte ese estrecho margen en un problema práctico, no teórico.

Por qué es importante: Los sistemas expuestos son aquellos en los que el aislamiento local es el resultado: alojamiento compartido, servidores multitenant, ejecutores de CI y nodos de contenedores que ejecutan código no fiable. epoll es la base de casi todos los servicios, por lo que no hay ninguna superficie de ataque que se pueda desactivar. En este caso, un LPE local es el evento que traspasa los límites.

Haz esto ahora mismo: no existe una solución de configuración sencilla —epoll no se puede desactivar—. Aísla la ejecución local no fiable y comprueba que el núcleo incorpore realmente la corrección, en lugar de fiarte de que un exploit no haya funcionado. Se está analizando un parche de KernelCare que no requiere reinicio; todavía no hay nada disponible en los repositorios. Más detalles a continuación.

¿Estás harto de tener que programar otro reinicio de emergencia?

KernelCare aplica parches al núcleo de Linux sin tiempo de inactividad, interrupciones ni ventanas de mantenimiento de emergencia.

Estado de KernelCare (actualizado el 4 de julio de 2026 — en análisis): Se trata de un linaje de kernel compartido: RHEL, AlmaLinux, Rocky, Oracle Linux y CloudLinux de la misma versión principal comparten el mismo ep_remove() Código y exposición: considérense «EL10» y «EL9» como una misma familia. Red Hat indica que RHEL 9 y 10 se ven afectados (7/8 no se ven afectados). EL10 se ve afectado; es muy probable que EL9 herede la confirmación inicial que se ha retroportado. Todavía estamos verificando la reproducción del fallo y las versiones afectadas exactas. Ningún parche de KernelCare ha completado la validación, y ninguno está aún disponible en ningún canal de distribución (seguido como KCARE-27500). A día de hoy no existe ninguna configuración que el cliente pueda aplicar para mitigar el problema; véase la sección de mitigación.

Descargar KernelCare

La versión larga

Hay dos cosas que te incitarán a cerrar este ticket antes de tiempo, y ambas son un error.

El primero es el propio archivo README del PoC, que indica que el fallo solo afecta a los núcleos «basados en la versión 6.4 o posterior» y considera seguros los núcleos basados en la versión 6.1. Si lees eso en un sistema con CloudLinux 9 —basado en la versión 5.14—, lo más lógico sería que te consideraras fuera del ámbito de aplicación. Pero te equivocarías. El segundo es una ejecución limpia del exploit. Si diriges el PoC público a un núcleo en una pequeña máquina virtual y observas cómo pierde la carrera unos cientos de miles de veces, es fácil escribir «no reproducible, no afectado» y pasar página. También es un error y, en el caso de este fallo, puede resultar peligroso.

«Bad Epoll» es una condición de carrera de tipo «use-after-free» en el subsistema eventpoll del núcleo —el mecanismo que sustenta las llamadas al sistema epoll, del que dependen prácticamente todos los servicios de red del sistema—. La condición de carrera se produce en la ruta de limpieza de ep_remove(), y la ventana tiene una amplitud aproximada de seis instrucciones de CPU. Si no se aprovecha, no ocurre nada. Si se aprovecha, como hace el exploit público con gran fiabilidad en un núcleo 6.12, un usuario sin privilegios tiene el camino libre hacia los privilegios de root.

Se ha confirmado que EL10 es explotable y que es muy probable que EL9 se vea afectado a través de la confirmación de introducción retroportada, por lo que no se trata de una interpretación cautelosa de un aviso del proveedor. Se trata de un fallo real, con una corrección real en el código fuente original, y un exploit público ya preparado para su uso malicioso que ya figura en una propuesta de kernelCTF.

Cómo funciona mal Epoll

epoll mantiene un struct eventpoll objeto, respaldado por un struct file, para cada instancia de epoll. Es importante desmontarlo correctamente, ya que pueden darse dos vías que acaben cerrando lo mismo casi al mismo tiempo: la vía de eliminación de epoll y una liberación simultánea del archivo subyacente.

El error es un pequeño fallo de ordenación en ese desmontaje. Dentro de ep_remove(), el código antiguo borraba la asociación epoll del archivo (file->f_ep) mientras se sujeta file->f_lock, y luego siguió utilizando ese mismo archivo y sus datos de eventpoll dentro de la sección crítica. Una operación concurrente __fput() Si se utiliza la ruta rápida de liberación en ese intervalo, se produce un valor NULL transitorio f_ep, llega a la conclusión de que no tiene que realizar ninguna limpieza de epoll y pasa directamente a f_op->release. En una configuración «epoll-vigila-epoll», esa ruta libera el elemento vigilado struct eventpoll sin lugar a dudas. La primera ruta sigue en marcha, y su siguiente hlist_del_rcu() escribe a través de un puntero incrustado en la memoria que acaba de liberarse.

[Unprivileged local process]
│  creates linked epoll objects backed by struct file
▼
[Two close paths race inside ep_remove()]
│  path A clears file->f_ep, keeps using the file
│  path B (__fput) sees NULL f_ep, skips epoll cleanup
▼
[Path B frees the watched struct eventpoll / recycles the file slot]
│  path A's hlist_del_rcu() writes into freed memory
▼
[Attacker-controlled 8-byte use-after-free write]
▼
[Cross-cache reclaim gives control of a struct file]
▼
[Arbitrary kernel read + control-flow hijack]
▼
[uid=0 root shell]

La escritura en sí se realiza en un espacio de ocho bytes dentro de la memoria liberada, lo que parece manejable hasta que se observa lo que hace el exploit con ella. La cadena pública utiliza cuatro objetos epoll organizados en dos pares: al cerrar un par se desencadena la carrera de condiciones, mientras que el otro se convierte en la víctima. Esto convierte la escritura de 8 bytes en un «use-after-free» en un struct file, utiliza la recuperación de memoria del montón entre cachés para sustituir esa ranura por un objeto controlado por el atacante y, a continuación, consigue leer datos arbitrarios del núcleo y secuestrar el flujo de control.

Precisamente por lo reñida que está la carrera es por lo que resulta fácil pasar por alto este error, y por lo que pasó desapercibido durante años. La misma confirmación de 2023 que lo introdujo también introdujo una carrera similar, CVE-2026-43074, que se detectó y corrigió a principios de 2026. Esa corrección no solucionó el problema de «Bad Epoll». El hecho de que se haya aplicado una corrección de epoll este año no prueba que se tengan ambos.

Qué cambia con la corrección de Upstream

La corrección es pequeña y autónoma, por lo que se adapta sin problemas. Impide que ep_remove() utilice una referencia sin protección al archivo que está eliminando.

La ruta corregida coloca el archivo en primer plano, tomando como referencia a través de epi_fget() y sosteniendo un struct file *file __free(fput) proteger antes de que entre en contacto file->f_lock. Mientras se mantenga esa referencia, el contador de referencias del archivo no puede bajar a cero, por lo que __fput() no se puede iniciar y la ruta de liberación concurrente no puede liberar el archivo ni su objeto eventpoll de la limpieza. Si no se puede liberar el pin, ep_remove() se interrumpe antes de borrar f_ep, y la ruta de liberación sigue el proceso de limpieza habitual, más lento, que se sincroniza a través del mutex «eventpoll» en lugar de producirse una carrera de acceso.

Desde un punto de vista conceptual:

Before:  clear epoll link → keep using file → concurrent release frees it → write into freed memory
After:   pin file reference → do cleanup while pinned → concurrent release cannot free → release reference

Ese único cambio resuelve ambas partes del error: la liberación de la variable vigilada struct eventpoll, y el reciclaje de la struct file ranura, mientras que la ruta original sigue creyendo que mantiene un bloqueo válido.

¿A quién afecta?

La respuesta breve para la familia CloudLinux y AlmaLinux: las versiones 9 y 10 se ven afectadas y así se ha confirmado; se espera que la versión 8 no se vea afectada.

Afectados:

  • CloudLinux 10 / AlmaLinux 10 (basado en 6.12): Una variante del PoC público, diseñada únicamente para provocar un bloqueo, hace que un host de AlmaLinux 10 sin privilegios en un servidor físico entre en pánico de forma fiable en cuestión de segundos: se trata de un «use-after-free» explotable y convertido en arma, no de una simple curiosidad de laboratorio. Se trata de la misma base 6.12 con la que el exploit completo consigue acceso root con una fiabilidad del 99 % en el código original.
  • CloudLinux 9 / AlmaLinux 9 (basadas en 5.14): Probablemente afectadas a través de la confirmación inicial retroportada; Red Hat incluye a RHEL 9 en la lista de sistemas afectados porque dicha confirmación se retroportó a esa rama. Aún se está verificando si el problema se reproduce en la rama 5.14, por lo que hay que considerarlo como afectado a la espera de confirmación, en lugar de como un hecho comprobado internamente.

Se espera que no se vea afectado, pero compruébalo antes de darlo por hecho:

  • CloudLinux 8 / AlmaLinux 8 (basado en 4.18): Red Hat indica que RHEL 7 y 8 no se ven afectados, y se espera que CL8 tampoco lo esté por herencia. Si un auditor o un cliente necesita una confirmación rotunda, comprueba la fuente en lugar de darlo por sentado.

La ventana de versiones es la primera trampa. El archivo README del PoC describe un rango de la línea principal que abarca desde la v6.4 en adelante, y califica de «seguros» los núcleos basados en la v6.1. Eso es cierto para la línea principal, pero no sirve de nada para Enterprise Linux, ya que los proveedores retroportan el cambio introducido a líneas mucho más antiguas. Un núcleo de EL9 basado en la 5.14 se sitúa muy por debajo de la v6.4 y sigue viéndose afectado. No extrayás conclusiones de la versión de upstream para tu máquina EL.

Una reproducción fallida es la segunda trampa. Las vulnerabilidades de tipo «race» son extremadamente sensibles al número de núcleos, la programación, la disposición del montón y la configuración de compilación. Una prueba inicial en una pequeña máquina virtual con dos vCPU no detectó ninguna vulnerabilidad de tipo «race» y parecía estar libre de problemas; sin embargo, un reproductor más potente en un sistema físico multinúcleo provocó un pánico en la misma línea del núcleo en cuestión de segundos. El problema fue un entorno de prueba inadecuado, no un núcleo parcheado. No interpretes la ausencia de una vulnerabilidad de tipo «race» como una garantía de seguridad.

Así que compruébalo con el código fuente, no con el exploit. Buscar con «grep» el hash de la confirmación del código original puede llevar a confusión, ya que las adaptaciones a versiones anteriores eliminan el hash. En su lugar, comprueba si aparece el patrón de corrección dentro de ep_remove():

grep -n 'epi_fget\|__free(fput)' /usr/src/kernels/$(uname -r)/fs/eventpoll.c

Si ep_remove() bloquea el archivo con epi_fget() y un __free(fput) tenga cuidado antes de tocarlo file->f_lock, la corrección está presente. Si no están presentes, el núcleo no está parcheado, y cualquier exploit negativo ejecutado en él fue un falso negativo.

Actúa ya

Se lo digo sin rodeos: no existe una solución clara para mitigar este problema de configuración.

epoll es una interfaz de llamadas al sistema fundamental. nginx, php-fpm, mysqld, systemd… Prácticamente todo lo que hay en un servidor de producción se basa en ella, y está habilitada en todos los núcleos de uso general. No hay ningún parámetro sysctl que cambiar, ningún módulo que añadir a la lista negra ni ninguna capacidad que se pueda eliminar para cerrar la vía de vulnerabilidad sin afectar a las cargas de trabajo que generan ingresos para el servidor. Ni siquiera requiere espacios de nombres de usuario ni capacidades especiales; el investigador señala que se puede acceder a ella desde contextos restringidos, incluido el entorno aislado (sandbox) del motor de renderizado de un navegador. Cualquiera que te ofrezca una solución de refuerzo de epoll en una sola línea te está vendiendo un sistema defectuoso.

Dado que el error es solo local (AV:L, PR:L), las medidas de control duraderas son las de siempre, que ya conoces:

  • Limita el número de usuarios que pueden ejecutar código en los servidores afectados, ya que este fallo requiere un punto de acceso local sin privilegios; cuantos menos puntos de acceso haya, menor será la exposición.
  • Aísla la ejecución local no fiable y semiconfiable —código del cliente, tareas de CI, pasos de compilación— de los servidores que más necesitas proteger, o trasládala a núcleos que puedas reparar en primer lugar.
  • Da prioridad a los servidores en los que el aislamiento local constituye la verdadera barrera de seguridad: alojamiento compartido, nodos multitenant, ejecutores de CI y servidores de contenedores.
  • Comprueba que el núcleo incorpore la corrección mediante la comprobación del código fuente descrita anteriormente, en lugar de dar por sentada la seguridad basándote en que la ejecución del exploit no haya dado lugar a ningún error.

Momento decisivo. Si un servidor no ejecuta código local no fiable y cuenta con un grupo reducido de usuarios de confianza, el riesgo residual es menor y puedes aplicar parches con tu periodicidad habitual en cuanto se publique una errata o un parche que no requiera reinicio. Si un servidor ejecuta código que no controlas —alojamiento compartido, CI, entorno multitenant—, considéralo expuesto desde hoy mismo y da prioridad en la cola a un parche que no requiera reinicio o a un kernel corregido en cuanto esté disponible.

Parcheo sin reinicio

Este es el tipo de fallo para el que existen los parches sin necesidad de reiniciar. El cambio del desarrollador original está disponible, pero eso no protege a un sistema en funcionamiento: el proveedor tiene que adaptarlo, hay que instalar el paquete y el equipo tiene que arrancar con el nuevo núcleo. Ese último paso es donde persiste el riesgo, y es más difícil precisamente donde más importa.

La corrección consiste en un pequeño ajuste de limpieza independiente, lo que la convierte en una buena candidata a parche que no requiere reinicio. Se trata de una adaptación directa del pin de referencia ep_remove() del código original, aplicada al núcleo en ejecución, de modo que la limpieza en curso ya no pueda liberar el archivo subyacente; es decir, ofrece la misma garantía que la corrección del código original, pero sin necesidad de reiniciar el sistema.

En el caso de CloudLinux y AlmaLinux, ya se ha identificado la solución: se trata de un backport directo del pin de referencia ep_remove() del proyecto original (backport de RHEL 10, Gerrit 257974). El backport de KernelCare aún se está analizando, y se está verificando la reproducibilidad en EL10 y EL9, por lo que ningún parche ha completado la validación y ninguno se encuentra todavía en los canales de pruebas, principal o ePortal. LibCare queda fuera del alcance de este caso: se trata de un error exclusivo del núcleo, por lo que no hay ningún aspecto relacionado con las bibliotecas del espacio de usuario que requiera un parche.

Una vez que una versión está disponible, su implementación desde el canal de pruebas (feed) se realiza de la siguiente manera:

kcarectl --update --prefix test

Para confirmar que la versión del parche en ejecución tiene una fecha igual o posterior a la de lanzamiento:

kcarectl --info | grep kpatch-build-time

La fecha de compilación por sí sola no prueba nada. Comprueba directamente la correspondencia con el CVE, la errata del proveedor, el patrón de origen o el estado del parche de KernelCare.

Descargar KernelCare →

Detección

Un epoll defectuoso no deja ninguna huella clara en el disco. El exploit funciona íntegramente en la memoria del núcleo —ganando una carrera, corrompiendo un objeto liberado, reescribiendo el flujo de control—, por lo que las herramientas de integridad de archivos no detectan nada. El desencadenante se construye a partir de interfaces comunes (creación de instancias de epoll, registro de descriptores, timerfds, cierre de los mismos) que son habituales en cualquier host Linux. Esto traslada la detección al ámbito del comportamiento, y cada uno de los siguientes puntos es una pista, no una prueba:

  • Procesos sin privilegios que crean y destruyen un gran número de instancias de epoll y timerfds en bucles muy cortos, lo que se corresponde con el bombardeo de una situación de carrera estrecha.
  • Errores «oops» del núcleo o errores de corrupción de listas en la ruta de desmontaje de eventpoll, con firmas en torno a ep_show_fdinfo, ep_clear_and_put, ep_eventpoll_releaseo __fput.
  • Se producen repetidos fallos del núcleo y reinicios en un servidor multinúcleo sin que haya ningún cambio en el hardware ni en la configuración que los explique; un disparador diseñado exclusivamente para provocar fallos hace que el sistema entre en pánico en cuestión de segundos.
  • Una cuenta de usuario o de servicio local que obtiene privilegios poco después de que se produzca una ráfaga de lo anterior, sin que haya ningún evento de «sudo» o de inicio de sesión que lo justifique.

Si se ha ejecutado código local no fiable o semiconfiable en un host EL9 o EL10 expuesto y se observa inestabilidad del núcleo concentrada en la ruta de cierre de epoll, hay que dar prioridad a la aplicación de parches y considerar que el host requiere un análisis más detallado —nuevas cuentas o claves SSH, configuración de autenticación modificada, servicios inesperados— en lugar de interpretar que los hash de los archivos estén limpios como una ausencia de compromiso.

Por qué es importante este tema

«Bad Epoll» no implica la ejecución remota de código. Nadie consigue acceso root a tu servidor desde Internet mediante esto. Para los entornos en los que realmente se produce, eso supone un pequeño consuelo.

El alojamiento compartido ejecuta el código de los clientes. Los ejecutores de CI ejecutan lo que les indique la última solicitud de incorporación de cambios. Los contenedores y los nodos de Kubernetes ejecutan cargas de trabajo con distintos niveles de confianza, y los servidores multitenant existen precisamente para mantener separados a los distintos usuarios. En todos estos casos, la escalada de privilegios local es el incidente que todo el diseño pretende evitar. Convierte el código al que se le permitía ejecutarse en código que se ejecuta como root, donde nunca debería haberlo hecho. El hecho de que también se pueda acceder al fallo desde lugares a los que la mayoría de los fallos del kernel no llegan, como el entorno aislado del renderizador de un navegador, no hace más que ampliar la superficie de ataque.

La razón por la que es fácil equivocarse es la misma por la que resulta peligroso. Hay tres señales que parecen plausibles y que apuntan todas hacia «seguro», pero que en realidad son engañosas: la línea de versión «v6.4+» pasa por alto las adaptaciones hacia atrás en EL9, basado en 5.14; una ejecución fallida del exploit ignora lo difícil que es provocar una carrera de seis instrucciones sin un esfuerzo deliberado; y el hecho de haber aplicado la corrección de epoll a principios de este año no sirve de nada para este caso. Si te fías de cualquiera de ellas, marcarás un host vulnerable como seguro.

El riesgo se concentra donde siempre: en los servidores que llevan unas cuantas actualizaciones de retraso, en los servidores de integración continua (CI) que llevan años en funcionamiento y que nadie reinicia, y en los servidores multitenant en los que la ventana de mantenimiento es objeto de negociación. Esos son precisamente los servidores en los que un «N-day» con una prueba de concepto (PoC) pública se convierte silenciosamente en un problema del mismo día, y aquellos en los que un parche que no requiere reinicio marca la diferencia entre solucionarlo hoy o hacerlo el próximo trimestre.

Lista de verificación de medidas correctoras priorizadas

  • Considera que CloudLinux 9 y CloudLinux 10 están afectados y confirmados. No excluyas CL9 basándote en la nota «v6.4+», ya que la confirmación inicial se retroportó a la línea 5.14.
  • Confirma cada kernel por su código fuente, no por el resultado del exploit: comprueba ep_remove() para el epi_fget() + __free(fput) Establecer un patrón y considerar que una ejecución fallida de la prueba de concepto (PoC) no es concluyente.
  • No des por sentado que el hecho de que «hayamos corregido un fallo de epoll este año» solucione este problema; la corrección del CVE-2026-43074, relacionado con este, no resuelve el fallo «Bad Epoll».
  • Da prioridad a los servidores en los que el aislamiento local constituya la barrera de seguridad: alojamiento compartido, nodos multitenant, ejecutores de CI, contenedores y servidores de desarrollo que ejecuten código no fiable.
  • Reduzca y aísle la ejecución local no fiable hasta que se aplique una solución. No hay ninguna medida de mitigación a través de la configuración a la que recurrir: epoll no se puede desactivar.
  • Comprueba CloudLinux 8 en su origen antes de decirle a nadie que está todo en orden.
  • Busca fallos inexplicables del núcleo y actividad inusual de epoll/timerfd en la ruta de desmontaje de eventpoll, y considera que los hash de archivos limpios no constituyen una prueba suficiente.
  • Aplica el parche de KernelCare que no requiere reinicio tan pronto como se haya validado y se haya incorporado al canal de actualizaciones, especialmente en los servidores en los que resulte más complicado reiniciar el sistema. El parche aún se encuentra en fase de análisis; las etiquetas «K» se publicarán aquí cuando se lancen las versiones.

Aplica parches a cualquier kernel sin necesidad de reiniciar. Si aún no eres usuario de KernelCare, ahora es un buen momento para descubrir cómo la aplicación de parches sin reinicio protege los sistemas Linux críticos sin necesidad de ventanas de mantenimiento de emergencia ni tiempos de inactividad.

Consigue KernelCare hoy mismo →

Referencias

Únase a más de 4.500 profesionales de Linux y el código abierto.

2 veces al mes. Sin spam.

Índice
Obtenga las respuestas de seguridad de código abierto que necesita

Únase a más de 4.500 profesionales de Linux y el código abierto.

2 veces al mes. Sin spam.