CVE-2026-98954
NoneCVSS
—
EPSS
0.2%
Published
Oct 23, 2026
CISA due date
—
Cloudanix analysis
A bug in the Linux kernel's network code could let specially crafted packets cause crashes or memory errors when the system tries to handle certain virtual network traffic.
- Exploitation
- Local Privilege
- Attacker needs
- Low Privilege
- Complexity
- Moderate
- Impact
- Data Exposure
- Component
- OS kernel
- Class
- Memory Corruption
- Remediation
- Upgrade
- Effort
- Medium
- Patch risk
- Low
What it actually does
Out-of-bounds read in skb_gso_transport_seglen triggered by insufficient flow dissection and transport header validation for GSO packets without VIRTIO_NET_HDR_F_NEEDS_CSUM in __virtio_net_hdr_to_skb, allowing malformed network headers or IP options/extension headers to leave tcp_hdrlen accessing data outside skb linear region.
Why it matters to the business
Kernel memory corruption crashes or potential leaks during network packet processing on systems using virtio/tun interfaces and traffic control qdiscs, with low immediate operational risk due to recent publication and absence of known exploitation.
How an attack unfolds
An attacker sends crafted GSO packets via a tun device or virtio interface; the kernel path skips full dissection, fails to validate or pull the transport header, and later triggers the OOB read in skb_gso_validate_mac_len when enqueueing to a qdisc such as TBF.
How to fix it
Apply the upstream fix that removes the skb->network_header guard, eliminates the unvalidated fallback path, initializes dev/network_header/protocol before calling virtio_net_hdr_*_to_skb in tun/virtnet paths, and moves proto validation after flow dissection; rebuild and deploy updated kernel images.
How to confirm the fix worked
Confirm kernel source contains the described changes to __virtio_net_hdr_to_skb and caller sites; recompile with KASAN and exercise GSO paths with malformed headers to verify no slab-out-of-bounds; check for absence of the BUG string in crash logs.
Typical attack path
- Send malformed GSO packet through tun/virtio without VIRTIO_NET_HDR_F_NEEDS_CSUM
- Bypass flow dissection due to zero network_header or pre-set protocol
- skb_probe_transport_header fails leaving transport_header at ~0U
- skb_gso_transport_seglen performs out-of-bounds read during qdisc enqueue
- Trigger KASAN slab-out-of-bounds or kernel panic
How to detect it
Search kernel logs and crash dumps for KASAN slab-out-of-bounds reports naming skb_gso_transport_seglen, skb_gso_validate_mac_len, tbf_enqueue, or __dev_queue_xmit; correlate with recent tun or virtio receive activity.
- BUG: KASAN: slab-out-of-bounds in skb_gso_transport_seglen
- skb_gso_transport_seglen (net/core/gso.c:155)
- tbf_enqueue (net/sched/sch_tbf.c:260)
What your security team should do
- Prioritize kernel update on any system exposing virtio or tun interfaces to untrusted traffic
- Monitor for KASAN reports or crashes referencing skb_gso_transport_seglen and sch_tbf
- Apply defense-in-depth by restricting untrusted GSO traffic and enabling strict qdisc validation where possible
The record
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.
Affected packages
| Ecosystem | Package | Introduced | Fixed |
|---|