| From d0ef7aca6c2e3a67dc5ad7cf4fd1116f96bd271b Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Tue, 30 Mar 2021 12:28:52 +0200 |
| Subject: udp: never accept GSO_FRAGLIST packets |
| |
| From: Paolo Abeni <pabeni@redhat.com> |
| |
| [ Upstream commit 78352f73dc5047f3f744764cc45912498c52f3c9 ] |
| |
| Currently the UDP protocol delivers GSO_FRAGLIST packets to |
| the sockets without the expected segmentation. |
| |
| This change addresses the issue introducing and maintaining |
| a couple of new fields to explicitly accept SKB_GSO_UDP_L4 |
| or GSO_FRAGLIST packets. Additionally updates udp_unexpected_gso() |
| accordingly. |
| |
| UDP sockets enabling UDP_GRO stil keep accept_udp_fraglist |
| zeroed. |
| |
| v1 -> v2: |
| - use 2 bits instead of a whole GSO bitmask (Willem) |
| |
| Fixes: 9fd1ff5d2ac7 ("udp: Support UDP fraglist GRO/GSO.") |
| Signed-off-by: Paolo Abeni <pabeni@redhat.com> |
| Reviewed-by: Willem de Bruijn <willemb@google.com> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| include/linux/udp.h | 16 +++++++++++++--- |
| net/ipv4/udp.c | 3 +++ |
| 2 files changed, 16 insertions(+), 3 deletions(-) |
| |
| diff --git a/include/linux/udp.h b/include/linux/udp.h |
| index aa84597bdc33..ae58ff3b6b5b 100644 |
| --- a/include/linux/udp.h |
| +++ b/include/linux/udp.h |
| @@ -51,7 +51,9 @@ struct udp_sock { |
| * different encapsulation layer set |
| * this |
| */ |
| - gro_enabled:1; /* Can accept GRO packets */ |
| + gro_enabled:1, /* Request GRO aggregation */ |
| + accept_udp_l4:1, |
| + accept_udp_fraglist:1; |
| /* |
| * Following member retains the information to create a UDP header |
| * when the socket is uncorked. |
| @@ -131,8 +133,16 @@ static inline void udp_cmsg_recv(struct msghdr *msg, struct sock *sk, |
| |
| static inline bool udp_unexpected_gso(struct sock *sk, struct sk_buff *skb) |
| { |
| - return !udp_sk(sk)->gro_enabled && skb_is_gso(skb) && |
| - skb_shinfo(skb)->gso_type & SKB_GSO_UDP_L4; |
| + if (!skb_is_gso(skb)) |
| + return false; |
| + |
| + if (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_L4 && !udp_sk(sk)->accept_udp_l4) |
| + return true; |
| + |
| + if (skb_shinfo(skb)->gso_type & SKB_GSO_FRAGLIST && !udp_sk(sk)->accept_udp_fraglist) |
| + return true; |
| + |
| + return false; |
| } |
| |
| #define udp_portaddr_for_each_entry(__sk, list) \ |
| diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c |
| index 9d2a1a247cec..a5d716f185f6 100644 |
| --- a/net/ipv4/udp.c |
| +++ b/net/ipv4/udp.c |
| @@ -2659,9 +2659,12 @@ int udp_lib_setsockopt(struct sock *sk, int level, int optname, |
| |
| case UDP_GRO: |
| lock_sock(sk); |
| + |
| + /* when enabling GRO, accept the related GSO packet type */ |
| if (valbool) |
| udp_tunnel_encap_enable(sk->sk_socket); |
| up->gro_enabled = valbool; |
| + up->accept_udp_l4 = valbool; |
| release_sock(sk); |
| break; |
| |
| -- |
| 2.30.2 |
| |