Skip to content

Commit 1a83f4a

Browse files
kuba-mooPaolo Abeni
authored andcommitted
net: avoid UAF on deleted altname
Altnames are accessed under RCU (dev_get_by_name_rcu()) but freed by kfree() with no synchronization point. Each node has one or two allocations (node and a variable-size name, sometimes the name is netdev->name). Adding rcu_heads here is a bit tedious. Besides most code which unlists the names already has rcu barriers - so take the simpler approach of adding synchronize_rcu(). Note that the one on the unregistration path (which matters more) is removed by the next fix. Fixes: ff92741 ("net: introduce name_node struct to be used in hashlist") Reviewed-by: Jiri Pirko <jiri@nvidia.com> Signed-off-by: Jakub Kicinski <kuba@kernel.org> Signed-off-by: Paolo Abeni <pabeni@redhat.com>
1 parent 7663d52 commit 1a83f4a

File tree

1 file changed

+6
-1
lines changed

1 file changed

+6
-1
lines changed

net/core/dev.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -345,7 +345,6 @@ int netdev_name_node_alt_create(struct net_device *dev, const char *name)
345345
static void __netdev_name_node_alt_destroy(struct netdev_name_node *name_node)
346346
{
347347
list_del(&name_node->list);
348-
netdev_name_node_del(name_node);
349348
kfree(name_node->name);
350349
netdev_name_node_free(name_node);
351350
}
@@ -364,6 +363,8 @@ int netdev_name_node_alt_destroy(struct net_device *dev, const char *name)
364363
if (name_node == dev->name_node || name_node->dev != dev)
365364
return -EINVAL;
366365

366+
netdev_name_node_del(name_node);
367+
synchronize_rcu();
367368
__netdev_name_node_alt_destroy(name_node);
368369

369370
return 0;
@@ -10941,6 +10942,7 @@ void unregister_netdevice_many_notify(struct list_head *head,
1094110942
synchronize_net();
1094210943

1094310944
list_for_each_entry(dev, head, unreg_list) {
10945+
struct netdev_name_node *name_node;
1094410946
struct sk_buff *skb = NULL;
1094510947

1094610948
/* Shutdown queueing discipline. */
@@ -10968,6 +10970,9 @@ void unregister_netdevice_many_notify(struct list_head *head,
1096810970
dev_uc_flush(dev);
1096910971
dev_mc_flush(dev);
1097010972

10973+
netdev_for_each_altname(dev, name_node)
10974+
netdev_name_node_del(name_node);
10975+
synchronize_rcu();
1097110976
netdev_name_node_alt_flush(dev);
1097210977
netdev_name_node_free(dev->name_node);
1097310978

0 commit comments

Comments
 (0)