]> www.infradead.org Git - users/dwmw2/linux.git/commitdiff
ipv4: Convert devinet_ioctl() to per-netns RTNL except for SIOCSIFFLAGS.
authorKuniyuki Iwashima <kuniyu@amazon.com>
Mon, 21 Oct 2024 18:32:38 +0000 (11:32 -0700)
committerPaolo Abeni <pabeni@redhat.com>
Tue, 29 Oct 2024 10:54:58 +0000 (11:54 +0100)
Basically, devinet_ioctl() operates on a single netns.

However, ioctl(SIOCSIFFLAGS) will trigger the netdev notifier
that could touch another netdev in different netns.

Let's use per-netns RTNL helper in devinet_ioctl() and place
ASSERT_RTNL() for SIOCSIFFLAGS.

We will remove ASSERT_RTNL() once RTM_SETLINK and RTM_DELLINK
are converted.

Signed-off-by: Kuniyuki Iwashima <kuniyu@amazon.com>
Reviewed-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
net/ipv4/devinet.c

index bd65e0ef774eb729779b27893d1ae48df764b810..fb4bc63b8fa29d09b2f3fe4baf433d77a379cff1 100644 (file)
@@ -589,9 +589,7 @@ static int inet_insert_ifa(struct in_ifaddr *ifa)
 
 static int inet_set_ifa(struct net_device *dev, struct in_ifaddr *ifa)
 {
-       struct in_device *in_dev = __in_dev_get_rtnl(dev);
-
-       ASSERT_RTNL();
+       struct in_device *in_dev = __in_dev_get_rtnl_net(dev);
 
        ipv4_devconf_setall(in_dev);
        neigh_parms_data_state_setall(in_dev->arp_parms);
@@ -1129,7 +1127,7 @@ int devinet_ioctl(struct net *net, unsigned int cmd, struct ifreq *ifr)
                goto out;
        }
 
-       rtnl_lock();
+       rtnl_net_lock(net);
 
        ret = -ENODEV;
        dev = __dev_get_by_name(net, ifr->ifr_name);
@@ -1139,7 +1137,7 @@ int devinet_ioctl(struct net *net, unsigned int cmd, struct ifreq *ifr)
        if (colon)
                *colon = ':';
 
-       in_dev = __in_dev_get_rtnl(dev);
+       in_dev = __in_dev_get_rtnl_net(dev);
        if (in_dev) {
                if (tryaddrmatch) {
                        /* Matthias Andree */
@@ -1149,7 +1147,7 @@ int devinet_ioctl(struct net *net, unsigned int cmd, struct ifreq *ifr)
                           This is checked above. */
 
                        for (ifap = &in_dev->ifa_list;
-                            (ifa = rtnl_dereference(*ifap)) != NULL;
+                            (ifa = rtnl_net_dereference(net, *ifap)) != NULL;
                             ifap = &ifa->ifa_next) {
                                if (!strcmp(ifr->ifr_name, ifa->ifa_label) &&
                                    sin_orig.sin_addr.s_addr ==
@@ -1163,7 +1161,7 @@ int devinet_ioctl(struct net *net, unsigned int cmd, struct ifreq *ifr)
                   comparing just the label */
                if (!ifa) {
                        for (ifap = &in_dev->ifa_list;
-                            (ifa = rtnl_dereference(*ifap)) != NULL;
+                            (ifa = rtnl_net_dereference(net, *ifap)) != NULL;
                             ifap = &ifa->ifa_next)
                                if (!strcmp(ifr->ifr_name, ifa->ifa_label))
                                        break;
@@ -1205,6 +1203,9 @@ int devinet_ioctl(struct net *net, unsigned int cmd, struct ifreq *ifr)
                                inet_del_ifa(in_dev, ifap, 1);
                        break;
                }
+
+               /* NETDEV_UP/DOWN/CHANGE could touch a peer dev */
+               ASSERT_RTNL();
                ret = dev_change_flags(dev, ifr->ifr_flags, NULL);
                break;
 
@@ -1306,7 +1307,7 @@ int devinet_ioctl(struct net *net, unsigned int cmd, struct ifreq *ifr)
                break;
        }
 done:
-       rtnl_unlock();
+       rtnl_net_unlock(net);
 out:
        return ret;
 }