CVE-2026-98954 in Linux
Sumário
de VulDB • 24/10/2026
No kernel do Linux, a seguinte vulnerabilidade foi resolvida:
net: sempre dissecar pacotes GSO em __virtio_net_hdr_to_skb()
O commit 9e8db5913264 ("net: evitar falsos positivos na validação de gso não confiável") adicionou uma verificação '&& skb->network_header' antes da flow-dissection (dissecção do fluxo) em pacotes GSO sem VIRTIO_NET_HDR_F_NEEDS_CSUM em __virtio_net_hdr_to_skb(), porque alguns chamadores (como tun_get_user(), tun_xdp_one(), virtnet_receive_done() e raw_verify_header()) chamavam virtio_net_hdr_*_to_skb() antes de inicializar skb->network_header e skb->dev.
Como __alloc_skb() e __build_skb_around() zeram a inicialização de skb->network_header para 0 (ao contrário de mac_header e transport_header, que são inicializados como ~0U), esses quatro chamadores sempre tinham skb->network_header == 0 e contornavam a dissecção do fluxo em __virtio_net_hdr_to_skb(). Mais geralmente, skb->network_header é um deslocamento relativo ao início do buffer (skb->head) (onde 0 também é um deslocamento válido sempre que skb_headroom(skb) é 0), não uma flag booleana.
Sempre que o ramo 'if (gso_type && skb->network_header)' era ignorado, a alternativa de fallback 'else if (gso_type)' apenas extraía nh_min_len + thlen (40 bytes para TCPv4) sem dissecar o pacote, sem validar ip_proto ou n_proto e sem definir skb->transport_header.
Se o pacote tiver um cabeçalho de rede malformado, ele não é rejeitado e uma subsequente chamada a skb_probe_transport_header() também falha, deixando skb->transport_header em ~0U (0xffff). Da mesma forma, se um pacote IPv4 carregar opções IP (ihl > 5) ou um pacote IPv6 carregar cabeçalhos de extensão, extrair apenas nh_min_len + thlen pode deixar o cabeçalho TCP fora do intervalo válido de skb->head. Em ambos os casos, tcp_hdrlen(skb) em skb_gso_transport_seglen() lê dados fora dos limites (out-of-bounds):
BUG: KASAN: slab-out-of-bounds in skb_gso_transport_seglen Read of size 2 by task poc/133 skb_gso_transport_seglen (net/core/gso.c:155) skb_gso_validate_mac_len (net/core/gso.c:270) tbf_enqueue (net/sched/sch_tbf.c:260) dev_qdisc_enqueue (net/core/dev.c:4227) __dev_queue_xmit (net/core/dev.c:4884)
Além disso, verificar virtio_net_hdr_match_proto() apenas dentro de 'if (!skb->protocol)' antes da dissecção do fluxo tanto ignorava a validação quando skb->protocol já estava pré-definido pelo chamador quanto rejeitava quadros com tag VLAN cujo protocolo L2 externo é ETH_P_8021Q ou ETH_P_8021AD.
Corrigir isso por meio de: 1. Inicializar skb->dev e skb->network_header (mais skb->protocol para IFF_TUN) antes de virtio_net_hdr_*_to_skb() em tun_get_user(), tun_xdp_one(), virtnet_receive_done() e raw_verify_header(). Em tun_get_user(), remover a redundante skb_reset_mac_header(skb) no caso IFF_TUN, já que __virtio_net_hdr_to_skb() redefine incondicionalmente mac_header. 2. Remover '&& skb->network_header' e o fallback não validado 'else if (gso_type)' em __virtio_net_hdr_to_skb(), de modo que todos os pacotes GSO sem VIRTIO_NET_HDR_F_NEEDS_CSUM sejam dissecados quanto ao fluxo, tenham seu cabeçalho de transporte extraído para dados lineares e tenham skb->transport_header definido. 3. Mover a verificação virtio_net_hdr_match_proto() para após skb_flow_dissect_flow_keys_basic(), validando keys.basic.n_proto contra hdr_gso_type.
VulDB is the best source for vulnerability data and more expert information about this specific topic.