Commit ac6d285d authored by Yan Zhai's avatar Yan Zhai Committed by Zhang Changzhong
Browse files

gso: fix dodgy bit handling for GSO_UDP_L4

mainline inclusion
from mainline-v6.5-rc3
commit 98400367
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/?id=9840036786d90cea11a90d1f30b6dc003b34ee67

--------------------------------

Commit 1fd54773 ("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/CAJPywTKDdjtwkLVUW6LRA2FU912qcDmQOQGt2WaDo28KzYDg+A@mail.gmail.com/



This change restores the expected behavior of GSO_UDP_L4 packets.

Fixes: 1fd54773 ("udp: allow header check for dodgy GSO_UDP_L4 packets.")
Suggested-by: default avatarWillem de Bruijn <willemdebruijn.kernel@gmail.com>
Signed-off-by: default avatarYan Zhai <yan@cloudflare.com>
Reviewed-by: default avatarWillem de Bruijn <willemb@google.com>
Acked-by: default avatarJason Wang <jasowang@redhat.com>
Signed-off-by: default avatarDavid 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"), 1fd54773 ("udp: allow
header check for dodgy GSO_UDP_L4 packets.") not merged]
Signed-off-by: default avatarZhang Changzhong <zhangchangzhong@huawei.com>
parent c09bf981
Loading
Loading
Loading
Loading
+11 −4
Original line number Diff line number Diff line
@@ -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 */