net: add rcu safety to rtnl_prop_list_size()
authorEric Dumazet <edumazet@google.com>
Fri, 9 Feb 2024 18:12:48 +0000 (18:12 +0000)
committerJakub Kicinski <kuba@kernel.org>
Tue, 13 Feb 2024 01:38:52 +0000 (17:38 -0800)
rtnl_prop_list_size() can be called while alternative names
are added or removed concurrently.

if_nlmsg_size() / rtnl_calcit() can indeed be called
without RTNL held.

Use explicit RCU protection to avoid UAF.

Fixes: 88f4fb0c7496 ("net: rtnetlink: put alternative names to getlink message")
Signed-off-by: Eric Dumazet <edumazet@google.com>
Cc: Jiri Pirko <jiri@nvidia.com>
Link: https://lore.kernel.org/r/20240209181248.96637-1-edumazet@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
net/core/dev.c
net/core/rtnetlink.c

index 9bb792cecc16f07449a91e4ca96357600d7453f9..73a0219730075e666c4f11f668a50dbf9f9afa97 100644 (file)
@@ -336,7 +336,7 @@ int netdev_name_node_alt_create(struct net_device *dev, const char *name)
                return -ENOMEM;
        netdev_name_node_add(net, name_node);
        /* The node that holds dev->name acts as a head of per-device list. */
-       list_add_tail(&name_node->list, &dev->name_node->list);
+       list_add_tail_rcu(&name_node->list, &dev->name_node->list);
 
        return 0;
 }
index f6f29eb03ec277a1ea17ccc220fa7624bf6db092..9c4f427f3a5057b52ec05405e8b15b8ca2246b4b 100644 (file)
@@ -1020,14 +1020,17 @@ static size_t rtnl_xdp_size(void)
 static size_t rtnl_prop_list_size(const struct net_device *dev)
 {
        struct netdev_name_node *name_node;
-       size_t size;
+       unsigned int cnt = 0;
+
+       rcu_read_lock();
+       list_for_each_entry_rcu(name_node, &dev->name_node->list, list)
+               cnt++;
+       rcu_read_unlock();
 
-       if (list_empty(&dev->name_node->list))
+       if (!cnt)
                return 0;
-       size = nla_total_size(0);
-       list_for_each_entry(name_node, &dev->name_node->list, list)
-               size += nla_total_size(ALTIFNAMSIZ);
-       return size;
+
+       return nla_total_size(0) + cnt * nla_total_size(ALTIFNAMSIZ);
 }
 
 static size_t rtnl_proto_down_size(const struct net_device *dev)