[PATCH net 0/3] xsk, ipv6: validate user-supplied checksum offsets

From: Nick Simpson

Date: Wed Oct 21 2026 - 14:05:00 EST


In copy mode, AF_XDP turns the csum_start/csum_offset of
XDP_TXMD_FLAGS_CHECKSUM into a CHECKSUM_PARTIAL skb after checking only
that the checksum fits in the frame. Sent over a veth into a namespace
that forwards IPv6 with nf_defrag_ipv6, the checksum is then completed
after the forward hook has accepted the packet, at an offset in the IPv6
header chosen by the sender; with csum_start before the network header,
skb_checksum_help() warns. Patch 1 has the details and the trace.

This is the AF_XDP counterpart of the virtio_net_hdr issue fixed for
IPv4 by commit 6785011f8b16 ("ipv4: validate checksum_start before
completing checksum") and addressed by the "more virtio-net csum
hardening" series [1], which does not cover AF_XDP.

Patch 1 is the fix: CHECKSUM_PARTIAL is kept only for the TCP or UDP
checksum of an unfragmented IPv4/IPv6 packet, not IP-in-IP or GRE
encapsulated, on an Ethernet device; other requests are completed in
software at the sender. Frames without a linear part
(IFF_TX_SKB_NO_LINEAR) are left unchanged. One visible change: a request
on a frame that is itself an IP fragment is completed over that fragment
alone, as a device would, so the reassembled datagram no longer has a
valid transport checksum and conntrack marks it invalid; before, if
every fragment carried a request, it stayed CHECKSUM_PARTIAL and was
completed on refragmentation.

Patch 2 documents the new behaviour in xsk-tx-metadata.rst. It is kept
separate so that patch 1 stays within the stable size limit.

Patch 3 is defence in depth: the IPv6 counterpart of
ip_check_csum_start() on the two IPv6 fragmentation paths,
ip6_fragment() and br_ip6_fragment(). For IPv4 the check is also
called from nfnetlink_queue, xt_CHECKSUM and xfrm_output; their IPv6
counterparts are not changed here, and a check at reassembly time would
cover more. Patch 1 does not depend on it, and it is not marked for
stable.

Testing, on netdev/net 82e31923c055, arm64 under QEMU:
- reproducer (fragmented IPv6/UDP over veth into a namespace with an
nftables forward rule on "ip6 saddr", csum_start/csum_offset 22/22;
an unfragmented packet with 14/22 and TX checksum offload off on the
egress veth; csum_start 20): without the series the source address is
rewritten after the forward hook accepted the packet, and
skb_checksum_help() warns. With the series, or with patch 1 alone,
nothing is rewritten after the accept and there is no warning; with
patch 3 alone the fragmented cases are not sent on (ip6_fragment()
drops them) and the unfragmented case is not covered
- a legitimate IPv6/UDP request (csum_start at the UDP header, offset 6)
is still sent CHECKSUM_PARTIAL and delivered to a UDP socket
- which requests stay CHECKSUM_PARTIAL, observed on the veth peer with
PACKET_AUXDATA: IPv4/UDP, IPv4/TCP, IPv4 with options, IPv6/UDP, IPv6
with a hop-by-hop header and VLAN-tagged IPv6/UDP stay partial; a
wrong csum_offset, csum_start in the IP header, IPv4 and IPv6 first
fragments, IPIP and ICMP are completed in software with the correct
value. Without the series all of them stay partial.
- tools/testing/selftests/bpf: test_progs -t xdp_metadata passes with
and without the series
- on a kernel with KASAN, PROVE_LOCKING, PROVE_RCU,
DEBUG_ATOMIC_SLEEP, DEBUG_PREEMPT, DEBUG_PAGEALLOC and
DEBUG_OBJECTS_RCU_HEAD, no warnings: with the series, the
reproducer, the classification test and the selftest; without it,
the selftest and the legitimate request
- W=1 and sparse (C=1) on the changed files in allmodconfig builds for
arm64, x86_64, i386 and s390: no warnings, with or without the
series; checkstack unchanged; arm64 allnoconfig and an INET=n build
with XDP_SOCKETS=y build; checkpatch --strict is clean; htmldocs for
networking builds without warnings for xsk-tx-metadata.rst
- arm64 allmodconfig and allyesconfig with W=1 build, with no warning
in the changed files (CONFIG_WERROR and the DRM *_WERROR options
were turned off: with gcc 15, existing W=1 warnings in unrelated
files otherwise stop the build)
Not tested: IFF_TX_SKB_NO_LINEAR (virtio_net) devices, multi-buffer
frames, an attached BPF flow dissector, a sender in an unprivileged
user namespace, x86 at runtime, and patch 3 with tun/tap or packet
socket sources of CHECKSUM_PARTIAL (the same header rewrite through a
tap device was reproduced on mainline earlier, but not re-run with
patch 3).

The issue was found, and the patches and tests prepared, with LLM
assistance (see the Assisted-by tags). I have reviewed the changes and
the test results. A reproducer is available on request.

[1] https://lore.kernel.org/r/cover.1792411304.git.mst@xxxxxxxxxx

Nick Simpson (3):
xsk: validate checksum offload requests in copy mode
xsk: document checksum offload handling in copy mode
ipv6: validate checksum_start before fragmenting

Documentation/networking/xsk-tx-metadata.rst | 7 ++-
include/net/ipv6.h | 12 ++++
net/ipv6/ip6_output.c | 10 +++-
net/ipv6/netfilter.c | 10 +++-
net/xdp/xsk.c | 58 ++++++++++++++++++++
5 files changed, 90 insertions(+), 7 deletions(-)


base-commit: 82e31923c0553fdbfcddcd910ca07952880ca9b9
--
2.53.0