diff options
author | Sabrina Dubroca <sd@queasysnail.net> | 2016-08-11 09:24:27 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2016-08-11 12:58:57 -0400 |
commit | bbe11fab0b6c1d113776b2898e085bf4d1fdc607 (patch) | |
tree | 6cfcbd774a34d469cbe811424095f3c0807db577 | |
parent | 104a493390940e85fb7c840a9fd5214aba5cb3bd (diff) |
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: 960d5848dbf1 ("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>
-rw-r--r-- | drivers/net/macsec.c | 23 |
1 files changed, 17 insertions, 6 deletions
diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c index d13e6e15d7b5..dbd590a8177f 100644 --- a/drivers/net/macsec.c +++ b/drivers/net/macsec.c | |||
@@ -3047,22 +3047,29 @@ static void macsec_del_dev(struct macsec_dev *macsec) | |||
3047 | } | 3047 | } |
3048 | } | 3048 | } |
3049 | 3049 | ||
3050 | static void macsec_common_dellink(struct net_device *dev, struct list_head *head) | ||
3051 | { | ||
3052 | struct macsec_dev *macsec = macsec_priv(dev); | ||
3053 | |||
3054 | unregister_netdevice_queue(dev, head); | ||
3055 | list_del_rcu(&macsec->secys); | ||
3056 | macsec_del_dev(macsec); | ||
3057 | |||
3058 | macsec_generation++; | ||
3059 | } | ||
3060 | |||
3050 | static void macsec_dellink(struct net_device *dev, struct list_head *head) | 3061 | static void macsec_dellink(struct net_device *dev, struct list_head *head) |
3051 | { | 3062 | { |
3052 | struct macsec_dev *macsec = macsec_priv(dev); | 3063 | struct macsec_dev *macsec = macsec_priv(dev); |
3053 | struct net_device *real_dev = macsec->real_dev; | 3064 | struct net_device *real_dev = macsec->real_dev; |
3054 | struct macsec_rxh_data *rxd = macsec_data_rtnl(real_dev); | 3065 | struct macsec_rxh_data *rxd = macsec_data_rtnl(real_dev); |
3055 | 3066 | ||
3056 | macsec_generation++; | 3067 | macsec_common_dellink(dev, head); |
3057 | 3068 | ||
3058 | unregister_netdevice_queue(dev, head); | ||
3059 | list_del_rcu(&macsec->secys); | ||
3060 | if (list_empty(&rxd->secys)) { | 3069 | if (list_empty(&rxd->secys)) { |
3061 | netdev_rx_handler_unregister(real_dev); | 3070 | netdev_rx_handler_unregister(real_dev); |
3062 | kfree(rxd); | 3071 | kfree(rxd); |
3063 | } | 3072 | } |
3064 | |||
3065 | macsec_del_dev(macsec); | ||
3066 | } | 3073 | } |
3067 | 3074 | ||
3068 | static int register_macsec_dev(struct net_device *real_dev, | 3075 | 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 | 3389 | ||
3383 | rxd = macsec_data_rtnl(real_dev); | 3390 | rxd = macsec_data_rtnl(real_dev); |
3384 | list_for_each_entry_safe(m, n, &rxd->secys, secys) { | 3391 | list_for_each_entry_safe(m, n, &rxd->secys, secys) { |
3385 | macsec_dellink(m->secy.netdev, &head); | 3392 | macsec_common_dellink(m->secy.netdev, &head); |
3386 | } | 3393 | } |
3394 | |||
3395 | netdev_rx_handler_unregister(real_dev); | ||
3396 | kfree(rxd); | ||
3397 | |||
3387 | unregister_netdevice_many(&head); | 3398 | unregister_netdevice_many(&head); |
3388 | break; | 3399 | break; |
3389 | } | 3400 | } |