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

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

Gravedad CVSS v3.1:
ALTA
Tipo:
CWE-787 Escritura fuera de límites
Fecha de publicación:
12/07/2024
Última modificación:
25/09/2025

Descripción

En el kernel de Linux se ha resuelto la siguiente vulnerabilidad: bpf: Fix reg_set_min_max corrupción de fake_reg Juan informó que después de hacer algunos cambios al buzzer [0] e implementar una nueva estrategia de fuzzing guiada por cobertura, notaron lo siguiente en una de las sondas : [...] 13: (79) r6 = *(u64 *)(r0 +0) ; R0=map_value(ks=4,vs=8) R6_w=escalar() 14: (b7) r0 = 0 ; R0_w=0 15: (b4) w0 = -1 ; R0_w=0xffffffff 16: (74) w0 >>= 1 ; R0_w=0x7ffffffff 17: (5c) w6 &= w0 ; R0_w=0x7fffffff R6_w=escalar(smin=smin32=0,smax=umax=umax32=0x7fffffff,var_off=(0x0; 0x7fffffff)) 18: (44) w6 |= 2 ; R6_w=scalar(smin=umin=smin32=umin32=2,smax=umax=umax32=0x7fffffff,var_off=(0x2; 0x7ffffffd)) 19: (56) if w6 != 0x7ffffffd goto pc+1 VIOLACIÓN DE INVARIANTES REG (true_reg2) : violación de límites de rango u64=[0x7fffffff, 0x7ffffffd] s64=[0x7fffffff, 0x7ffffffd] u32=[0x7fffffff, 0x7ffffffd] s32=[0x7fffffff, 0x7ffffffd] var_off=(0x7fffffff, 0x0) INVARIANTES DEL REG (false_reg1): violación de los límites de rango u64 =[0x7fffffff, 0x7ffffffd] s64=[0x7fffffff, 0x7ffffffd] u32=[0x7fffffff, 0x7ffffffd] s32=[0x7fffffff, 0x7ffffffd] var_off=(0x7fffffff, 0x0) VIOLACIÓN DE INVARIANTES REG (false_reg2): st tnum no está sincronizado con los límites de rango u64 =[0x0, 0xffffffffffffffff] s64=[0x80000000000000000, 0x7ffffffffffffff] u32=[0x0, 0xffffffff] s32=[0x80000000, 0x7ffffff] var_off=(0x7ffffffff, 0x0) 19: 6_w=0x7fffffff 20: (95) salida del 19 al 21: R0=0x7fffffff R6=escalar(smin=umin=smin32=umin32=2,smax=umax=smax32=umax32=0x7ffffffe,var_off=(0x2; 0x7ffffffd)) R7=map_ptr(ks=4,vs=8) R9=ctx () R10=fp0 fp-24=map_ptr(ks=4,vs=8) fp-40=mmmmmmmm 21: R0=0x7fffffff R6=escalar(smin=umin=smin32=umin32=2,smax=umax=smax32=umax32 =0x7ffffffe,var_off=(0x2; 0x7ffffffd)) R7=map_ptr(ks=4,vs=8) R9=ctx() R10=fp0 fp-24=map_ptr(ks=4,vs=8) fp-40=mmmmmmmm 21: (14) w6 -= 2147483632; R6_w=scalar(smin=umin=umin32=2,smax=umax=0xffffffff,smin32=0x80000012,smax32=14,var_off=(0x2; 0xfffffffd)) 22: (76) si w6 s>= 0xe goto pc+1; R6_w=scalar(smin=umin=umin32=2,smax=umax=0xffffffff,smin32=0x80000012,smax32=13,var_off=(0x2; 0xfffffffd)) 23: (95) salida de 22 a 24: R0=0x7fffffff R6_w= 14 R7=map_ptr(ks=4,vs=8) R9=ctx() R10=fp0 fp-24=map_ptr(ks=4,vs=8) fp-40=mmmmmmmm 24: R0=0x7ffffffff R6_w=14 R7= map_ptr(ks=4,vs=8) R9=ctx() R10=fp0 fp-24=map_ptr(ks=4,vs=8) fp-40=mmmmmmmm 24: (14) w6 -= 14 ; R6_w=0 [...] Lo que se puede ver aquí es una violación de invariante de registro en la línea 19. Después del binario o en la línea 18, el verificador sabe que el bit 2 está establecido pero no sabe nada sobre el resto del contenido que fue cargado desde un valor de mapa, es decir, el rango es [2,0x7fffffff] con var_off=(0x2; 0x7ffffffd). Cuando en la línea 19 el verificador analiza la rama, divide los estados de registro en reg_set_min_max() en los registros de la rama verdadera (true_reg1, true_reg2) y los registros de la rama falsa (false_reg1, false_reg2). Dado que la prueba es w6! = 0x7ffffffd, src_reg es una constante conocida. Internamente, el verificador crea un registro "falso" inicializado como escalar al valor de 0x7ffffffd y luego lo pasa a reg_set_min_max(). Ahora, para la línea 19, es matemáticamente imposible tomar la rama falsa de este programa, sin embargo, el verificador la analiza. Es imposible porque el segundo bit de r6 se establecerá debido a la operación anterior o y la constante en la condición tiene ese bit sin configurar (hex(fd) == binario(1111 1101). Cuando el verificador analiza por primera vez el valor falso/caída -a través de la rama, calculará una intersección entre el var_off de r6 y la constante. Esto se debe a que el verificador crea un registro "falso" inicializado con el valor de la constante. El resultado de la intersección luego refina ambos registros en regs_refine_cond_op(): [...] t = tnum_intersect(tnum_subreg(reg1->var_off), tnum_subreg(reg2->var_off));

Productos y versiones vulnerables

CPE Desde Hasta
cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:* 6.8 (incluyendo) 6.9.7 (excluyendo)
cpe:2.3:o:linux:linux_kernel:6.10:rc1:*:*:*:*:*:*
cpe:2.3:o:linux:linux_kernel:6.10:rc2:*:*:*:*:*:*
cpe:2.3:o:linux:linux_kernel:6.10:rc3:*:*:*:*:*:*
cpe:2.3:o:linux:linux_kernel:6.10:rc4:*:*:*:*:*:*