Skip to content

Commit

Permalink
IPoIB: Fix use-after-free of multicast object
Browse files Browse the repository at this point in the history
Fix a crash in ipoib_mcast_join_task().  (with help from Or Gerlitz)

Commit c8c2afe ("IPoIB: Use rtnl lock/unlock when changing device
flags") added a call to rtnl_lock() in ipoib_mcast_join_task(), which
is run from the ipoib_workqueue, and hence the workqueue can't be
flushed from the context of ipoib_stop().

In the current code, ipoib_stop() (which doesn't flush the workqueue)
calls ipoib_mcast_dev_flush(), which goes and deletes all the
multicast entries.  This takes place without any synchronization with
a possible running instance of ipoib_mcast_join_task() for the same
ipoib device, leading to a crash due to NULL pointer dereference.

Fix this by making sure that the workqueue is flushed before
ipoib_mcast_dev_flush() is called.  To make that possible, we move the
RTNL-lock wrapped code to ipoib_mcast_join_finish().

Signed-off-by: Patrick McHardy <kaber@trash.net>
Cc: <stable@vger.kernel.org>
Signed-off-by: Roland Dreier <roland@purestorage.com>
  • Loading branch information
Patrick McHardy authored and Roland Dreier committed Oct 1, 2012
1 parent 979570e commit bea1e22
Show file tree
Hide file tree
Showing 2 changed files with 11 additions and 10 deletions.
2 changes: 1 addition & 1 deletion drivers/infiniband/ulp/ipoib/ipoib_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ static int ipoib_stop(struct net_device *dev)

netif_stop_queue(dev);

ipoib_ib_dev_down(dev, 0);
ipoib_ib_dev_down(dev, 1);
ipoib_ib_dev_stop(dev, 0);

if (!test_bit(IPOIB_FLAG_SUBINTERFACE, &priv->flags)) {
Expand Down
19 changes: 10 additions & 9 deletions drivers/infiniband/ulp/ipoib/ipoib_multicast.c
Original file line number Diff line number Diff line change
Expand Up @@ -175,18 +175,27 @@ static int ipoib_mcast_join_finish(struct ipoib_mcast *mcast,

mcast->mcmember = *mcmember;

/* Set the cached Q_Key before we attach if it's the broadcast group */
/* Set the multicast MTU and cached Q_Key before we attach if it's
* the broadcast group.
*/
if (!memcmp(mcast->mcmember.mgid.raw, priv->dev->broadcast + 4,
sizeof (union ib_gid))) {
spin_lock_irq(&priv->lock);
if (!priv->broadcast) {
spin_unlock_irq(&priv->lock);
return -EAGAIN;
}
priv->mcast_mtu = IPOIB_UD_MTU(ib_mtu_enum_to_int(priv->broadcast->mcmember.mtu));
priv->qkey = be32_to_cpu(priv->broadcast->mcmember.qkey);
spin_unlock_irq(&priv->lock);
priv->tx_wr.wr.ud.remote_qkey = priv->qkey;
set_qkey = 1;

if (!ipoib_cm_admin_enabled(dev)) {
rtnl_lock();
dev_set_mtu(dev, min(priv->mcast_mtu, priv->admin_mtu));
rtnl_unlock();
}
}

if (!test_bit(IPOIB_MCAST_FLAG_SENDONLY, &mcast->flags)) {
Expand Down Expand Up @@ -574,14 +583,6 @@ void ipoib_mcast_join_task(struct work_struct *work)
return;
}

priv->mcast_mtu = IPOIB_UD_MTU(ib_mtu_enum_to_int(priv->broadcast->mcmember.mtu));

if (!ipoib_cm_admin_enabled(dev)) {
rtnl_lock();
dev_set_mtu(dev, min(priv->mcast_mtu, priv->admin_mtu));
rtnl_unlock();
}

ipoib_dbg_mcast(priv, "successfully joined all multicast groups\n");

clear_bit(IPOIB_MCAST_RUN, &priv->flags);
Expand Down

0 comments on commit bea1e22

Please sign in to comment.