Vulnerabilidad en kernel de Linux (CVE-2025-37821)
Gravedad:
Pendiente de análisis
Tipo:
No Disponible / Otro tipo
Fecha de publicación:
08/05/2025
Última modificación:
18/05/2025
Descripción
En el kernel de Linux, se ha resuelto la siguiente vulnerabilidad: sched/eevdf: Se soluciona que se->slice se establezca en U64_MAX y el bloqueo resultante Hay una ruta de código en dequeue_entities() que puede establecer el slice de un sched_entity en U64_MAX, lo que a veces resulta en un bloqueo. El caso ofensivo es cuando se llama a dequeue_entities() para sacar de la cola una entidad de grupo retrasada y luego se retrasa la salida de la cola del padre de la entidad. En ese caso: 1. En el bloque if (entity_is_task(se)) else al comienzo de dequeue_entities(), slice se establece en cfs_rq_min_slice(group_cfs_rq(se)). Si la entidad se retrasó, entonces no tiene tareas en cola, por lo que cfs_rq_min_slice() devuelve U64_MAX. 2. El primer bucle for_each_sched_entity() saca de la cola la entidad. 3. Si la entidad era la única hija de su padre, la siguiente iteración intenta sacar de la cola al padre. 4. Si es necesario retrasar la salida de la cola del padre, se interrumpe desde el primer bucle for_each_sched_entity() _sin actualizar la porción_. 5. El segundo bucle for_each_sched_entity() establece la porción -> del padre en la porción guardada, que sigue siendo U64_MAX. Esto altera los cálculos posteriores con resultados potencialmente catastróficos. Una manifestación que vimos en producción fue: 6. En update_entity_lag(), se->slice se usa para calcular el límite, que termina como un número negativo enorme. 7. limit se usa en se->vlag = clamp(vlag, -limit, limit). Como limit es negativo, vlag > limit, por lo que se->vlag se establece en el mismo número negativo enorme. 8. En place_entity(), se->vlag se escala, lo que se desborda y da como resultado otro número enorme (positivo o negativo). 9. El retardo ajustado se resta de se->vruntime, lo que aumenta o disminuye se->vruntime considerablemente. 10. pick_eevdf() llama a entity_eligible()/vruntime_eligible(), que devuelve incorrectamente "false" debido a la gran distancia entre el vruntime y los demás vruntimes de la cola, lo que provoca un desbordamiento del cálculo de carga (vruntime - cfs_rq->min_vruntime) *. 11. Nada parece ser elegible, por lo que pick_eevdf() devuelve NULL. 12. pick_next_entity() intenta desreferenciar el valor de retorno de pick_eevdf() y se bloquea. Volcar los estados de cfs_rq desde los volcados de núcleo con drgn mostró rangos de tiempo de ejecución virtuales enormes y valores de vlag falsos, y también rastreé que se->slice se configuraba en U64_MAX en sistemas en vivo (lo cual solía ser "benigno", ya que el resto de la cola de ejecución debía estar en un estado específico para fallar). Corríjalo en dequeue_entities() configurando siempre slice desde el primer cfs_rq no vacío.