inet: do not use RTNL in inet_netconf_get_devconf()
authorEric Dumazet <edumazet@google.com>
Tue, 27 Feb 2024 09:24:10 +0000 (09:24 +0000)
committerJakub Kicinski <kuba@kernel.org>
Thu, 29 Feb 2024 03:36:40 +0000 (19:36 -0800)
"ip -4 netconf show dev XXXX" no longer acquires RTNL.

Return -ENODEV instead of -EINVAL if no netdev or idev can be found.

Signed-off-by: Eric Dumazet <edumazet@google.com>
Reviewed-by: Jiri Pirko <jiri@nvidia.com>
Link: https://lore.kernel.org/r/20240227092411.2315725-3-edumazet@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
net/ipv4/devinet.c

index ca75d0fff1d1ebd8c199fb74a6f0e2f51160635c..f045a34e90b974b17512a30c3b719bdfc3cba153 100644 (file)
@@ -2205,21 +2205,20 @@ static int inet_netconf_get_devconf(struct sk_buff *in_skb,
                                    struct netlink_ext_ack *extack)
 {
        struct net *net = sock_net(in_skb->sk);
-       struct nlattr *tb[NETCONFA_MAX+1];
+       struct nlattr *tb[NETCONFA_MAX + 1];
+       const struct ipv4_devconf *devconf;
+       struct in_device *in_dev = NULL;
+       struct net_device *dev = NULL;
        struct sk_buff *skb;
-       struct ipv4_devconf *devconf;
-       struct in_device *in_dev;
-       struct net_device *dev;
        int ifindex;
        int err;
 
        err = inet_netconf_valid_get_req(in_skb, nlh, tb, extack);
        if (err)
-               goto errout;
+               return err;
 
-       err = -EINVAL;
        if (!tb[NETCONFA_IFINDEX])
-               goto errout;
+               return -EINVAL;
 
        ifindex = nla_get_s32(tb[NETCONFA_IFINDEX]);
        switch (ifindex) {
@@ -2230,10 +2229,10 @@ static int inet_netconf_get_devconf(struct sk_buff *in_skb,
                devconf = net->ipv4.devconf_dflt;
                break;
        default:
-               dev = __dev_get_by_index(net, ifindex);
-               if (!dev)
-                       goto errout;
-               in_dev = __in_dev_get_rtnl(dev);
+               err = -ENODEV;
+               dev = dev_get_by_index(net, ifindex);
+               if (dev)
+                       in_dev = in_dev_get(dev);
                if (!in_dev)
                        goto errout;
                devconf = &in_dev->cnf;
@@ -2257,6 +2256,9 @@ static int inet_netconf_get_devconf(struct sk_buff *in_skb,
        }
        err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).portid);
 errout:
+       if (in_dev)
+               in_dev_put(in_dev);
+       dev_put(dev);
        return err;
 }
 
@@ -2826,5 +2828,6 @@ void __init devinet_init(void)
        rtnl_register(PF_INET, RTM_DELADDR, inet_rtm_deladdr, NULL, 0);
        rtnl_register(PF_INET, RTM_GETADDR, NULL, inet_dump_ifaddr, 0);
        rtnl_register(PF_INET, RTM_GETNETCONF, inet_netconf_get_devconf,
-                     inet_netconf_dump_devconf, 0);
+                     inet_netconf_dump_devconf,
+                     RTNL_FLAG_DOIT_UNLOCKED);
 }