this affected - among other things - tailscale's userspace wireguard implementation:
https://github.com/tailscale/tailscale/issues/19777 Signed-off-by: Fabian Grünbichler <[email protected]> --- ...ndling-checksum-in-__udp_gso_segment.patch | 71 +++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 patches/kernel/0053-udp-gso-Fix-handling-checksum-in-__udp_gso_segment.patch diff --git a/patches/kernel/0053-udp-gso-Fix-handling-checksum-in-__udp_gso_segment.patch b/patches/kernel/0053-udp-gso-Fix-handling-checksum-in-__udp_gso_segment.patch new file mode 100644 index 0000000..c5ab651 --- /dev/null +++ b/patches/kernel/0053-udp-gso-Fix-handling-checksum-in-__udp_gso_segment.patch @@ -0,0 +1,72 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Alice Mikityanska <[email protected]> +Date: Mon, 18 May 2026 09:22:49 +0300 +Subject: [PATCH] udp: gso: Fix handling checksum in __udp_gso_segment + +The cited commit started using msslen for uh->len, but still uses newlen +to adjust uh->check. Although the checksum is ignored in most cases due +to the hardware offload, __udp_gso_segment attempts to maintain the +correct one. Fix uh->check and adjust it by the right value. + +Additionally, after the fix, newlen becomes assigned and unused before +the loop. The code can be simplified a bit if mss adjustment is dropped, +so that newlen becomes equal to msslen before the loop, and msslen can +be also dropped, saving a few lines of code. + +This brings us back to one variable, drops an unneeded arithmetic for +mss, and fixes the UDP checksum. + +Fixes: b10b446ce7ad ("udp: gso: Use single MSS length in UDP header for GSO_PARTIAL") +Signed-off-by: Alice Mikityanska <[email protected]> +Reviewed-by: Willem de Bruijn <[email protected]> +Signed-off-by: Gal Pressman <[email protected]> +Link: https://patch.msgid.link/[email protected] +Signed-off-by: Jakub Kicinski <[email protected]> +(cherry picked from commit 5f17ae0f595aeb560155ce98edbe44d3eacc7e40) +Signed-off-by: Fabian Grünbichler <[email protected]> +--- + net/ipv4/udp_offload.c | 13 ++----------- + 1 file changed, 2 insertions(+), 11 deletions(-) + +diff --git a/net/ipv4/udp_offload.c b/net/ipv4/udp_offload.c +index 6b1654c1ad4ac0b7c611c338d75632f1974f842b..e831234326c414a1004609656ef2207d087d3346 100644 +--- a/net/ipv4/udp_offload.c ++++ b/net/ipv4/udp_offload.c +@@ -483,11 +483,11 @@ struct sk_buff *__udp_gso_segment(struct sk_buff *gso_skb, + struct sock *sk = gso_skb->sk; + unsigned int sum_truesize = 0; + struct sk_buff *segs, *seg; +- __be16 newlen, msslen; + struct udphdr *uh; + unsigned int mss; + bool copy_dtor; + __sum16 check; ++ __be16 newlen; + int ret = 0; + + mss = skb_shinfo(gso_skb)->gso_size; +@@ -556,15 +556,6 @@ struct sk_buff *__udp_gso_segment(struct sk_buff *gso_skb, + return segs; + } + +- msslen = htons(sizeof(*uh) + mss); +- +- /* GSO partial and frag_list segmentation only requires splitting +- * the frame into an MSS multiple and possibly a remainder, both +- * cases return a GSO skb. So update the mss now. +- */ +- if (skb_is_gso(segs)) +- mss *= skb_shinfo(segs)->gso_segs; +- + seg = segs; + uh = udp_hdr(seg); + +@@ -587,7 +578,7 @@ struct sk_buff *__udp_gso_segment(struct sk_buff *gso_skb, + if (!seg->next) + break; + +- uh->len = msslen; ++ uh->len = newlen; + uh->check = check; + + if (seg->ip_summed == CHECKSUM_PARTIAL) -- 2.47.3
