Commit bbe11fab authored by Sabrina Dubroca's avatar Sabrina Dubroca Committed by David S. Miller

macsec: use after free when deleting the underlying device

macsec_notify() loops over the list of macsec devices configured on the
underlying device when this device is being removed.  This list is part
of the rx_handler data.

However, macsec_dellink unregisters the rx_handler and frees the
rx_handler data when the last macsec device is removed from the
underlying device.

Add macsec_common_dellink() to delete macsec devices without
unregistering the rx_handler and freeing the associated data.

Fixes: 960d5848 ("macsec: fix memory leaks around rx_handler (un)registration")
Signed-off-by: default avatarSabrina Dubroca <sd@queasysnail.net>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 104a4933
...@@ -3047,22 +3047,29 @@ static void macsec_del_dev(struct macsec_dev *macsec) ...@@ -3047,22 +3047,29 @@ static void macsec_del_dev(struct macsec_dev *macsec)
} }
} }
static void macsec_common_dellink(struct net_device *dev, struct list_head *head)
{
struct macsec_dev *macsec = macsec_priv(dev);
unregister_netdevice_queue(dev, head);
list_del_rcu(&macsec->secys);
macsec_del_dev(macsec);
macsec_generation++;
}
static void macsec_dellink(struct net_device *dev, struct list_head *head) static void macsec_dellink(struct net_device *dev, struct list_head *head)
{ {
struct macsec_dev *macsec = macsec_priv(dev); struct macsec_dev *macsec = macsec_priv(dev);
struct net_device *real_dev = macsec->real_dev; struct net_device *real_dev = macsec->real_dev;
struct macsec_rxh_data *rxd = macsec_data_rtnl(real_dev); struct macsec_rxh_data *rxd = macsec_data_rtnl(real_dev);
macsec_generation++; macsec_common_dellink(dev, head);
unregister_netdevice_queue(dev, head);
list_del_rcu(&macsec->secys);
if (list_empty(&rxd->secys)) { if (list_empty(&rxd->secys)) {
netdev_rx_handler_unregister(real_dev); netdev_rx_handler_unregister(real_dev);
kfree(rxd); kfree(rxd);
} }
macsec_del_dev(macsec);
} }
static int register_macsec_dev(struct net_device *real_dev, static int register_macsec_dev(struct net_device *real_dev,
...@@ -3382,8 +3389,12 @@ static int macsec_notify(struct notifier_block *this, unsigned long event, ...@@ -3382,8 +3389,12 @@ static int macsec_notify(struct notifier_block *this, unsigned long event,
rxd = macsec_data_rtnl(real_dev); rxd = macsec_data_rtnl(real_dev);
list_for_each_entry_safe(m, n, &rxd->secys, secys) { list_for_each_entry_safe(m, n, &rxd->secys, secys) {
macsec_dellink(m->secy.netdev, &head); macsec_common_dellink(m->secy.netdev, &head);
} }
netdev_rx_handler_unregister(real_dev);
kfree(rxd);
unregister_netdevice_many(&head); unregister_netdevice_many(&head);
break; break;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment