linux/include
Paul Chaignon 6d7fcd8a7a bpf: Fix L4 csum update on IPv6 in CHECKSUM_COMPLETE
commit ead7f9b8de upstream.

In Cilium, we use bpf_csum_diff + bpf_l4_csum_replace to, among other
things, update the L4 checksum after reverse SNATing IPv6 packets. That
use case is however not currently supported and leads to invalid
skb->csum values in some cases. This patch adds support for IPv6 address
changes in bpf_l4_csum_update via a new flag.

When calling bpf_l4_csum_replace in Cilium, it ends up calling
inet_proto_csum_replace_by_diff:

    1:  void inet_proto_csum_replace_by_diff(__sum16 *sum, struct sk_buff *skb,
    2:                                       __wsum diff, bool pseudohdr)
    3:  {
    4:      if (skb->ip_summed != CHECKSUM_PARTIAL) {
    5:          csum_replace_by_diff(sum, diff);
    6:          if (skb->ip_summed == CHECKSUM_COMPLETE && pseudohdr)
    7:              skb->csum = ~csum_sub(diff, skb->csum);
    8:      } else if (pseudohdr) {
    9:          *sum = ~csum_fold(csum_add(diff, csum_unfold(*sum)));
    10:     }
    11: }

The bug happens when we're in the CHECKSUM_COMPLETE state. We've just
updated one of the IPv6 addresses. The helper now updates the L4 header
checksum on line 5. Next, it updates skb->csum on line 7. It shouldn't.

For an IPv6 packet, the updates of the IPv6 address and of the L4
checksum will cancel each other. The checksums are set such that
computing a checksum over the packet including its checksum will result
in a sum of 0. So the same is true here when we update the L4 checksum
on line 5. We'll update it as to cancel the previous IPv6 address
update. Hence skb->csum should remain untouched in this case.

The same bug doesn't affect IPv4 packets because, in that case, three
fields are updated: the IPv4 address, the IP checksum, and the L4
checksum. The change to the IPv4 address and one of the checksums still
cancel each other in skb->csum, but we're left with one checksum update
and should therefore update skb->csum accordingly. That's exactly what
inet_proto_csum_replace_by_diff does.

This special case for IPv6 L4 checksums is also described atop
inet_proto_csum_replace16, the function we should be using in this case.

This patch introduces a new bpf_l4_csum_replace flag, BPF_F_IPV6,
to indicate that we're updating the L4 checksum of an IPv6 packet. When
the flag is set, inet_proto_csum_replace_by_diff will skip the
skb->csum update.

Fixes: 7d672345ed ("bpf: add generic bpf_csum_diff helper")
Signed-off-by: Paul Chaignon <paul.chaignon@gmail.com>
Acked-by: Daniel Borkmann <daniel@iogearbox.net>
Link: https://patch.msgid.link/96a6bc3a443e6f0b21ff7b7834000e17fb549e05.1748509484.git.paul.chaignon@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
[ Note: Fixed conflict due to unrelated comment change. ]
Signed-off-by: Paul Chaignon <paul.chaignon@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
History 2025-06-27 11:05:38 +01:00
..
acpi ACPICA: Avoid sequence overread in call to strncmp() 2025-06-27 11:05:27 +01:00
asm-generic vmlinux.lds: Ensure that const vars with relocations are mapped R/O 2025-03-13 12:51:00 +01:00
clocksource x86/hyperv: Fix hv tsc page based sched_clock for hibernation 2025-01-09 13:28:42 +01:00
crypto crypto: af_alg - Disallow multiple in-flight AIO requests 2024-01-25 14:52:34 -08:00
drm drm/atomic: clarify the rules around drm_atomic_state->allow_modeset 2025-06-04 14:38:04 +02:00
dt-bindings dt-bindings: clock: qcom: Add GPLL9 support on gcc-sc8180x 2024-10-17 15:11:46 +02:00
keys KEYS: trusted: allow use of kernel RNG for key material 2023-10-19 23:05:33 +02:00
kunit kunit: fix kernel-doc warnings due to mismatched arg names 2021-10-06 17:54:07 -06:00
kvm KVM: arm64: vgic-v4: Make the doorbell request robust w.r.t preemption 2024-07-05 09:14:51 +02:00
linux mm: hugetlb: independent PMD page table shared count 2025-06-27 11:05:35 +01:00
math-emu math-emu: Fix fall-through warning 2021-07-13 13:57:44 -05:00
media media: v4l: Memset argument to 0 before calling get_mbus_config pad op 2025-06-04 14:38:02 +02:00
memory memory: renesas-rpc-if: Fix HF/OSPI data transfer in Manual Mode 2022-05-09 09:14:34 +02:00
misc ocxl: Update the Process Element Entry 2020-12-04 01:01:30 +11:00
net net: Fix checksum update for ILA adj-transport 2025-06-27 11:05:38 +01:00
pcmcia pcmcia: Replace zero-length array with flexible-array 2020-05-18 10:28:31 +02:00
ras Revert "mm/memory-failure.c: fix race with changing page compound again" 2022-07-12 16:35:17 +02:00
rdma RDMA/uverbs: Propagate errors from rdma_lookup_get_uobject() 2025-06-04 14:37:57 +02:00
scsi scsi: libsas: Add struct sas_tmf_task 2025-05-02 07:44:07 +02:00
soc soc: qcom: rpmh-rsc: Enhance check for VRM in-flight request 2024-06-16 13:39:55 +02:00
sound ALSA: pcm: Fix race of buffer access at PCM OSS layer 2025-06-04 14:38:06 +02:00
target scsi: target: Fix multiple LUN_RESET handling 2023-05-11 23:00:26 +09:00
trace erofs: remove unused trace event erofs_destroy_inode 2025-06-27 11:05:35 +01:00
uapi bpf: Fix L4 csum update on IPv6 in CHECKSUM_COMPLETE 2025-06-27 11:05:38 +01:00
vdso time64.h: Consolidated PSEC_PER_SEC definition 2021-04-06 16:32:17 -07:00
video video: of_display_timing.h: include errno.h 2022-07-12 16:35:10 +02:00
xen xen/mcelog: Add __nonstring annotations for unterminated strings 2025-05-02 07:43:53 +02:00