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

Vulnerabilidad en kernel de Linux (CVE-2022-48644)

Gravedad CVSS v3.1:
MEDIA
Tipo:
CWE-476 Desreferencia a puntero nulo (NULL)
Fecha de publicación:
28/04/2024
Última modificación:
19/09/2025

Descripción

En el kernel de Linux, se ha resuelto la siguiente vulnerabilidad: net/sched: taprio: evita deshabilitar la descarga cuando nunca estuvo habilitada. En una decisión de diseño de API increíblemente extraña, se llama a qdisc->destroy() incluso si qdisc->init() nunca tuvo éxito, no exclusivamente desde el commit 87b60cfacf9f ("net_sched: corregir recuperación de error en la creación de qdisc"), sino aparentemente también antes (en el caso de qdisc_create_dflt()). La qdisc taprio no reconoce completamente esto cuando intenta una descarga completa, porque comienza con q->flags = TAPRIO_FLAGS_INVALID en taprio_init(), luego reemplaza q->flags con TCA_TAPRIO_ATTR_FLAGS analizado desde netlink (en taprio_change(), cola llamada de taprio_init()). Pero en taprio_destroy(), llamamos a taprio_disable_offload(), y esto determina qué hacer en función de FULL_OFFLOAD_IS_ENABLED(q->flags). Pero al observar la implementación de FULL_OFFLOAD_IS_ENABLED() (una verificación bit a bit del bit 1 en q->flags), no es válido llamar a esta macro en q->flags cuando contiene TAPRIO_FLAGS_INVALID, porque está configurado en U32_MAX y, por lo tanto, FULL_OFFLOAD_IS_ENABLED () devolverá verdadero en un conjunto de indicadores no válido. Como resultado, es posible bloquear el kernel si el espacio del usuario fuerza un error entre configurar q->flags = TAPRIO_FLAGS_INVALID y la llamada de taprio_enable_offload(). Esto se debe a que los conductores no esperan que se deshabilite la descarga cuando nunca estuvo habilitada. El error que forzamos aquí es adjuntar taprio como una qdisc no raíz, sino como hija de una qdisc raíz mqprio: $ tc qdisc add dev swp0 root handle 1: \ mqprio num_tc 8 map 0 1 2 3 4 5 6 7 \ colas 1@0 1@1 1@2 1@3 1@4 1@5 1@6 1@7 hw 0 $ tc qdisc reemplazar dev swp0 padre 1:1 \ taprio num_tc 8 map 0 1 2 3 4 5 6 7 \ colas 1@0 1@1 1@2 1@3 1@4 1@5 1@6 1@7 tiempo base 0 \ entrada programada S 0x7f 990000 entrada programada S 0x80 100000 \ banderas 0x0 clockid CLOCK_TAI No se puede para manejar la solicitud de paginación del kernel en la dirección virtual ffffffffffffffff8 [ffffffffffffffff8] pgd=0000000000000000, p4d=0000000000000000 Error interno: Vaya: 96000004 [#1] Seguimiento de llamada SMP PREEMPT: taprio_dump+0x27c/0x310 vsc9959_port _setup_tc+0x1f4/0x460 felix_port_setup_tc+0x24/0x3c dsa_slave_setup_tc +0x54/0x27c taprio_disable_offload.isra.0+0x58/0xe0 taprio_destroy+0x80/0x104 qdisc_create+0x240/0x470 tc_modify_qdisc+0x1fc/0x6b0 rtnetlink_rcv_msg+0x12c/0x390 x5c/0x130 rtnetlink_rcv+0x1c/0x2c Solucione este problema manteniendo un registro de operaciones que hicimos, y deshacer la descarga solo si realmente lo hicimos. Agregué "bool descargado" dentro de un hueco de 4 bytes entre "int clockid" y "atomic64_t picos_per_byte". Ahora la primera línea de caché se ve así: $ pahole -C taprio_sched net/sched/sch_taprio.o struct taprio_sched { struct Qdisc * * qdiscs; /* 0 8 */ struct Qdisc * raíz; /* 8 8 */ u32 banderas; /* 16 4 */ enum tk_offsets tk_offset; /* 20 4 */ int relojid; /* 24 4 */ bool descargado; /* 28 1 */ /* XXX agujero de 3 bytes, intenta empaquetar */ atomic64_t picos_per_byte; /* 32 0 */ /* XXX agujero de 8 bytes, intenta empaquetar */ spinlock_t current_entry_lock; /* 40 0 */ /* XXX agujero de 8 bytes, intenta empaquetar */ struct sched_entry * current_entry; /* 48 8 */ struct sched_gate_list * oper_sched; /* 56 8 */ /* --- límite de línea de caché 1 (64 bytes) --- */

Productos y versiones vulnerables

CPE Desde Hasta
cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:* 5.4 (incluyendo) 5.4.215 (excluyendo)
cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:* 5.5 (incluyendo) 5.10.146 (excluyendo)
cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:* 5.11 (incluyendo) 5.15.71 (excluyendo)
cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:* 5.16 (incluyendo) 5.19.12 (excluyendo)
cpe:2.3:o:linux:linux_kernel:6.0:rc1:*:*:*:*:*:*
cpe:2.3:o:linux:linux_kernel:6.0:rc2:*:*:*:*:*:*
cpe:2.3:o:linux:linux_kernel:6.0:rc3:*:*:*:*:*:*
cpe:2.3:o:linux:linux_kernel:6.0:rc4:*:*:*:*:*:*
cpe:2.3:o:linux:linux_kernel:6.0:rc5:*:*:*:*:*:*
cpe:2.3:o:linux:linux_kernel:6.0:rc6:*:*:*:*:*:*