udp: move udp->gro_enabled to udp->udp_flags
authorEric Dumazet <edumazet@google.com>
Tue, 12 Sep 2023 09:17:24 +0000 (09:17 +0000)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 20 Nov 2023 10:58:56 +0000 (11:58 +0100)
[ Upstream commit e1dc0615c6b08ef36414f08c011965b8fb56198b ]

syzbot reported that udp->gro_enabled can be read locklessly.
Use one atomic bit from udp->udp_flags.

Fixes: e20cf8d3f1f7 ("udp: implement GRO for plain UDP sockets.")
Reported-by: syzbot <syzkaller@googlegroups.com>
Signed-off-by: Eric Dumazet <edumazet@google.com>
Reviewed-by: Willem de Bruijn <willemb@google.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
include/linux/udp.h
net/ipv4/udp.c
net/ipv4/udp_offload.c
net/ipv6/udp.c

index 8d4c383..b344bd2 100644 (file)
@@ -36,6 +36,7 @@ enum {
        UDP_FLAGS_CORK,         /* Cork is required */
        UDP_FLAGS_NO_CHECK6_TX, /* Send zero UDP6 checksums on TX? */
        UDP_FLAGS_NO_CHECK6_RX, /* Allow zero UDP6 checksums on RX? */
+       UDP_FLAGS_GRO_ENABLED,  /* Request GRO aggregation */
 };
 
 struct udp_sock {
@@ -54,7 +55,6 @@ struct udp_sock {
                                           * different encapsulation layer set
                                           * this
                                           */
-                        gro_enabled:1, /* Request GRO aggregation */
                         accept_udp_l4:1,
                         accept_udp_fraglist:1;
 /* indicator bits used by pcflag: */
index cb32826..1debc10 100644 (file)
@@ -1868,7 +1868,7 @@ try_again:
                                                      (struct sockaddr *)sin);
        }
 
-       if (udp_sk(sk)->gro_enabled)
+       if (udp_test_bit(GRO_ENABLED, sk))
                udp_cmsg_recv(msg, sk, skb);
 
        if (inet_cmsg_flags(inet))
@@ -2713,7 +2713,7 @@ int udp_lib_setsockopt(struct sock *sk, int level, int optname,
                /* when enabling GRO, accept the related GSO packet type */
                if (valbool)
                        udp_tunnel_encap_enable(sk->sk_socket);
-               up->gro_enabled = valbool;
+               udp_assign_bit(GRO_ENABLED, sk, valbool);
                up->accept_udp_l4 = valbool;
                release_sock(sk);
                break;
@@ -2803,7 +2803,7 @@ int udp_lib_getsockopt(struct sock *sk, int level, int optname,
                break;
 
        case UDP_GRO:
-               val = up->gro_enabled;
+               val = udp_test_bit(GRO_ENABLED, sk);
                break;
 
        /* The following two cannot be changed on UDP sockets, the return is
index 0f46b3c..6c95d28 100644 (file)
@@ -557,10 +557,10 @@ struct sk_buff *udp_gro_receive(struct list_head *head, struct sk_buff *skb,
        NAPI_GRO_CB(skb)->is_flist = 0;
        if (!sk || !udp_sk(sk)->gro_receive) {
                if (skb->dev->features & NETIF_F_GRO_FRAGLIST)
-                       NAPI_GRO_CB(skb)->is_flist = sk ? !udp_sk(sk)->gro_enabled : 1;
+                       NAPI_GRO_CB(skb)->is_flist = sk ? !udp_test_bit(GRO_ENABLED, sk) : 1;
 
                if ((!sk && (skb->dev->features & NETIF_F_GRO_UDP_FWD)) ||
-                   (sk && udp_sk(sk)->gro_enabled) || NAPI_GRO_CB(skb)->is_flist)
+                   (sk && udp_test_bit(GRO_ENABLED, sk)) || NAPI_GRO_CB(skb)->is_flist)
                        return call_gro_receive(udp_gro_receive_segment, head, skb);
 
                /* no GRO, be sure flush the current packet */
index 6e1ea30..2c32818 100644 (file)
@@ -413,7 +413,7 @@ try_again:
                                                      (struct sockaddr *)sin6);
        }
 
-       if (udp_sk(sk)->gro_enabled)
+       if (udp_test_bit(GRO_ENABLED, sk))
                udp_cmsg_recv(msg, sk, skb);
 
        if (np->rxopt.all)