
Explotando CVE-2022-0847 - escrito por : Antonius (w1sdom)
Dirty Pipe (CVE-2022-0847) es una de las vulnerabilidades de seguridad más significativas en el Kernel de Linux 5.8 – 5.15.24, descubierta por Max Kellermann en 2022. Esta vulnerabilidad permite a usuarios ordinarios (sin privilegios especiales) sobrescribir datos en archivos que deberían ser de solo lectura. Entendiendo los Conceptos Clave
Antes de discutir Dirty Pipe en detalle, aquí hay algunos conceptos internos del kernel de Linux que deben entenderse:
1. Paginación
La paginación es un mecanismo de gestión de memoria en el kernel de Linux donde el sistema de memoria divide la memoria física en bloques pequeños de tamaño fijo llamados marcos de página, y la memoria virtual se divide en bloques del mismo tamaño llamados páginas.
Este mecanismo permite al kernel mapear el espacio de direcciones virtuales de los procesos a la memoria física de manera no secuencial, lo cual es crucial para la eficiencia y seguridad en los sistemas modernos.
2. Página (Memoria Virtual)
En Linux, una página es la unidad más pequeña de gestión de memoria física manejada por el kernel.
Analogía: la RAM es como un libro gigante. Una página es una hoja de papel en ese libro. El kernel no mueve datos bit a bit, sino hoja por hoja (página por página).
Generalmente, en arquitecturas de sistemas modernos (como x86_64), el tamaño estándar de una página es de 4 KB (4096 bytes).
3. Caché de Páginas
Esta es una parte crucial. Linux no lee archivos directamente del disco cada vez porque es lento. El kernel copia el contenido de los archivos en la RAM llamada Caché de Páginas.
4. Buffer de Tubería
La tubería es un mecanismo de Comunicación entre Procesos (IPC). Internamente, el kernel gestiona las tuberías utilizando la estructura de datos pipe_inode_info. Los datos dentro de una tubería se almacenan en un "buffer" llamado Buffer de Tubería.
5. Bandera del Buffer de Tubería (PIPE_BUF_FLAG_CAN_MERGE)
La bandera PIPE_BUF_FLAG_CAN_MERGE se introdujo en el Kernel de Linux versión 5.8.
Aquí es donde reside la vulnerabilidad principal. La bandera llamada PIPE_BUF_FLAG_CAN_MERGE.
6. Splice
splice() es una llamada al sistema para mover datos entre dos descriptores de archivo sin copiar los datos entre el espacio del kernel y el espacio de usuario. A esto a menudo se le llama mecanismo de copia cero.
La llamada al sistema splice() es el "actor principal" en Dirty Pipe:
7. Copia en Escritura (CoW)
El mecanismo de Copia en Escritura (CoW) es una estrategia de optimización de gestión de memoria utilizada por el kernel de Linux para retrasar la copia de datos hasta que sea absolutamente necesario.
La relación entre Copia en Escritura (CoW) y el exploit Dirty Pipe (CVE-2022-0847) trata sobre cómo un pequeño error en el kernel de Linux logra "engañar" al mecanismo CoW, permitiendo que se escriban datos en archivos que deberían ser de solo lectura.
8. Página Sucia
Una página sucia es una página de memoria en RAM que ha sido modificada por una aplicación, pero los cambios aún no se han escrito de vuelta al almacenamiento secundario (como SSD o disco duro).
Análisis de la Vulnerabilidad Dirty Pipe
Dirty Pipe es un tipo de error lógico en el manejo del buffer de tubería en el kernel de Linux 5.8 hasta el kernel de Linux 5.15.24. El problema principal reside en el mecanismo de Tubería (canal de comunicación entre procesos) y cómo el kernel gestiona la Caché de Páginas (memoria que almacena copias de datos de archivos del disco). El problema central es un error en la bandera PIPE_BUF_FLAG_CAN_MERGE.
El problema principal radica en la falla del kernel al no reinicializar correctamente esta bandera (error lógico). Aquí está el análisis del código: En las funciones copy_page_to_iter_pipe y push_to_pipe en el kernel de Linux anterior a la versión 5.16.11, al realizar operaciones splice, el kernel prepara la estructura pipe_buffer pero olvida limpiar el miembro .flags.
Estructura de Código Vulnerable:
// Ubicación del problema: fs/pipe.c o include/linux/pipe_fs_i.h
struct pipe_buffer {
struct page *page;
unsigned int offset, len;
const struct pipe_buf_operations *ops;
unsigned int flags; // <--- ESTA BANDERA NO SE REINICIA
unsigned long private;
};
Código Antes del Parche (Vulnerable):
// lib/iov_iter.c - Antes del parche de CVE-2022-0847
static size_t copy_page_to_iter_pipe(struct page *page,
size_t offset, size_t bytes, struct iov_iter *i) {
// ---------snip-----------
struct pipe_buffer *buf = &pipe->bufs[head & mask];