aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorMoni Shoua <monis@mellanox.com>2015-02-08 04:49:32 -0500
committerDavid S. Miller <davem@davemloft.net>2015-02-09 17:03:53 -0500
commit92e584fe443995bbb84069a4d13ea8ebedb5c5c8 (patch)
tree56ec4d25143890b36edd026b8ab6ec3950d98661 /drivers/net
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')
-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)
1196 info->link_failure_count = slave->link_failure_count; 1196 info->link_failure_count = slave->link_failure_count;
1197} 1197}
1198 1198
1199static void bond_netdev_notify(struct slave *slave, struct net_device *dev) 1199static void bond_netdev_notify(struct net_device *dev,
1200 struct netdev_bonding_info *info)
1200{ 1201{
1201 struct bonding *bond = slave->bond;
1202 struct netdev_bonding_info bonding_info;
1203
1204 rtnl_lock(); 1202 rtnl_lock();
1205 /* make sure that slave is still valid */ 1203 netdev_bonding_info_change(dev, info);
1206 if (dev->priv_flags & IFF_BONDING) {
1207 bond_fill_ifslave(slave, &bonding_info.slave);
1208 bond_fill_ifbond(bond, &bonding_info.master);
1209 netdev_bonding_info_change(slave->dev, &bonding_info);
1210 }
1211 rtnl_unlock(); 1204 rtnl_unlock();
1212} 1205}
1213 1206
@@ -1216,25 +1209,26 @@ static void bond_netdev_notify_work(struct work_struct *_work)
1216 struct netdev_notify_work *w = 1209 struct netdev_notify_work *w =
1217 container_of(_work, struct netdev_notify_work, work.work); 1210 container_of(_work, struct netdev_notify_work, work.work);
1218 1211
1219 bond_netdev_notify(w->slave, w->dev); 1212 bond_netdev_notify(w->dev, &w->bonding_info);
1220 dev_put(w->dev); 1213 dev_put(w->dev);
1214 kfree(w);
1221} 1215}
1222 1216
1223void bond_queue_slave_event(struct slave *slave) 1217void bond_queue_slave_event(struct slave *slave)
1224{ 1218{
1219 struct bonding *bond = slave->bond;
1225 struct netdev_notify_work *nnw = kzalloc(sizeof(*nnw), GFP_ATOMIC); 1220 struct netdev_notify_work *nnw = kzalloc(sizeof(*nnw), GFP_ATOMIC);
1226 1221
1227 if (!nnw) 1222 if (!nnw)
1228 return; 1223 return;
1229 1224
1230 INIT_DELAYED_WORK(&nnw->work, bond_netdev_notify_work); 1225 dev_hold(slave->dev);
1231 nnw->slave = slave;
1232 nnw->dev = slave->dev; 1226 nnw->dev = slave->dev;
1227 bond_fill_ifslave(slave, &nnw->bonding_info.slave);
1228 bond_fill_ifbond(bond, &nnw->bonding_info.master);
1229 INIT_DELAYED_WORK(&nnw->work, bond_netdev_notify_work);
1233 1230
1234 if (queue_delayed_work(slave->bond->wq, &nnw->work, 0)) 1231 queue_delayed_work(slave->bond->wq, &nnw->work, 0);
1235 dev_hold(slave->dev);
1236 else
1237 kfree(nnw);
1238} 1232}
1239 1233
1240/* enslave device <slave> to bond device <master> */ 1234/* enslave device <slave> to bond device <master> */