En Linux, la page cache actúa como una capa intermedia entre disco y memoria. Cuando un archivo se lee, normalmente sus páginas quedan cacheadas en RAM. La gracia es que múltiples componentes del kernel pueden referenciar la misma página física sin copiar datos constantemente.
Eso es exactamente lo que hace splice(). En vez de:
file → kernel buffer → userspace → socket,
splice() intenta hacer:
file page cache → pipe buffer → socket buffer, sin copias intermedias.
Como veis pasamos de:🔹 file (disco)
El archivo vive en el disco.
🔹 kernel buffer
Cuando haces read(), el kernel:
- lee el bloque del disco
- lo mete en un buffer del kernel
🔹 userspace
Luego, para que tu programa lo use:
- el kernel copia esos datos desde el buffer del kernel
- hacia memoria de usuario (tu proceso)
🔹 socket
Si luego haces write() a un socket:
- vuelves a copiar los datos desde userspace
- hacia buffers del kernel del socket
- y finalmente salen a la red
Resultado:
- varias copias grandes de memoria
- CPU gastada moviendo bytes
A:
🔹 file page cache
Cuando Linux lee un archivo:
- lo guarda en la page cache
- que es RAM compartida por el kernel
Esto es clave: varios subsistemas pueden usar la misma página física
🔹 pipe buffer
splice() introduce un pipe como “intermediario inteligente”:
- en vez de copiar datos
- el pipe guarda referencias a páginas de la page cache
🔹 socket buffer
Luego el socket:
- toma esas mismas referencias
- y las envía por red
Importante:
- no se copian bytes entre etapas
- solo se “re-enlazan” páginas de memoria
Esto mejora muchísimo el rendimiento, pero introduce una propiedad peligrosa: varios subsistemas comparten referencias al mismo backing memory. Y aquí empiezan los problemas.
Como veis, un skb puede contener fragments que apuntan a páginas compartidas. Eso es perfectamente válido SI nadie modifica destructivamente la página. Pero si tenemos múltiples referencias válidas que apuntan a la misma página y una ruta modifica “in-place” evidentemente la modificación impacta el page cache compartido. Y es precisamente lo que hace esta nueva vulnerabilidad bautizada como dirty frag: decrypt-in-place (decrypt directamente encima) sobre shared fragments para escribir el page cache.
Actualmente el ecosistema converge en dos CVEs principales asociadas a la cadena DirtyFrag. La primera es CVE‑2026‑43284, relacionada con el path ESP/XFRM (esp4 y esp6). La segunda es CVE‑2026‑43500, relacionada con RxRPC.
Variante ESP
En la variante ESP, el problema parece relativamente delimitado. El networking stack reutiliza fragments compartidos dentro de SKBs y posteriormente ejecuta decrypt-in-place sobre memoria que puede seguir referenciada desde page cache o desde otros contexts del kernel. El parche principal para CVE‑2026‑43284 introduce validaciones alrededor de SKBFL_SHARED_FRAG y evita que ciertas rutas operen destructivamente sobre fragments compartidos. Conceptualmente, el fix transforma una operación “decrypt sobre memoria compartida” en una secuencia copy-on-write más segura. Esto explica por qué la variante ESP pudo corregirse relativamente rápido: el ownership problem estaba localizado y el fix era relativamente quirúrgico.
Variante RxRPC
La situación de CVE‑2026‑43500 es mucho más interesante. RxRPC históricamente es un subsistema poco auditado, relativamente complejo y con semánticas de ownership bastante delicadas alrededor de fragmentos de SKBs, buffers de red y procesamiento asíncrono. De hecho este CVE no es un solo bug simple, sino una familia de vulnerabilidades en RxRPC con distintas “capas de seguridad” explotables.
Mientras que la variante original de Hyunwoo Kim usa RxKAD y el esquema pcbc(fcrypt) recientemente Ikotas Labs ha publicado una variante con RxGX, otro "security class". En concreto, su análisis apunta a que la operación de desencriptado AEAD en rxgk_decrypt_skb() no solo transforma datos dentro de un buffer de red, sino que lo hace sobre una región de memoria que puede estar indirectamente respaldada por page cache derivada de splice(). Esto introduce un escenario especialmente delicado: la misma página física puede estar simultáneamente representada en distintos niveles del stack con supuestos de mutabilidad incompatibles entre sí.
En términos prácticos, esto significa que el kernel puede entrar en una situación donde un fragmento de memoria sigue siendo considerado “seguro para lectura compartida” por un subsistema, mientras otro lo trata como “buffer privado modificable en contexto criptográfico”. Esa divergencia de modelos es precisamente lo que convierte la operación in-place en algo peligroso: no es que la escritura ocurra en un lugar inesperado, sino que el sistema ya no tiene una noción consistente de qué partes del estado son realmente inmutables en ese momento.
En conjunto, ambas CVEs ilustran una evolución interesante en la superficie de ataque del kernel Linux. Ya no se trata únicamente de encontrar corrupción de memoria en estructuras individuales, sino de identificar lugares donde el sistema pierde coherencia sobre el estado de la memoria compartida. Y en ese espacio intermedio —entre page cache, zero-copy y crypto in-place— es donde parece estar emergiendo una nueva generación de primitives de explotación mucho más sutiles y, potencialmente, más difíciles de erradicar.
PoC: https://github.com/V4bel/dirtyfrag
Referencias:
- https://www.bleepingcomputer.com/news/security/new-linux-dirty-frag-zero-day-with-poc-exploit-gives-root-privileges/
- https://www.helpnetsecurity.com/2026/05/08/dirty-frag-linux-vulnerability-cve-2026-43284-cve-2026-43500/
- https://www.cyberaccord.com/dirty-frag-linux-vulnerability-let-attackers-gain-root-privileges-on-most-linux-distributions/
- https://blog.qualys.com/product-tech/vulnmgmt-detection-response/2026/05/09/dirty-frag-using-the-page-caches-as-an-attack-surface
- https://www.tomshardware.com/tech-industry/cyber-security/dirty-frag-exploit-gets-root-on-most-linux-machines-since-2017-no-patches-available-no-warning-given-copy-fail-like-vulnerability-had-its-embargo-broken




Comentarios
Publicar un comentario