CVE-2026-98096 PUBLISHED

ipv6: sr: restore network header before routing and forwarding

Assigner: Linux
Reserved: 25.09.2026 Published: 25.09.2026 Updated: 25.09.2026

In the Linux kernel, the following vulnerability has been resolved:

ipv6: sr: restore network header before routing and forwarding

ipv6_srh_rcv() runs with skb->data at the Segment Routing Header (SRH) while skb_network_header() points at the IPv6 header.

When segments_left > 0, ipv6_srh_rcv() previously restored the skb->data position by pushing sizeof(struct ipv6hdr), assuming the SRH immediately followed the fixed IPv6 header. If another extension header (such as a Hop-by-Hop options header) precedes the SRH, skb_network_offset() remained negative.

This led to two problems: 1. During ip6_route_input(), fib6_rules_early_flow_dissect() invokes __skb_flow_dissect() which passes the negative skb_network_offset() to flow dissection, breaking BPF and C flow dissector logic. 2. If forwarded via ip6_forward() or redirected via act_mirred, downstream handlers (like sch_fragment() or neighbour output) pass the negative offset as an unsigned length, triggering OOB memcpy or buffer overflows.

Fix this by pushing -skb_network_offset(skb) before routing, ensuring skb_network_offset(skb) is 0 for route lookup / flow dissection as well as downstream forwarding. On the loopback path, pull skb_transport_offset(skb) to restore skb->data to the SRH before looping back.

Metrics

CVSS Vector: CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:H/A:H
CVSS Score: 7.4

AV:N - The bad input is a routed IPv6 packet sent by a remote host: a Hop-by-Hop header followed by an SRH with segments_left>0. ipv6_srh_rcv() processes it on receive, and its fixed skb_push(sizeof(struct ipv6hdr)) leaves skb_network_offset() negative before ip6_route_input() and dst_input() forward the packet. AC:H - ipv6_srh_rcv() drops the packet unless seg6_enabled, which defaults to 0, is set both in devconf_all and on the ingress interface. The out-of-bounds memcpy in sch_frag_prepare_frag() also needs the admin to have set up tc act_ct with an MRU plus act_mirred on the forwarding path. The remote attacker cannot set up either of these. PR:N - No authentication is needed to send the packet. seg6_hmac_validate_skb() accepts SRHs that carry no HMAC TLV when seg6_require_hmac is at its default of 0, so an unauthenticated sender reaches the segments_left>0 branch. UI:N - No victim action is needed. The router processes the attacker's SRH packet in softirq receive context as soon as it arrives. S:U - The corruption stays inside the router's own kernel (skb metadata, then the per-CPU sch_frag_data_storage and memory after it). No VM, IOMMU or sandbox boundary is crossed. C:N - With the negative offset, the flow dissector and the neighbour output path read or write inside the skb head, and the bytes sch_frag reads out of bounds go into per-CPU storage. I found no path that sends kernel memory back to the attacker. I:H - sch_frag_prepare_frag() takes the negative skb_network_offset() as unsigned hlen and runs memcpy(&data->l2_data, skb->data, hlen). That writes packet bytes the attacker supplied past the per-CPU sch_frag_data_storage buffer, an out-of-bounds kernel write. A:H - The roughly 4 GB memcpy in sch_frag_prepare_frag() will fault and crash the router. On other paths the negative offset breaks flow dissection and garbles forwarded packets. The attacker can repeat this with each crafted packet.

Product Status

Vendor Linux
Product Linux
Versions Default: unaffected
  • affected from 1ababeba4a21f3dba3da3523c670b207fb2feb62 to ce4c8beedc19aceeab0e7bdc6f34394fb158c47c (excl.)
  • affected from 1ababeba4a21f3dba3da3523c670b207fb2feb62 to 97b21ef57dfabbff660a4672c9fef7edfb720f47 (excl.)
  • affected from 1ababeba4a21f3dba3da3523c670b207fb2feb62 to 3ad7dca5e03bd64c65983a19734337512fd75491 (excl.)
  • affected from 1ababeba4a21f3dba3da3523c670b207fb2feb62 to 975b5b067f525a1b1338c4a3bee1c46545801518 (excl.)
Vendor Linux
Product Linux
Versions Default: affected
  • Version 4.10 is affected
  • unaffected from 0 to 4.10 (excl.)
  • unaffected from 6.12.111 to 6.12.* (incl.)
  • unaffected from 6.18.53 to 6.18.* (incl.)
  • unaffected from 7.2.7 to 7.2.* (incl.)
  • unaffected from 7.3-rc2 to * (incl.)

References