Skip to content
This repository has been archived by the owner on Jul 13, 2022. It is now read-only.

Commit

Permalink
IPoIB: Fix use-after-free of multicast object
Browse files Browse the repository at this point in the history
commit bea1e22df494a729978e7f2c54f7bda328f74bc3 upstream.

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>
Signed-off-by: Roland Dreier <roland@purestorage.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
kaber authored and gregkh committed Oct 7, 2012
1 parent d125a7e commit 0a44207
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 @@ -148,7 +148,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 @@ -189,18 +189,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 @@ -586,14 +595,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 0a44207

Please sign in to comment.