FAILED: patch "[PATCH] gso: fix udp gso fraglist segmentation after pull from" failed to apply to 5.10-stable tree
Subsystems (2)
[email protected]
maintainerThe patch below does not apply to the 5.10-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-5.10.y
git checkout FETCH_HEAD
git cherry-pick -x a1e40ac5b5e9077fe1f7ae0eb88034db0f9ae1ab
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2024100726-unlocking-handled-41bb@gregkh' --subject-prefix 'PATCH 5.10.y' HEAD^..
Possible dependencies:
a1e40ac5b5e9 ("gso: fix udp gso fraglist segmentation after pull from frag_list") 9840036786d9 ("gso: fix dodgy bit handling for GSO_UDP_L4") c3df39ac9b0e ("udp: ipv4: manipulate network header of NATed UDP GRO fraglist")
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From a1e40ac5b5e9077fe1f7ae0eb88034db0f9ae1ab Mon Sep 17 00:00:00 2001
From: Willem de Bruijn <[email protected]>
Date: Tue, 1 Oct 2024 13:17:46 -0400
Subject: [PATCH] gso: fix udp gso fraglist segmentation after pull from
frag_list
Detect gso fraglist skbs with corrupted geometry (see below) and pass these to skb_segment instead of skb_segment_list, as the first can segment them correctly.
Valid SKB_GSO_FRAGLIST skbs
- consist of two or more segments
- the head_skb holds the protocol headers plus first gso_size
- one or more frag_list skbs hold exactly one segment
- all but the last must be gso_size
Optional datapath hooks such as NAT and BPF (bpf_skb_pull_data) can modify these skbs, breaking these invariants.
In extreme cases they pull all data into skb linear. For UDP, this causes a NULL ptr deref in __udpv4_gso_segment_list_csum at udp_hdr(seg->next)->dest.
Detect invalid geometry due to pull, by checking head_skb size. Don't just drop, as this may blackhole a destination. Convert to be able to pass to regular skb_segment.
net/ipv4/udp_offload.c +20 -2
@@ -296,8 +296,26 @@ struct sk_buff *__udp_gso_segment(struct sk_buff *gso_skb,return NULL ; } -if (skb_shinfo (gso_skb)->gso_type &SKB_GSO_FRAGLIST ) -return __udp_gso_segment_list (gso_skb, features, is_ipv6); +if (skb_shinfo (gso_skb)->gso_type &SKB_GSO_FRAGLIST ) { +/* Detect modified geometry and pass those to skb_segment. */ +if (skb_pagelen (gso_skb) -sizeof (*uh) ==skb_shinfo (gso_skb)->gso_size) +return __udp_gso_segment_list (gso_skb, features, is_ipv6); + +/* Setup csum, as fraglist skips this in udp4_gro_receive. */ + gso_skb->csum_start =skb_transport_header (gso_skb) - gso_skb->head; + gso_skb->csum_offset = offsetof(struct udphdr , check); + gso_skb->ip_summed =CHECKSUM_PARTIAL ; + + uh =udp_hdr (gso_skb); +if (is_ipv6) + uh->check = ~udp_v6_check (gso_skb->len, + &ipv6_hdr (gso_skb)->saddr, + &ipv6_hdr (gso_skb)->daddr,0 ); +else + uh->check = ~udp_v4_check (gso_skb->len, +ip_hdr (gso_skb)->saddr, +ip_hdr (gso_skb)->daddr,0 ); + }skb_pull (gso_skb,sizeof (*uh));