Re: [PATCH net 3/3] ipv6: validate checksum_start before fragmenting
From: Eric Dumazet
Date: Wed Oct 21 2026 - 14:23:26 EST
Le mer. 21 oct. 2026 à 20:05, Nick Simpson <nick.simo@xxxxxxxxx> a écrit :
>
> ip6_fragment() and br_ip6_fragment() complete CHECKSUM_PARTIAL skbs with
> skb_checksum_help() without checking where csum_start points. After
> reassembly by nf_defrag_ipv6, the IPv6 header has moved forward by the
> 8 bytes of the fragment header while csum_start has not, so a
> CHECKSUM_PARTIAL skb from an untrusted source (tun/tap or packet sockets
> with a virtio_net_hdr, or AF_XDP TX metadata) can have csum_start inside
> the IPv6 header, and the checksum is then written into a header that the
> forward hook has already accepted. When csum_start lies before the
> network header, skb_checksum_help() warns.
>
> Add the IPv6 counterpart of ip_check_csum_start() from
> commit 6785011f8b16 ("ipv4: validate checksum_start before completing
> checksum") to the two IPv6 fragmentation paths: refuse to complete a
> checksum that starts inside the unfragmentable part of the packet (the
> IPv6 header and the extension headers before the fragment header) and
> drop the packet instead.
>
> For IPv4, ip_check_csum_start() is also called from nfnetlink_queue,
> xt_CHECKSUM and xfrm_output; their IPv6 counterparts are not changed
> here. A reassembled packet that is not fragmented again, such as an
> atomic fragment, and an unfragmented packet whose checksum is completed
> at egress are not covered either; those have to be handled where the
> CHECKSUM_PARTIAL skb is created, or by a check at reassembly time.
Then let's do that, instead of adding checks to every consumer.
A CHECKSUM_PARTIAL fragment is meaningless: the L4 checksum covers the
whole datagram, and our own stack completes it before fragmenting
(ip_do_fragment(), ip6_fragment()). Only untrusted injectors produce
them. Yet inet_frag_reasm_finish() keeps the reassembled skb
CHECKSUM_PARTIAL when all fragments are.
Downgrading CHECKSUM_PARTIAL to CHECKSUM_NONE in inet_frag_reasm_finish()
covers IPv4, IPv6, nf_defrag_ipv6 (and the bridge path) in one place;
the bogus L4 checksum is then verified and the packet dropped.
Also, reassembly does not move the L4 bytes, so a valid csum_start stays
valid; the "header moved without adjusting csum_start" framing is not
the bug.
Finally, this patch is described as defence in depth and not for
stable, but carries three Fixes: tags. Please drop it.
Nacked-by: Eric Dumazet <edumazet@xxxxxxxxxx>
I am so tired of these LLM patches working around the issues instead
of fixing the root causes.