
From: Yan Zhai <yan@cloudflare.com> mainline inclusion from mainline-v6.5-rc3 commit 9840036786d90cea11a90d1f30b6dc003b34ee67 category: bugfix bugzilla: https://gitee.com/src-openeuler/kernel/issues/IAKQ33 CVE: CVE-2024-43817 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i... -------------------------------- Commit 1fd54773c267 ("udp: allow header check for dodgy GSO_UDP_L4 packets.") checks DODGY bit for UDP, but for packets that can be fed directly to the device after gso_segs reset, it actually falls through to fragmentation: https://lore.kernel.org/all/CAJPywTKDdjtwkLVUW6LRA2FU912qcDmQOQGt2WaDo28KzYD... This change restores the expected behavior of GSO_UDP_L4 packets. Fixes: 1fd54773c267 ("udp: allow header check for dodgy GSO_UDP_L4 packets.") Suggested-by: Willem de Bruijn <willemdebruijn.kernel@gmail.com> Signed-off-by: Yan Zhai <yan@cloudflare.com> Reviewed-by: Willem de Bruijn <willemb@google.com> Acked-by: Jason Wang <jasowang@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net> Conflicts: net/ipv4/udp_offload.c net/ipv6/udp_offload.c [conflict with 5957b013e3c3 ("[Backport] gso: fix udp gso fraglist segmentation after pull from frag_list"), 1fd54773c267 ("udp: allow header check for dodgy GSO_UDP_L4 packets.") not merged] Signed-off-by: Zhang Changzhong <zhangchangzhong@huawei.com> --- net/ipv4/udp_offload.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/net/ipv4/udp_offload.c b/net/ipv4/udp_offload.c index d6ab7af..6120df4 100644 --- a/net/ipv4/udp_offload.c +++ b/net/ipv4/udp_offload.c @@ -270,6 +270,17 @@ struct sk_buff *__udp_gso_segment(struct sk_buff *gso_skb, __sum16 check; __be16 newlen; + mss = skb_shinfo(gso_skb)->gso_size; + if (gso_skb->len <= sizeof(*uh) + mss) + return ERR_PTR(-EINVAL); + + if (skb_gso_ok(gso_skb, features | NETIF_F_GSO_ROBUST)) { + /* Packet is from an untrusted source, reset gso_segs. */ + skb_shinfo(gso_skb)->gso_segs = DIV_ROUND_UP(gso_skb->len - sizeof(*uh), + mss); + return NULL; + } + 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) @@ -291,10 +302,6 @@ struct sk_buff *__udp_gso_segment(struct sk_buff *gso_skb, ip_hdr(gso_skb)->daddr, 0); } - mss = skb_shinfo(gso_skb)->gso_size; - if (gso_skb->len <= sizeof(*uh) + mss) - return ERR_PTR(-EINVAL); - skb_pull(gso_skb, sizeof(*uh)); /* clear destructor to avoid skb_segment assigning it to tail */ -- 2.9.5