summaryrefslogtreecommitdiff
path: root/drivers/net/bonding
diff options
context:
space:
mode:
authorMoni Shoua <monis@mellanox.com>2015-02-08 11:49:32 +0200
committerDavid S. Miller <davem@davemloft.net>2015-02-09 14:03:53 -0800
commit92e584fe443995bbb84069a4d13ea8ebedb5c5c8 (patch)
tree56ec4d25143890b36edd026b8ab6ec3950d98661 /drivers/net/bonding
parent9dce285b70c157754d753203112cfef22770b1f9 (diff)
net/bonding: Fix potential bad memory access during bonding events
When queuing work to send the NETDEV_BONDING_INFO netdev event, it's possible that when the work is executed, the pointer to the slave becomes invalid. This can happen if between queuing the event and the execution of the work, the net-device was un-ensvaled and re-enslaved. Fix that by queuing a work with the data of the slave instead of the slave structure. Fixes: 69e6113343cf ('net/bonding: Notify state change on slaves') Reported-by: Nikolay Aleksandrov <nikolay@redhat.com> Signed-off-by: Moni Shoua <monis@mellanox.com> Signed-off-by: Or Gerlitz <ogerlitz@mellanox.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/bonding')
-rw-r--r--drivers/net/bonding/bond_main.c28
1 files changed, 11 insertions, 17 deletions
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 679ef00d6b16..b979c265fc51 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -1196,18 +1196,11 @@ static void bond_fill_ifslave(struct slave *slave, struct ifslave *info)
info->link_failure_count = slave->link_failure_count;
}
-static void bond_netdev_notify(struct slave *slave, struct net_device *dev)
+static void bond_netdev_notify(struct net_device *dev,
+ struct netdev_bonding_info *info)
{
- struct bonding *bond = slave->bond;
- struct netdev_bonding_info bonding_info;
-
rtnl_lock();
- /* make sure that slave is still valid */
- if (dev->priv_flags & IFF_BONDING) {
- bond_fill_ifslave(slave, &bonding_info.slave);
- bond_fill_ifbond(bond, &bonding_info.master);
- netdev_bonding_info_change(slave->dev, &bonding_info);
- }
+ netdev_bonding_info_change(dev, info);
rtnl_unlock();
}
@@ -1216,25 +1209,26 @@ static void bond_netdev_notify_work(struct work_struct *_work)
struct netdev_notify_work *w =
container_of(_work, struct netdev_notify_work, work.work);
- bond_netdev_notify(w->slave, w->dev);
+ bond_netdev_notify(w->dev, &w->bonding_info);
dev_put(w->dev);
+ kfree(w);
}
void bond_queue_slave_event(struct slave *slave)
{
+ struct bonding *bond = slave->bond;
struct netdev_notify_work *nnw = kzalloc(sizeof(*nnw), GFP_ATOMIC);
if (!nnw)
return;
- INIT_DELAYED_WORK(&nnw->work, bond_netdev_notify_work);
- nnw->slave = slave;
+ dev_hold(slave->dev);
nnw->dev = slave->dev;
+ bond_fill_ifslave(slave, &nnw->bonding_info.slave);
+ bond_fill_ifbond(bond, &nnw->bonding_info.master);
+ INIT_DELAYED_WORK(&nnw->work, bond_netdev_notify_work);
- if (queue_delayed_work(slave->bond->wq, &nnw->work, 0))
- dev_hold(slave->dev);
- else
- kfree(nnw);
+ queue_delayed_work(slave->bond->wq, &nnw->work, 0);
}
/* enslave device <slave> to bond device <master> */