Hello Security Team,
The IPv4 part of this was fixed some time ago in commit 6785011f8b16
("ipv4: validate checksum_start before completing checksum"): a packet
whose virtio_net_hdr csum metadata points its checksum start inside the
IP header makes skb_checksum_help() (the deferred csum completion)
rewrite the header the stack has already validated (fixed checksum
offset-width write at csum_start + csum_offset). The IPv6 paths were
not covered, and they still are not: a 2-patch series mirroring that
commit for IPv4->IPv6, including its remaining not-yet-IPv6-guarded
sinks, is reproduced below and attached as patches/0001 and 0002.
Why this is reachable today
---------------------------
include/linux/virtio_net.h's __virtio_net_hdr_to_skb() only enforces
skb_transport_offset() >= sizeof(struct iphdr) (nh_min_len) for
NEEDS_CSUM -- i.e., for IPv6 packets any csum_start in
[20, sizeof(struct ipv6hdr)) passes admission, sitting inside the fixed
40-byte IPv6 header that the stack has just validated. With TUN (tun
device using IFF_VNET_HDR) or AF_PACKET csum -- the same admission the
virtio/vhost setup uses for guests, and reachable unprivileged --
skb_checksum_help() can then write an attacker-chosen 16-bit value into
the outgoing IPv6 header of a forwarded frame. The write value is
csum_fold over an attacker-built payload and is fully deterministic
(pre-computed in userspace in the reproducer).
Sinks on master (line numbers from c03c1a14507d, "Linux 7.3", checked
2026-10-19):
net/ipv6/ip6_output.c:945 ip6_fragment() unguarded
net/ipv6/netfilter.c:147 br_ip6_fragment() unguarded
(reachable by bridge
refrag in
net/bridge/netfilter/
nf_conntrack_bridge.c:358 and
by Open vSwitch
ovs_fragment()'s IPv6 branch
which calls ip6_fragment())
net/netfilter/xt_CHECKSUM.c:30 checksum_tg() guard is
NFPROTO_IPV4-only, IPv6 falls
through; helper return also
ignored (patch 2)
net/netfilter/nfnetlink_queue.c:678 nf_queue_checksum_help()
checked for ETH_P_IP only,
IPv6 falls through
net/xfrm/xfrm_output.c:826 xfrm_output() same
ETH_P_IP-only gate
The ip6_fragment() side-drop is the direct sibling of the IPv4
ip_do_fragment() check that commit added; xt_CHECKSUM's IPv6 case is
reachable for a v6-only netns since ingress-side -- for instance via
`ip6tables -t mangle POSTROUTING -j CHECKSUM --checksum-fill`, which
finalizes the partial checksum at the sink.
Bug report and evidence
-----------------------
Dear attachments, all under ipv6-csum-start-submission.zip:
- report.txt: detailed writeup with the full admission-gap audit and
the sink table above, impact, and the reproducer output below;
- patches/0000-cover-letter.txt, 0001, 0002: the proposed git-series
(2 patches, drafted against c03c1a14507d);
- poc/poc_ipv6_csum_start.c: a single-file reproducer (as PID 1 in an
initramfs VM it needs no external tools -- netns + veth + tun via
raw netlink, TUN,VNET_HDR, ip6tables via the bundled
ip6tables-legacy, and a packet-over-TUN/AF_PACKET sender); csum
geometry (csum_start=24 = inside the IPv6 fixed header) with a
csum_start=64 falsification control variant;
- poc/build_vm.sh, logs/run-*.log: the two runs, verbatim, from a
QEMU initramfs VM against a real 6.12.38 kernel (no KVM required):
-- control (csum_start=64, past the header) --
[*] emitted frame #1 len=1478 daddr intact: fd:00:00:0c hop_limit=63
[+] control OK: 1 frames, headers intact
Ip6OutForwDatagrams 1
-- evil (csum_start=24, inside the header) --
[!] MUTATED OUTPUT FRAME #1: daddr bits now 4a:32:00:0c
(wire-validated value was fd00:c::= 0c:0c:0c:0c); written
16-bit=4a32 len=1478
[+] BUG CONFIRMED: csum_start=24 < sizeof(struct ipv6hdr)=40:
deferred skb_checksum_help() rewrote the previously VALIDATED
IPv6 header in an EMITTED packet.
Ip6OutForwDatagrams 1
The 4a:32 written into the emitted frame's destination address is the
folded checksum the reproducer predicted before sending; the control
run shows the same code path intact, ruling out ordinary corruption.
Likewise, no CVE for this IPv6 path is known to me as of 2026-10-19;
there is no harm in restoring parity with the IPv4 fix, and following
up with [email protected] after this lands, if you agree.
The proposed fix mirrors commit 6785011f8b16 one sink at a time; the
input-side admission is still the "more work forthcoming" item from
that commit's changelog (its IPv4 work precedes it), and this series
does not attempt to change it -- it only documents that gap in
report.txt for whoever picks it up.
Happy to rework the split (netfilter-only first, or one patch per
sink), or to paste the patches inline if inline is preferred over the
attachment. Testing status: the reproducer was exercised end to end
against the 6.12.38 kernel named above; patches are hand-crafted and
not yet boot-tested as a series.
Let me know if it is eligible for CVE
Thanks,
PRNJL
_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev