Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

gso: fix dodgy bit handling for GSO_UDP_L4

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/CAJPywTKDdjtwkLVUW6LRA2FU912qcDmQOQGt2WaDo28KzYDg+A@mail.gmail.com/

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>

authored by

Yan Zhai and committed by
David S. Miller
98400367 a822551c

+12 -7
+11 -5
net/ipv4/udp_offload.c
··· 274 274 __sum16 check; 275 275 __be16 newlen; 276 276 277 - if (skb_shinfo(gso_skb)->gso_type & SKB_GSO_FRAGLIST) 278 - return __udp_gso_segment_list(gso_skb, features, is_ipv6); 279 - 280 277 mss = skb_shinfo(gso_skb)->gso_size; 281 278 if (gso_skb->len <= sizeof(*uh) + mss) 282 279 return ERR_PTR(-EINVAL); 280 + 281 + if (skb_gso_ok(gso_skb, features | NETIF_F_GSO_ROBUST)) { 282 + /* Packet is from an untrusted source, reset gso_segs. */ 283 + skb_shinfo(gso_skb)->gso_segs = DIV_ROUND_UP(gso_skb->len - sizeof(*uh), 284 + mss); 285 + return NULL; 286 + } 287 + 288 + if (skb_shinfo(gso_skb)->gso_type & SKB_GSO_FRAGLIST) 289 + return __udp_gso_segment_list(gso_skb, features, is_ipv6); 283 290 284 291 skb_pull(gso_skb, sizeof(*uh)); 285 292 ··· 395 388 if (!pskb_may_pull(skb, sizeof(struct udphdr))) 396 389 goto out; 397 390 398 - if (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_L4 && 399 - !skb_gso_ok(skb, features | NETIF_F_GSO_ROBUST)) 391 + if (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_L4) 400 392 return __udp_gso_segment(skb, features, false); 401 393 402 394 mss = skb_shinfo(skb)->gso_size;
+1 -2
net/ipv6/udp_offload.c
··· 43 43 if (!pskb_may_pull(skb, sizeof(struct udphdr))) 44 44 goto out; 45 45 46 - if (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_L4 && 47 - !skb_gso_ok(skb, features | NETIF_F_GSO_ROBUST)) 46 + if (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_L4) 48 47 return __udp_gso_segment(skb, features, true); 49 48 50 49 mss = skb_shinfo(skb)->gso_size;