Instituto Nacional de ciberseguridad. Sección Incibe
Instituto Nacional de Ciberseguridad. Sección INCIBE-CERT

Vulnerabilidad en kernel de Linux (CVE-2024-53219)

Gravedad CVSS v3.1:
MEDIA
Tipo:
No Disponible / Otro tipo
Fecha de publicación:
27/12/2024
Última modificación:
19/09/2025

Descripción

En el kernel de Linux, se ha resuelto la siguiente vulnerabilidad: virtiofs: usar páginas en lugar de puntero para E/S directa del kernel Al intentar insertar un módulo de kernel de 10 MB guardado en un virtio-fs con la caché deshabilitada, se informó la siguiente advertencia: ------------[ cortar aquí ]------------ ADVERTENCIA: CPU: 1 PID: 404 en mm/page_alloc.c:4551 ...... Módulos vinculados: CPU: 1 PID: 404 Comm: insmod No contaminado 6.9.0-rc5+ #123 Nombre del hardware: QEMU Standard PC (i440FX + PIIX, 1996) ...... RIP: 0010:__alloc_pages+0x2bf/0x380 ...... Rastreo de llamadas: ? __warn+0x8e/0x150 ? __alloc_pages+0x2bf/0x380 __kmalloc_large_node+0x86/0x160 __kmalloc+0x33c/0x480 virtio_fs_enqueue_req+0x240/0x6d0 virtio_fs_wake_pending_and_unlock+0x7f/0x190 queue_request_and_unlock+0x55/0x60 fuse_simple_request+0x152/0x2b0 fuse_direct_io+0x5d2/0x8c0 fuse_file_read_iter+0x121/0x160 __kernel_read+0x151/0x2d0 kernel_read+0x45/0x50 kernel_read_file+0x1a9/0x2a0 init_module_from_file+0x6a/0xe0 idempotent_init_module+0x175/0x230 __x64_sys_finit_module+0x5d/0xb0 x64_sys_call+0x1c3/0x9e0 do_syscall_64+0x3d/0xc0 entry_SYSCALL_64_after_hwframe+0x4b/0x53 ...... ---[ end trace 000000000000000 ]--- La advertencia se activa de la siguiente manera: 1) syscall finit_module() gestiona la inserción del módulo e invoca kernel_read_file() para leer primero el contenido del módulo. 2) kernel_read_file() asigna un búfer de 10 MB mediante vmalloc() y lo pasa a kernel_read(). kernel_read() construye un iter kvec utilizando iov_iter_kvec() y lo pasa a fuse_file_read_iter(). 3) virtio-fs desactiva la caché, por lo que fuse_file_read_iter() invoca fuse_direct_io(). Por ahora, el tamaño máximo de lectura para el iter kvec solo está limitado por fc->max_read. Para virtio-fs, max_read es UINT_MAX, por lo que fuse_direct_io() no divide el búfer de 10 MB. Guarda la dirección y el tamaño del búfer de 10 MB en out_args[0] de una solicitud de fuse y pasa la solicitud de fuse a virtio_fs_wake_pending_and_unlock(). 4) virtio_fs_wake_pending_and_unlock() utiliza virtio_fs_enqueue_req() para poner en cola la solicitud. Debido a que los virtiofs necesitan una dirección que pueda ser DMA, virtio_fs_enqueue_req() usa kmalloc() para asignar un buffer de rebote para todos los argumentos de fusión, copia estos argumentos en el buffer de rebote y pasa la dirección física del buffer de rebote a virtiofsd. La longitud total de estos argumentos de fusión para la solicitud de fusión pasada es de aproximadamente 10 MB, por lo que copy_args_to_argbuf() invoca kmalloc() con un parámetro de tamaño de 10 MB y activa la advertencia en __alloc_pages(): if (WARN_ON_ONCE_GFP(order > MAX_PAGE_ORDER, gfp)) return NULL; 5) virtio_fs_enqueue_req() volverá a intentar la asignación de memoria en un kworker, pero no ayudará, porque kmalloc() siempre devolverá NULL debido al tamaño anormal y finit_module() se colgará para siempre. Una solución factible es limitar el valor de max_read para virtio-fs, por lo que la longitud pasada a kmalloc() será limitada. Sin embargo, afectará el tamaño máximo de lectura para la lectura normal. Y para la escritura de virtio-fs iniciada desde el kernel, tiene el mismo problema pero ahora no hay forma de limitar fc->max_write en el kernel. Entonces, en lugar de limitar los valores de max_read y max_write en el kernel, se introduce use_pages_for_kvec_io en fuse_conn y se establece como verdadero en virtiofs. Cuando use_pages_for_kvec_io está habilitado, fuse usará páginas en lugar de punteros para pasar los datos de KVEC_IO. Después de cambiar a páginas para los datos de KVEC_IO, estas páginas se usarán para DMA a través de virtio-fs. Si estas páginas están respaldadas por vmalloc(), {flush|invalidate}_kernel_vmap_range() son necesarias para vaciar o invalidar la caché antes de la operación de DMA. Por lo tanto, agregue dos nuevos campos en fuse_args_pages para registrar la dirección base del área vmalloc y la condición que indica si se necesita invalidación. --truncated---

Productos y versiones vulnerables

CPE Desde Hasta
cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:* 5.4 (incluyendo) 6.11.11 (excluyendo)
cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:* 6.12 (incluyendo) 6.12.2 (excluyendo)