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

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

Gravedad CVSS v3.1:
MEDIA
Tipo:
CWE-190 Desbordamiento o ajuste de enteros
Fecha de publicación:
02/12/2024
Última modificación:
11/12/2024

Descripción

En el kernel de Linux, se ha resuelto la siguiente vulnerabilidad: mm/mremap: se corrige el envoltorio de direcciones en move_page_tables() En plataformas de 32 bits, es posible que la expresión `len + old_addr < old_end` sea un falso positivo si `len + old_addr` realiza un envoltorio. `old_addr` es el cursor en el rango antiguo hasta el cual se han movido las entradas de la tabla de páginas; por lo que si la operación tuvo éxito, `old_addr` es el *final* de la región antigua, y agregarle `len` puede realizar un envoltorio. El desbordamiento hace que mremap() crea erróneamente que se han copiado las PTE; la consecuencia es que mremap() se retira, pero no mueve las PTE de nuevo antes de que se desasigne el nuevo VMA, lo que provoca que se pierdan las páginas anónimas en la región. Básicamente, si el espacio de usuario intenta ejecutar mremap() en una región privada-anon y encuentra este error, mremap() devolverá un error y el contenido de la región privada-anon parecerá haber sido puesto a cero. La idea de esta comprobación es que `old_end - len` sea la dirección de inicio original, y escribir la comprobación de esa manera también facilita la lectura; por lo tanto, arregle la comprobación reorganizando la comparación en consecuencia. (Un workaround sería refactorizar esta función introduciendo una variable "orig_old_start" o algo similar). Probado en una máquina virtual con un núcleo X86 de 32 bits; sin el parche: ``` usuario@horn:~/big_mremap$ cat test.c #define _GNU_SOURCE #include #include #include #include #define ADDR1 ((void*)0x60000000) #define ADDR2 ((void*)0x10000000) #define SIZE 0x50000000uL int main(void) { unsigned char *p1 = mmap(ADDR1, SIZE, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE|MAP_FIXED_NOREPLACE, -1, 0); if (p1 == MAP_FAILED) err(1, "mmap 1"); carácter sin signo *p2 = mmap(ADDR2, SIZE, PROT_NONE, MAP_ANONYMOUS|MAP_PRIVATE|MAP_FIXED_NOREPLACE, -1, 0); si (p2 == MAP_FAILED) err(1, "mmap 2"); *p1 = 0x41; printf("el primer carácter es 0x%02hhx\n", *p1); carácter sin signo *p3 = mremap(p1, SIZE, SIZE, MREMAP_MAYMOVE|MREMAP_FIXED, p2); si (p3 == MAP_FAILED) { printf("mremap() falló; el primer carácter es 0x%02hhx\n", *p1); } de lo contrario { printf("mremap() tuvo éxito; el primer carácter es 0x%02hhx\n", *p3); } } usuario@horn:~/big_mremap$ gcc -static -o test test.c usuario@horn:~/big_mremap$ setarch -R ./test el primer carácter es 0x41 mremap() falló; el primer carácter es 0x00 ``` Con el parche: ``` usuario@horn:~/big_mremap$ setarch -R ./test el primer carácter es 0x41 mremap() tuvo éxito; el primer carácter es 0x41 ```

Productos y versiones vulnerables

CPE Desde Hasta
cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:* 6.7 (incluyendo) 6.11.10 (excluyendo)
cpe:2.3:o:linux:linux_kernel:6.12:rc1:*:*:*:*:*:*
cpe:2.3:o:linux:linux_kernel:6.12:rc2:*:*:*:*:*:*
cpe:2.3:o:linux:linux_kernel:6.12:rc3:*:*:*:*:*:*
cpe:2.3:o:linux:linux_kernel:6.12:rc4:*:*:*:*:*:*
cpe:2.3:o:linux:linux_kernel:6.12:rc5:*:*:*:*:*:*
cpe:2.3:o:linux:linux_kernel:6.12:rc6:*:*:*:*:*:*
cpe:2.3:o:linux:linux_kernel:6.12:rc7:*:*:*:*:*:*