CVE-2026-98954 in Linux
Summary
by MITRE • 10/23/2026
In the Linux kernel, the following vulnerability has been resolved:
net: always dissect GSO packets in __virtio_net_hdr_to_skb()
Commit 9e8db5913264 ("net: avoid false positives in untrusted gso validation") added a '&& skb->network_header' check before flow-dissecting GSO packets without VIRTIO_NET_HDR_F_NEEDS_CSUM in __virtio_net_hdr_to_skb(), because some callers (such as tun_get_user(), tun_xdp_one(), virtnet_receive_done(), and raw_verify_header()) called virtio_net_hdr_*_to_skb() before initializing skb->network_header and skb->dev.
Because __alloc_skb() and __build_skb_around() zero-initialize skb->network_header to 0 (unlike mac_header and transport_header which are initialized to ~0U), those four callers always had skb->network_header == 0 and bypassed flow dissection in __virtio_net_hdr_to_skb(). More generally, skb->network_header is an offset from skb->head (where 0 is also a valid offset whenever skb_headroom(skb) is 0), not a boolean flag.
Whenever the 'if (gso_type && skb->network_header)' branch was skipped, the fallback 'else if (gso_type)' only pulled nh_min_len + thlen (40 bytes for TCPv4) without dissecting the packet, without validating ip_proto or n_proto, and without setting skb->transport_header.
If the packet has a malformed network header, it is not rejected and a subsequent skb_probe_transport_header() also fails, leaving skb->transport_header at ~0U (0xffff). Similarly, if an IPv4 packet carries IP options (ihl > 5) or an IPv6 packet carries extension headers, pulling only nh_min_len + thlen can leave the TCP header outside skb->head. In both cases, tcp_hdrlen(skb) in skb_gso_transport_seglen() reads 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)
In addition, checking virtio_net_hdr_match_proto() only inside 'if (!skb->protocol)' before flow dissection both skipped validation when skb->protocol was pre-set by the caller and rejected VLAN-tagged frames whose outer L2 protocol is ETH_P_8021Q or ETH_P_8021AD.
Fix this by: 1. Initializing skb->dev and skb->network_header (plus skb->protocol for IFF_TUN) before virtio_net_hdr_*_to_skb() in tun_get_user(), tun_xdp_one(), virtnet_receive_done(), and raw_verify_header(). In tun_get_user(), drop the redundant skb_reset_mac_header(skb) in the IFF_TUN case since __virtio_net_hdr_to_skb() unconditionally resets mac_header. 2. Removing '&& skb->network_header' and the unvalidated 'else if (gso_type)' fallback in __virtio_net_hdr_to_skb() so all GSO packets without VIRTIO_NET_HDR_F_NEEDS_CSUM are flow-dissected, have their transport header pulled into linear data, and have skb->transport_header set. 3. Moving the virtio_net_hdr_match_proto() check to after skb_flow_dissect_flow_keys_basic(), validating keys.basic.n_proto against hdr_gso_type.
If you want to get the best quality for vulnerability data then you always have to consider VulDB.
Analysis
by VulDB Data Team • 10/23/2026
A critical out-of-bounds read vulnerability exists within the Linux kernel networking stack, specifically in the handling of Generic Segmentation Offload packets processed by the virtio-net driver and related interfaces such as TUN/TAP. The flaw originates from an incorrect conditional check introduced to prevent false positives during untrusted GSO validation. This change added a dependency on the skb->network_header field being non-zero before initiating flow dissection for certain packet types. However, because kernel memory allocation functions like __alloc_skb zero-initialize network offsets while leaving other headers uninitialized with high values, callers that invoke virtio_net_hdr_to_skb prior to fully initializing these fields inadvertently trigger this bypass condition. Consequently, the code path skips essential validation and parsing steps required to safely process incoming network segments.
When flow dissection is skipped due to this logic error, the kernel falls back to a simplified header pulling mechanism that extracts only a fixed minimum length of headers based on protocol assumptions rather than actual packet content. This approach fails to validate critical fields such as ip_proto or n_proto and does not set the skb->transport_header pointer correctly. If an incoming packet contains malformed network headers, IPv4 options with an identification head length greater than five, or IPv6 extension headers that extend beyond the minimum expected size, the fixed-length pull operation may leave the TCP header data outside the linear portion of the socket buffer memory. This misalignment creates a scenario where subsequent functions attempting to calculate transport segment lengths read from invalid memory locations.
The operational impact is severe, manifesting as kernel panics or potential information disclosure through slab-out-of-bounds reads detected by Kernel Address Sanitizer during normal traffic processing. The vulnerability affects components involved in queuing and transmitting packets, including the token bucket filter scheduler and device queue disciplines. Attackers capable of injecting crafted network frames into virtualized environments using virtio-net interfaces can exploit this condition to destabilize the host system or potentially leak kernel memory contents. This issue highlights a fundamental misunderstanding of how header offsets function within socket buffers, treating an offset value as a boolean flag rather than recognizing that zero is a valid and common offset when headroom is absent.
To remediate this vulnerability, developers have implemented several structural changes to ensure proper initialization and validation sequences. First, callers such as tun_get_user, tun_xdp_one, virtnet_receive_done, and raw_verify_header are now required to initialize skb->dev and skb->network_header before invoking header conversion functions. This ensures that the conditional logic within __virtio_net_hdr_to_skb behaves correctly regardless of prior state. Second, the problematic check relying on network_header presence has been removed from the GSO processing path, ensuring all relevant packets undergo full flow dissection. Third, the validation of protocol types against virtio headers is now performed after basic flow keys are extracted, allowing for accurate matching even when protocols are pre-set or VLAN tags are present.
This vulnerability aligns with CWE-125 Out-of-bounds Read and CWE-94 Improper Control of Generation of Code Command Injection in the context of logic flaws leading to memory corruption. From a threat modeling perspective using MITRE ATT&CK, this flaw relates to techniques involving exploitation for denial of service or potential privilege escalation through kernel memory exposure. The fix emphasizes the importance of strict initialization order and comprehensive header validation in network stack processing paths to prevent attackers from leveraging malformed packets against virtualized infrastructure components.