inet: implement lockless getsockopt(IP_MULTICAST_IF)
authorEric Dumazet <edumazet@google.com>
Fri, 22 Sep 2023 03:42:21 +0000 (03:42 +0000)
committerDavid S. Miller <davem@davemloft.net>
Sun, 1 Oct 2023 18:39:19 +0000 (19:39 +0100)
Add missing annotations to inet->mc_index and inet->mc_addr
to fix data-races.

getsockopt(IP_MULTICAST_IF) can be lockless.

setsockopt() side is left for later.

Signed-off-by: Eric Dumazet <edumazet@google.com>
Reviewed-by: David Ahern <dsahern@kernel.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/ipv4/datagram.c
net/ipv4/ip_sockglue.c
net/ipv4/ping.c
net/ipv4/raw.c
net/ipv4/udp.c

index 1480e9ebdfef445960e1f70f34f33a0e0c52b65b..2cc50cbfc2a31ec91fbdc4a541cb89df689cd9ae 100644 (file)
@@ -39,9 +39,9 @@ int __ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len
        saddr = inet->inet_saddr;
        if (ipv4_is_multicast(usin->sin_addr.s_addr)) {
                if (!oif || netif_index_is_l3_master(sock_net(sk), oif))
-                       oif = inet->mc_index;
+                       oif = READ_ONCE(inet->mc_index);
                if (!saddr)
-                       saddr = inet->mc_addr;
+                       saddr = READ_ONCE(inet->mc_addr);
        } else if (!oif) {
                oif = READ_ONCE(inet->uc_index);
        }
index 1ee01ff64171c94b6b244589518a53ce807a212d..0b74ac49d6a6f82f5e8ffe5279dba3baf30f874e 100644 (file)
@@ -1168,8 +1168,8 @@ int do_ip_setsockopt(struct sock *sk, int level, int optname,
 
                if (!mreq.imr_ifindex) {
                        if (mreq.imr_address.s_addr == htonl(INADDR_ANY)) {
-                               inet->mc_index = 0;
-                               inet->mc_addr  = 0;
+                               WRITE_ONCE(inet->mc_index, 0);
+                               WRITE_ONCE(inet->mc_addr, 0);
                                err = 0;
                                break;
                        }
@@ -1194,8 +1194,8 @@ int do_ip_setsockopt(struct sock *sk, int level, int optname,
                    midx != sk->sk_bound_dev_if)
                        break;
 
-               inet->mc_index = mreq.imr_ifindex;
-               inet->mc_addr  = mreq.imr_address.s_addr;
+               WRITE_ONCE(inet->mc_index, mreq.imr_ifindex);
+               WRITE_ONCE(inet->mc_addr, mreq.imr_address.s_addr);
                err = 0;
                break;
        }
@@ -1673,19 +1673,11 @@ int do_ip_getsockopt(struct sock *sk, int level, int optname,
        case IP_UNICAST_IF:
                val = (__force int)htonl((__u32) READ_ONCE(inet->uc_index));
                goto copyval;
-       }
-
-       if (needs_rtnl)
-               rtnl_lock();
-       sockopt_lock_sock(sk);
-
-       switch (optname) {
        case IP_MULTICAST_IF:
        {
                struct in_addr addr;
                len = min_t(unsigned int, len, sizeof(struct in_addr));
-               addr.s_addr = inet->mc_addr;
-               sockopt_release_sock(sk);
+               addr.s_addr = READ_ONCE(inet->mc_addr);
 
                if (copy_to_sockptr(optlen, &len, sizeof(int)))
                        return -EFAULT;
@@ -1693,6 +1685,13 @@ int do_ip_getsockopt(struct sock *sk, int level, int optname,
                        return -EFAULT;
                return 0;
        }
+       }
+
+       if (needs_rtnl)
+               rtnl_lock();
+       sockopt_lock_sock(sk);
+
+       switch (optname) {
        case IP_MSFILTER:
        {
                struct ip_msfilter msf;
index 66ad1f95af49f222afe0ee75b9163dd0af0a2c49..2c61f444e1c7d322e75e020c41af02977d8814f0 100644 (file)
@@ -773,9 +773,9 @@ static int ping_v4_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
 
        if (ipv4_is_multicast(daddr)) {
                if (!ipc.oif || netif_index_is_l3_master(sock_net(sk), ipc.oif))
-                       ipc.oif = inet->mc_index;
+                       ipc.oif = READ_ONCE(inet->mc_index);
                if (!saddr)
-                       saddr = inet->mc_addr;
+                       saddr = READ_ONCE(inet->mc_addr);
        } else if (!ipc.oif)
                ipc.oif = READ_ONCE(inet->uc_index);
 
index e2357d23202e5a39832bb1550c365de9a836c363..27da9d7294c0b4fb9027bb7feb704063dc6302db 100644 (file)
@@ -579,9 +579,9 @@ static int raw_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
        uc_index = READ_ONCE(inet->uc_index);
        if (ipv4_is_multicast(daddr)) {
                if (!ipc.oif || netif_index_is_l3_master(sock_net(sk), ipc.oif))
-                       ipc.oif = inet->mc_index;
+                       ipc.oif = READ_ONCE(inet->mc_index);
                if (!saddr)
-                       saddr = inet->mc_addr;
+                       saddr = READ_ONCE(inet->mc_addr);
        } else if (!ipc.oif) {
                ipc.oif = uc_index;
        } else if (ipv4_is_lbcast(daddr) && uc_index) {
index 1e0c3aba1e5a88c7ba50a28511412a1710f1bab5..7f7724beca33781f8ff12750d1c9c9ccc420f481 100644 (file)
@@ -1177,9 +1177,9 @@ int udp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
        uc_index = READ_ONCE(inet->uc_index);
        if (ipv4_is_multicast(daddr)) {
                if (!ipc.oif || netif_index_is_l3_master(sock_net(sk), ipc.oif))
-                       ipc.oif = inet->mc_index;
+                       ipc.oif = READ_ONCE(inet->mc_index);
                if (!saddr)
-                       saddr = inet->mc_addr;
+                       saddr = READ_ONCE(inet->mc_addr);
                connected = 0;
        } else if (!ipc.oif) {
                ipc.oif = uc_index;