udp: introduce udp->udp_flags
authorEric Dumazet <edumazet@google.com>
Tue, 12 Sep 2023 09:17:21 +0000 (09:17 +0000)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 20 Nov 2023 10:58:55 +0000 (11:58 +0100)
[ Upstream commit 81b36803ac139827538ac5ce4028e750a3c53f53 ]

According to syzbot, it is time to use proper atomic flags
for various UDP flags.

Add udp_flags field, and convert udp->corkflag to first
bit in it.

Signed-off-by: Eric Dumazet <edumazet@google.com>
Reviewed-by: Willem de Bruijn <willemb@google.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Stable-dep-of: a0002127cd74 ("udp: move udp->no_check6_tx to udp->udp_flags")
Signed-off-by: Sasha Levin <sashal@kernel.org>
include/linux/udp.h
net/ipv4/udp.c
net/ipv6/udp.c

index 43c1fb2..23f0693 100644 (file)
@@ -32,14 +32,20 @@ static inline u32 udp_hashfn(const struct net *net, u32 num, u32 mask)
        return (num + net_hash_mix(net)) & mask;
 }
 
+enum {
+       UDP_FLAGS_CORK,         /* Cork is required */
+};
+
 struct udp_sock {
        /* inet_sock has to be the first member */
        struct inet_sock inet;
 #define udp_port_hash          inet.sk.__sk_common.skc_u16hashes[0]
 #define udp_portaddr_hash      inet.sk.__sk_common.skc_u16hashes[1]
 #define udp_portaddr_node      inet.sk.__sk_common.skc_portaddr_node
+
+       unsigned long    udp_flags;
+
        int              pending;       /* Any pending frames ? */
-       unsigned int     corkflag;      /* Cork is required */
        __u8             encap_type;    /* Is this an Encapsulation socket? */
        unsigned char    no_check6_tx:1,/* Send zero UDP6 checksums on TX? */
                         no_check6_rx:1,/* Allow zero UDP6 checksums on RX? */
@@ -51,6 +57,11 @@ struct udp_sock {
                         gro_enabled:1, /* Request GRO aggregation */
                         accept_udp_l4:1,
                         accept_udp_fraglist:1;
+/* indicator bits used by pcflag: */
+#define UDPLITE_BIT      0x1           /* set by udplite proto init function */
+#define UDPLITE_SEND_CC  0x2           /* set via udplite setsockopt         */
+#define UDPLITE_RECV_CC  0x4           /* set via udplite setsocktopt        */
+       __u8             pcflag;        /* marks socket as UDP-Lite if > 0    */
        /*
         * Following member retains the information to create a UDP header
         * when the socket is uncorked.
@@ -62,12 +73,6 @@ struct udp_sock {
         */
        __u16            pcslen;
        __u16            pcrlen;
-/* indicator bits used by pcflag: */
-#define UDPLITE_BIT      0x1           /* set by udplite proto init function */
-#define UDPLITE_SEND_CC  0x2           /* set via udplite setsockopt         */
-#define UDPLITE_RECV_CC  0x4           /* set via udplite setsocktopt        */
-       __u8             pcflag;        /* marks socket as UDP-Lite if > 0    */
-       __u8             unused[3];
        /*
         * For encapsulation sockets.
         */
@@ -95,6 +100,15 @@ struct udp_sock {
        int             forward_threshold;
 };
 
+#define udp_test_bit(nr, sk)                   \
+       test_bit(UDP_FLAGS_##nr, &udp_sk(sk)->udp_flags)
+#define udp_set_bit(nr, sk)                    \
+       set_bit(UDP_FLAGS_##nr, &udp_sk(sk)->udp_flags)
+#define udp_clear_bit(nr, sk)                  \
+       clear_bit(UDP_FLAGS_##nr, &udp_sk(sk)->udp_flags)
+#define udp_assign_bit(nr, sk, val)            \
+       assign_bit(UDP_FLAGS_##nr, &udp_sk(sk)->udp_flags, val)
+
 #define UDP_MAX_SEGMENTS       (1 << 6UL)
 
 #define udp_sk(ptr) container_of_const(ptr, struct udp_sock, inet.sk)
index f39b9c8..9709f8a 100644 (file)
@@ -1051,7 +1051,7 @@ int udp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
        u8 tos, scope;
        __be16 dport;
        int err, is_udplite = IS_UDPLITE(sk);
-       int corkreq = READ_ONCE(up->corkflag) || msg->msg_flags&MSG_MORE;
+       int corkreq = udp_test_bit(CORK, sk) || msg->msg_flags & MSG_MORE;
        int (*getfrag)(void *, char *, int, int, int, struct sk_buff *);
        struct sk_buff *skb;
        struct ip_options_data opt_copy;
@@ -1315,11 +1315,11 @@ void udp_splice_eof(struct socket *sock)
        struct sock *sk = sock->sk;
        struct udp_sock *up = udp_sk(sk);
 
-       if (!up->pending || READ_ONCE(up->corkflag))
+       if (!up->pending || udp_test_bit(CORK, sk))
                return;
 
        lock_sock(sk);
-       if (up->pending && !READ_ONCE(up->corkflag))
+       if (up->pending && !udp_test_bit(CORK, sk))
                udp_push_pending_frames(sk);
        release_sock(sk);
 }
@@ -2658,9 +2658,9 @@ int udp_lib_setsockopt(struct sock *sk, int level, int optname,
        switch (optname) {
        case UDP_CORK:
                if (val != 0) {
-                       WRITE_ONCE(up->corkflag, 1);
+                       udp_set_bit(CORK, sk);
                } else {
-                       WRITE_ONCE(up->corkflag, 0);
+                       udp_clear_bit(CORK, sk);
                        lock_sock(sk);
                        push_pending_frames(sk);
                        release_sock(sk);
@@ -2783,7 +2783,7 @@ int udp_lib_getsockopt(struct sock *sk, int level, int optname,
 
        switch (optname) {
        case UDP_CORK:
-               val = READ_ONCE(up->corkflag);
+               val = udp_test_bit(CORK, sk);
                break;
 
        case UDP_ENCAP:
index 86b5d50..0c6973c 100644 (file)
@@ -1332,7 +1332,7 @@ int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
        int addr_len = msg->msg_namelen;
        bool connected = false;
        int ulen = len;
-       int corkreq = READ_ONCE(up->corkflag) || msg->msg_flags&MSG_MORE;
+       int corkreq = udp_test_bit(CORK, sk) || msg->msg_flags & MSG_MORE;
        int err;
        int is_udplite = IS_UDPLITE(sk);
        int (*getfrag)(void *, char *, int, int, int, struct sk_buff *);
@@ -1644,11 +1644,11 @@ static void udpv6_splice_eof(struct socket *sock)
        struct sock *sk = sock->sk;
        struct udp_sock *up = udp_sk(sk);
 
-       if (!up->pending || READ_ONCE(up->corkflag))
+       if (!up->pending || udp_test_bit(CORK, sk))
                return;
 
        lock_sock(sk);
-       if (up->pending && !READ_ONCE(up->corkflag))
+       if (up->pending && !udp_test_bit(CORK, sk))
                udp_v6_push_pending_frames(sk);
        release_sock(sk);
 }