1
0
Fork 0

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: 960d5848db ("macsec: fix memory leaks around rx_handler (un)registration")
Signed-off-by: Sabrina Dubroca <sd@queasysnail.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
hifive-unleashed-5.1
Sabrina Dubroca 2016-08-11 15:24:27 +02:00 committed by David S. Miller
parent 104a493390
commit bbe11fab0b
1 changed files with 17 additions and 6 deletions

View File

@ -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)
{
struct macsec_dev *macsec = macsec_priv(dev);
struct net_device *real_dev = macsec->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)) {
netdev_rx_handler_unregister(real_dev);
kfree(rxd);
}
macsec_del_dev(macsec);
}
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,
rxd = macsec_data_rtnl(real_dev);
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);
break;
}