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 */